stk.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /* SPDX-License-Identifier: MPL-1.1 OR GPL-2.0-or-later */
  2. /*
  3. * The contents of this file are subject to the Mozilla Public
  4. * License Version 1.1 (the "License"); you may not use this file
  5. * except in compliance with the License. You may obtain a copy of
  6. * the License at http://www.mozilla.org/MPL/
  7. *
  8. * Software distributed under the License is distributed on an "AS
  9. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10. * implied. See the License for the specific language governing
  11. * rights and limitations under the License.
  12. *
  13. * The Original Code is the Netscape Portable Runtime library.
  14. *
  15. * The Initial Developer of the Original Code is Netscape
  16. * Communications Corporation. Portions created by Netscape are
  17. * Copyright (C) 1994-2000 Netscape Communications Corporation. All
  18. * Rights Reserved.
  19. *
  20. * Contributor(s): Silicon Graphics, Inc.
  21. *
  22. * Portions created by SGI are Copyright (C) 2000-2001 Silicon
  23. * Graphics, Inc. All Rights Reserved.
  24. *
  25. * Alternatively, the contents of this file may be used under the
  26. * terms of the GNU General Public License Version 2 or later (the
  27. * "GPL"), in which case the provisions of the GPL are applicable
  28. * instead of those above. If you wish to allow use of your
  29. * version of this file only under the terms of the GPL and not to
  30. * allow others to use your version of this file under the MPL,
  31. * indicate your decision by deleting the provisions above and
  32. * replace them with the notice and other provisions required by
  33. * the GPL. If you do not delete the provisions above, a recipient
  34. * may use your version of this file under either the MPL or the
  35. * GPL.
  36. */
  37. /*
  38. * This file is derived directly from Netscape Communications Corporation,
  39. * and consists of extensive modifications made during the year(s) 1999-2000.
  40. */
  41. #include <stdlib.h>
  42. #include <sys/types.h>
  43. #include <sys/stat.h>
  44. #include <fcntl.h>
  45. #include <sys/mman.h>
  46. #include "common.h"
  47. /* How much space to leave between the stacks, at each end */
  48. #define REDZONE _ST_PAGE_SIZE
  49. __thread _st_clist_t _st_free_stacks;
  50. __thread int _st_num_free_stacks = 0;
  51. __thread int _st_randomize_stacks = 0;
  52. static char *_st_new_stk_segment(int size);
  53. _st_stack_t *_st_stack_new(int stack_size)
  54. {
  55. _st_clist_t *qp;
  56. _st_stack_t *ts;
  57. int extra;
  58. for (qp = _st_free_stacks.next; qp != &_st_free_stacks; qp = qp->next) {
  59. ts = _ST_THREAD_STACK_PTR(qp);
  60. if (ts->stk_size >= stack_size) {
  61. /* Found a stack that is big enough */
  62. ST_REMOVE_LINK(&ts->links);
  63. _st_num_free_stacks--;
  64. ts->links.next = NULL;
  65. ts->links.prev = NULL;
  66. return ts;
  67. }
  68. }
  69. /* Make a new thread stack object. */
  70. if ((ts = (_st_stack_t *)calloc(1, sizeof(_st_stack_t))) == NULL)
  71. return NULL;
  72. extra = _st_randomize_stacks ? _ST_PAGE_SIZE : 0;
  73. ts->vaddr_size = stack_size + 2*REDZONE + extra;
  74. ts->vaddr = _st_new_stk_segment(ts->vaddr_size);
  75. if (!ts->vaddr) {
  76. free(ts);
  77. return NULL;
  78. }
  79. ts->stk_size = stack_size;
  80. ts->stk_bottom = ts->vaddr + REDZONE;
  81. ts->stk_top = ts->stk_bottom + stack_size;
  82. /* For example, in OpenWRT, the memory at the begin minus 16B by mprotect is read-only. */
  83. #if defined(DEBUG) && !defined(MD_NO_PROTECT)
  84. mprotect(ts->vaddr, REDZONE, PROT_NONE);
  85. mprotect(ts->stk_top + extra, REDZONE, PROT_NONE);
  86. #endif
  87. if (extra) {
  88. long offset = (random() % extra) & ~0xf;
  89. ts->stk_bottom += offset;
  90. ts->stk_top += offset;
  91. }
  92. return ts;
  93. }
  94. /*
  95. * Free the stack for the current thread
  96. */
  97. void _st_stack_free(_st_stack_t *ts)
  98. {
  99. if (!ts)
  100. return;
  101. /* Put the stack on the free list */
  102. ST_APPEND_LINK(&ts->links, _st_free_stacks.prev);
  103. _st_num_free_stacks++;
  104. }
  105. static char *_st_new_stk_segment(int size)
  106. {
  107. #ifdef MALLOC_STACK
  108. void *vaddr = malloc(size);
  109. #else
  110. static int zero_fd = -1;
  111. int mmap_flags = MAP_PRIVATE;
  112. void *vaddr;
  113. #if defined (MD_USE_SYSV_ANON_MMAP)
  114. if (zero_fd < 0) {
  115. if ((zero_fd = open("/dev/zero", O_RDWR, 0)) < 0)
  116. return NULL;
  117. fcntl(zero_fd, F_SETFD, FD_CLOEXEC);
  118. }
  119. #elif defined (MD_USE_BSD_ANON_MMAP)
  120. mmap_flags |= MAP_ANON;
  121. #else
  122. #error Unknown OS
  123. #endif
  124. vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, zero_fd, 0);
  125. if (vaddr == (void *)MAP_FAILED)
  126. return NULL;
  127. #endif /* MALLOC_STACK */
  128. return (char *)vaddr;
  129. }
  130. /* Not used */
  131. #if 0
  132. void _st_delete_stk_segment(char *vaddr, int size)
  133. {
  134. #ifdef MALLOC_STACK
  135. free(vaddr);
  136. #else
  137. (void) munmap(vaddr, size);
  138. #endif
  139. }
  140. #endif
  141. int st_randomize_stacks(int on)
  142. {
  143. int wason = _st_randomize_stacks;
  144. _st_randomize_stacks = on;
  145. if (on)
  146. srandom((unsigned int) st_utime());
  147. return wason;
  148. }