mallocx.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. /*
  2. * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  3. * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
  4. * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
  5. * Copyright (c) 2000 by Hewlett-Packard Company. All rights reserved.
  6. *
  7. * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  8. * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
  9. *
  10. * Permission is hereby granted to use or copy this program
  11. * for any purpose, provided the above notices are retained on all copies.
  12. * Permission to modify the code and to distribute modified code is granted,
  13. * provided the above notices are retained, and a notice that the code was
  14. * modified is included with the above copyright notice.
  15. */
  16. #include "private/gc_priv.h"
  17. #include "gc_inline.h" /* for GC_malloc_kind */
  18. /*
  19. * These are extra allocation routines which are likely to be less
  20. * frequently used than those in malloc.c. They are separate in the
  21. * hope that the .o file will be excluded from statically linked
  22. * executables. We should probably break this up further.
  23. */
  24. #include <stdio.h>
  25. #include <string.h>
  26. #ifdef MSWINCE
  27. # ifndef WIN32_LEAN_AND_MEAN
  28. # define WIN32_LEAN_AND_MEAN 1
  29. # endif
  30. # define NOSERVICE
  31. # include <windows.h>
  32. #else
  33. # include <errno.h>
  34. #endif
  35. /* Some externally visible but unadvertised variables to allow access to */
  36. /* free lists from inlined allocators without including gc_priv.h */
  37. /* or introducing dependencies on internal data structure layouts. */
  38. #include "gc_alloc_ptrs.h"
  39. void ** const GC_objfreelist_ptr = GC_objfreelist;
  40. void ** const GC_aobjfreelist_ptr = GC_aobjfreelist;
  41. void ** const GC_uobjfreelist_ptr = GC_uobjfreelist;
  42. # ifdef GC_ATOMIC_UNCOLLECTABLE
  43. void ** const GC_auobjfreelist_ptr = GC_auobjfreelist;
  44. # endif
  45. GC_API int GC_CALL GC_get_kind_and_size(const void * p, size_t * psize)
  46. {
  47. hdr * hhdr = HDR(p);
  48. if (psize != NULL) {
  49. *psize = (size_t)hhdr->hb_sz;
  50. }
  51. return hhdr -> hb_obj_kind;
  52. }
  53. GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_or_special_malloc(size_t lb,
  54. int knd)
  55. {
  56. switch(knd) {
  57. case PTRFREE:
  58. case NORMAL:
  59. return GC_malloc_kind(lb, knd);
  60. case UNCOLLECTABLE:
  61. # ifdef GC_ATOMIC_UNCOLLECTABLE
  62. case AUNCOLLECTABLE:
  63. # endif
  64. return GC_generic_malloc_uncollectable(lb, knd);
  65. default:
  66. return GC_generic_malloc(lb, knd);
  67. }
  68. }
  69. /* Change the size of the block pointed to by p to contain at least */
  70. /* lb bytes. The object may be (and quite likely will be) moved. */
  71. /* The kind (e.g. atomic) is the same as that of the old. */
  72. /* Shrinking of large blocks is not implemented well. */
  73. GC_API void * GC_CALL GC_realloc(void * p, size_t lb)
  74. {
  75. struct hblk * h;
  76. hdr * hhdr;
  77. void * result;
  78. size_t sz; /* Current size in bytes */
  79. size_t orig_sz; /* Original sz in bytes */
  80. int obj_kind;
  81. if (p == 0) return(GC_malloc(lb)); /* Required by ANSI */
  82. if (0 == lb) /* and p != NULL */ {
  83. # ifndef IGNORE_FREE
  84. GC_free(p);
  85. # endif
  86. return NULL;
  87. }
  88. h = HBLKPTR(p);
  89. hhdr = HDR(h);
  90. sz = (size_t)hhdr->hb_sz;
  91. obj_kind = hhdr -> hb_obj_kind;
  92. orig_sz = sz;
  93. if (sz > MAXOBJBYTES) {
  94. /* Round it up to the next whole heap block */
  95. word descr = GC_obj_kinds[obj_kind].ok_descriptor;
  96. sz = (sz + HBLKSIZE-1) & ~HBLKMASK;
  97. if (GC_obj_kinds[obj_kind].ok_relocate_descr)
  98. descr += sz;
  99. /* GC_realloc might be changing the block size while */
  100. /* GC_reclaim_block or GC_clear_hdr_marks is examining it. */
  101. /* The change to the size field is benign, in that GC_reclaim */
  102. /* (and GC_clear_hdr_marks) would work correctly with either */
  103. /* value, since we are not changing the number of objects in */
  104. /* the block. But seeing a half-updated value (though unlikely */
  105. /* to occur in practice) could be probably bad. */
  106. /* Using unordered atomic accesses on the size and hb_descr */
  107. /* fields would solve the issue. (The alternate solution might */
  108. /* be to initially overallocate large objects, so we do not */
  109. /* have to adjust the size in GC_realloc, if they still fit. */
  110. /* But that is probably more expensive, since we may end up */
  111. /* scanning a bunch of zeros during GC.) */
  112. # ifdef AO_HAVE_store
  113. GC_STATIC_ASSERT(sizeof(hhdr->hb_sz) == sizeof(AO_t));
  114. AO_store((volatile AO_t *)&hhdr->hb_sz, (AO_t)sz);
  115. AO_store((volatile AO_t *)&hhdr->hb_descr, (AO_t)descr);
  116. # else
  117. {
  118. DCL_LOCK_STATE;
  119. LOCK();
  120. hhdr -> hb_sz = sz;
  121. hhdr -> hb_descr = descr;
  122. UNLOCK();
  123. }
  124. # endif
  125. # ifdef MARK_BIT_PER_OBJ
  126. GC_ASSERT(hhdr -> hb_inv_sz == LARGE_INV_SZ);
  127. # endif
  128. # ifdef MARK_BIT_PER_GRANULE
  129. GC_ASSERT((hhdr -> hb_flags & LARGE_BLOCK) != 0
  130. && hhdr -> hb_map[ANY_INDEX] == 1);
  131. # endif
  132. if (IS_UNCOLLECTABLE(obj_kind)) GC_non_gc_bytes += (sz - orig_sz);
  133. /* Extra area is already cleared by GC_alloc_large_and_clear. */
  134. }
  135. if (ADD_SLOP(lb) <= sz) {
  136. if (lb >= (sz >> 1)) {
  137. if (orig_sz > lb) {
  138. /* Clear unneeded part of object to avoid bogus pointer */
  139. /* tracing. */
  140. BZERO(((ptr_t)p) + lb, orig_sz - lb);
  141. }
  142. return(p);
  143. }
  144. /* shrink */
  145. sz = lb;
  146. }
  147. result = GC_generic_or_special_malloc((word)lb, obj_kind);
  148. if (result != NULL) {
  149. /* In case of shrink, it could also return original object. */
  150. /* But this gives the client warning of imminent disaster. */
  151. BCOPY(p, result, sz);
  152. # ifndef IGNORE_FREE
  153. GC_free(p);
  154. # endif
  155. }
  156. return result;
  157. }
  158. # if defined(REDIRECT_MALLOC) && !defined(REDIRECT_REALLOC)
  159. # define REDIRECT_REALLOC GC_realloc
  160. # endif
  161. # ifdef REDIRECT_REALLOC
  162. /* As with malloc, avoid two levels of extra calls here. */
  163. # define GC_debug_realloc_replacement(p, lb) \
  164. GC_debug_realloc(p, lb, GC_DBG_EXTRAS)
  165. # if !defined(REDIRECT_MALLOC_IN_HEADER)
  166. void * realloc(void * p, size_t lb)
  167. {
  168. return(REDIRECT_REALLOC(p, lb));
  169. }
  170. # endif
  171. # undef GC_debug_realloc_replacement
  172. # endif /* REDIRECT_REALLOC */
  173. /* Allocate memory such that only pointers to near the */
  174. /* beginning of the object are considered. */
  175. /* We avoid holding allocation lock while we clear the memory. */
  176. GC_API GC_ATTR_MALLOC void * GC_CALL
  177. GC_generic_malloc_ignore_off_page(size_t lb, int k)
  178. {
  179. void *result;
  180. size_t lg;
  181. size_t lb_rounded;
  182. word n_blocks;
  183. GC_bool init;
  184. DCL_LOCK_STATE;
  185. if (SMALL_OBJ(lb))
  186. return GC_generic_malloc(lb, k);
  187. GC_ASSERT(k < MAXOBJKINDS);
  188. lg = ROUNDED_UP_GRANULES(lb);
  189. lb_rounded = GRANULES_TO_BYTES(lg);
  190. n_blocks = OBJ_SZ_TO_BLOCKS(lb_rounded);
  191. init = GC_obj_kinds[k].ok_init;
  192. if (EXPECT(GC_have_errors, FALSE))
  193. GC_print_all_errors();
  194. GC_INVOKE_FINALIZERS();
  195. GC_DBG_COLLECT_AT_MALLOC(lb);
  196. LOCK();
  197. result = (ptr_t)GC_alloc_large(ADD_SLOP(lb), k, IGNORE_OFF_PAGE);
  198. if (NULL == result) {
  199. GC_oom_func oom_fn = GC_oom_fn;
  200. UNLOCK();
  201. return (*oom_fn)(lb);
  202. }
  203. if (GC_debugging_started) {
  204. BZERO(result, n_blocks * HBLKSIZE);
  205. } else {
  206. # ifdef THREADS
  207. /* Clear any memory that might be used for GC descriptors */
  208. /* before we release the lock. */
  209. ((word *)result)[0] = 0;
  210. ((word *)result)[1] = 0;
  211. ((word *)result)[GRANULES_TO_WORDS(lg)-1] = 0;
  212. ((word *)result)[GRANULES_TO_WORDS(lg)-2] = 0;
  213. # endif
  214. }
  215. GC_bytes_allocd += lb_rounded;
  216. UNLOCK();
  217. if (init && !GC_debugging_started) {
  218. BZERO(result, n_blocks * HBLKSIZE);
  219. }
  220. return(result);
  221. }
  222. GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_ignore_off_page(size_t lb)
  223. {
  224. return GC_generic_malloc_ignore_off_page(lb, NORMAL);
  225. }
  226. GC_API GC_ATTR_MALLOC void * GC_CALL
  227. GC_malloc_atomic_ignore_off_page(size_t lb)
  228. {
  229. return GC_generic_malloc_ignore_off_page(lb, PTRFREE);
  230. }
  231. /* Increment GC_bytes_allocd from code that doesn't have direct access */
  232. /* to GC_arrays. */
  233. GC_API void GC_CALL GC_incr_bytes_allocd(size_t n)
  234. {
  235. GC_bytes_allocd += n;
  236. }
  237. /* The same for GC_bytes_freed. */
  238. GC_API void GC_CALL GC_incr_bytes_freed(size_t n)
  239. {
  240. GC_bytes_freed += n;
  241. }
  242. GC_API size_t GC_CALL GC_get_expl_freed_bytes_since_gc(void)
  243. {
  244. return (size_t)GC_bytes_freed;
  245. }
  246. # ifdef PARALLEL_MARK
  247. STATIC volatile AO_t GC_bytes_allocd_tmp = 0;
  248. /* Number of bytes of memory allocated since */
  249. /* we released the GC lock. Instead of */
  250. /* reacquiring the GC lock just to add this in, */
  251. /* we add it in the next time we reacquire */
  252. /* the lock. (Atomically adding it doesn't */
  253. /* work, since we would have to atomically */
  254. /* update it in GC_malloc, which is too */
  255. /* expensive.) */
  256. # endif /* PARALLEL_MARK */
  257. /* Return a list of 1 or more objects of the indicated size, linked */
  258. /* through the first word in the object. This has the advantage that */
  259. /* it acquires the allocation lock only once, and may greatly reduce */
  260. /* time wasted contending for the allocation lock. Typical usage would */
  261. /* be in a thread that requires many items of the same size. It would */
  262. /* keep its own free list in thread-local storage, and call */
  263. /* GC_malloc_many or friends to replenish it. (We do not round up */
  264. /* object sizes, since a call indicates the intention to consume many */
  265. /* objects of exactly this size.) */
  266. /* We assume that the size is a multiple of GRANULE_BYTES. */
  267. /* We return the free-list by assigning it to *result, since it is */
  268. /* not safe to return, e.g. a linked list of pointer-free objects, */
  269. /* since the collector would not retain the entire list if it were */
  270. /* invoked just as we were returning. */
  271. /* Note that the client should usually clear the link field. */
  272. GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result)
  273. {
  274. void *op;
  275. void *p;
  276. void **opp;
  277. size_t lw; /* Length in words. */
  278. size_t lg; /* Length in granules. */
  279. signed_word my_bytes_allocd = 0;
  280. struct obj_kind * ok = &(GC_obj_kinds[k]);
  281. struct hblk ** rlh;
  282. DCL_LOCK_STATE;
  283. GC_ASSERT(lb != 0 && (lb & (GRANULE_BYTES-1)) == 0);
  284. if (!SMALL_OBJ(lb)) {
  285. op = GC_generic_malloc(lb, k);
  286. if (EXPECT(0 != op, TRUE))
  287. obj_link(op) = 0;
  288. *result = op;
  289. return;
  290. }
  291. GC_ASSERT(k < MAXOBJKINDS);
  292. lw = BYTES_TO_WORDS(lb);
  293. lg = BYTES_TO_GRANULES(lb);
  294. if (EXPECT(GC_have_errors, FALSE))
  295. GC_print_all_errors();
  296. GC_INVOKE_FINALIZERS();
  297. GC_DBG_COLLECT_AT_MALLOC(lb);
  298. if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
  299. LOCK();
  300. /* Do our share of marking work */
  301. if (GC_incremental && !GC_dont_gc) {
  302. ENTER_GC();
  303. GC_collect_a_little_inner(1);
  304. EXIT_GC();
  305. }
  306. /* First see if we can reclaim a page of objects waiting to be */
  307. /* reclaimed. */
  308. rlh = ok -> ok_reclaim_list;
  309. if (rlh != NULL) {
  310. struct hblk * hbp;
  311. hdr * hhdr;
  312. rlh += lg;
  313. while ((hbp = *rlh) != 0) {
  314. hhdr = HDR(hbp);
  315. *rlh = hhdr -> hb_next;
  316. GC_ASSERT(hhdr -> hb_sz == lb);
  317. hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
  318. # ifdef PARALLEL_MARK
  319. if (GC_parallel) {
  320. signed_word my_bytes_allocd_tmp =
  321. (signed_word)AO_load(&GC_bytes_allocd_tmp);
  322. GC_ASSERT(my_bytes_allocd_tmp >= 0);
  323. /* We only decrement it while holding the GC lock. */
  324. /* Thus we can't accidentally adjust it down in more */
  325. /* than one thread simultaneously. */
  326. if (my_bytes_allocd_tmp != 0) {
  327. (void)AO_fetch_and_add(&GC_bytes_allocd_tmp,
  328. (AO_t)(-my_bytes_allocd_tmp));
  329. GC_bytes_allocd += my_bytes_allocd_tmp;
  330. }
  331. GC_acquire_mark_lock();
  332. ++ GC_fl_builder_count;
  333. UNLOCK();
  334. GC_release_mark_lock();
  335. }
  336. # endif
  337. op = GC_reclaim_generic(hbp, hhdr, lb,
  338. ok -> ok_init, 0, &my_bytes_allocd);
  339. if (op != 0) {
  340. # ifdef PARALLEL_MARK
  341. if (GC_parallel) {
  342. *result = op;
  343. (void)AO_fetch_and_add(&GC_bytes_allocd_tmp,
  344. (AO_t)my_bytes_allocd);
  345. GC_acquire_mark_lock();
  346. -- GC_fl_builder_count;
  347. if (GC_fl_builder_count == 0) GC_notify_all_builder();
  348. # ifdef THREAD_SANITIZER
  349. GC_release_mark_lock();
  350. LOCK();
  351. GC_bytes_found += my_bytes_allocd;
  352. UNLOCK();
  353. # else
  354. GC_bytes_found += my_bytes_allocd;
  355. /* The result may be inaccurate. */
  356. GC_release_mark_lock();
  357. # endif
  358. (void) GC_clear_stack(0);
  359. return;
  360. }
  361. # endif
  362. /* We also reclaimed memory, so we need to adjust */
  363. /* that count. */
  364. GC_bytes_found += my_bytes_allocd;
  365. GC_bytes_allocd += my_bytes_allocd;
  366. goto out;
  367. }
  368. # ifdef PARALLEL_MARK
  369. if (GC_parallel) {
  370. GC_acquire_mark_lock();
  371. -- GC_fl_builder_count;
  372. if (GC_fl_builder_count == 0) GC_notify_all_builder();
  373. GC_release_mark_lock();
  374. LOCK();
  375. /* GC lock is needed for reclaim list access. We */
  376. /* must decrement fl_builder_count before reacquiring */
  377. /* the lock. Hopefully this path is rare. */
  378. }
  379. # endif
  380. }
  381. }
  382. /* Next try to use prefix of global free list if there is one. */
  383. /* We don't refill it, but we need to use it up before allocating */
  384. /* a new block ourselves. */
  385. opp = &(GC_obj_kinds[k].ok_freelist[lg]);
  386. if ( (op = *opp) != 0 ) {
  387. *opp = 0;
  388. my_bytes_allocd = 0;
  389. for (p = op; p != 0; p = obj_link(p)) {
  390. my_bytes_allocd += lb;
  391. if ((word)my_bytes_allocd >= HBLKSIZE) {
  392. *opp = obj_link(p);
  393. obj_link(p) = 0;
  394. break;
  395. }
  396. }
  397. GC_bytes_allocd += my_bytes_allocd;
  398. goto out;
  399. }
  400. /* Next try to allocate a new block worth of objects of this size. */
  401. {
  402. struct hblk *h = GC_allochblk(lb, k, 0);
  403. if (h != 0) {
  404. if (IS_UNCOLLECTABLE(k)) GC_set_hdr_marks(HDR(h));
  405. GC_bytes_allocd += HBLKSIZE - HBLKSIZE % lb;
  406. # ifdef PARALLEL_MARK
  407. if (GC_parallel) {
  408. GC_acquire_mark_lock();
  409. ++ GC_fl_builder_count;
  410. UNLOCK();
  411. GC_release_mark_lock();
  412. op = GC_build_fl(h, lw,
  413. (ok -> ok_init || GC_debugging_started), 0);
  414. *result = op;
  415. GC_acquire_mark_lock();
  416. -- GC_fl_builder_count;
  417. if (GC_fl_builder_count == 0) GC_notify_all_builder();
  418. GC_release_mark_lock();
  419. (void) GC_clear_stack(0);
  420. return;
  421. }
  422. # endif
  423. op = GC_build_fl(h, lw, (ok -> ok_init || GC_debugging_started), 0);
  424. goto out;
  425. }
  426. }
  427. /* As a last attempt, try allocating a single object. Note that */
  428. /* this may trigger a collection or expand the heap. */
  429. op = GC_generic_malloc_inner(lb, k);
  430. if (0 != op) obj_link(op) = 0;
  431. out:
  432. *result = op;
  433. UNLOCK();
  434. (void) GC_clear_stack(0);
  435. }
  436. /* Note that the "atomic" version of this would be unsafe, since the */
  437. /* links would not be seen by the collector. */
  438. GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_many(size_t lb)
  439. {
  440. void *result;
  441. /* Add EXTRA_BYTES and round up to a multiple of a granule. */
  442. lb = SIZET_SAT_ADD(lb, EXTRA_BYTES + GRANULE_BYTES - 1)
  443. & ~(GRANULE_BYTES - 1);
  444. GC_generic_malloc_many(lb, NORMAL, &result);
  445. return result;
  446. }
  447. #include <limits.h>
  448. /* Debug version is tricky and currently missing. */
  449. GC_API GC_ATTR_MALLOC void * GC_CALL GC_memalign(size_t align, size_t lb)
  450. {
  451. size_t new_lb;
  452. size_t offset;
  453. ptr_t result;
  454. if (align <= GRANULE_BYTES) return GC_malloc(lb);
  455. if (align >= HBLKSIZE/2 || lb >= HBLKSIZE/2) {
  456. if (align > HBLKSIZE) {
  457. return (*GC_get_oom_fn())(LONG_MAX-1024); /* Fail */
  458. }
  459. return GC_malloc(lb <= HBLKSIZE? HBLKSIZE : lb);
  460. /* Will be HBLKSIZE aligned. */
  461. }
  462. /* We could also try to make sure that the real rounded-up object size */
  463. /* is a multiple of align. That would be correct up to HBLKSIZE. */
  464. new_lb = SIZET_SAT_ADD(lb, align - 1);
  465. result = (ptr_t)GC_malloc(new_lb);
  466. /* It is OK not to check result for NULL as in that case */
  467. /* GC_memalign returns NULL too since (0 + 0 % align) is 0. */
  468. offset = (word)result % align;
  469. if (offset != 0) {
  470. offset = align - offset;
  471. if (!GC_all_interior_pointers) {
  472. GC_STATIC_ASSERT(VALID_OFFSET_SZ <= HBLKSIZE);
  473. GC_ASSERT(offset < VALID_OFFSET_SZ);
  474. GC_register_displacement(offset);
  475. }
  476. }
  477. result += offset;
  478. GC_ASSERT((word)result % align == 0);
  479. return result;
  480. }
  481. /* This one exists largely to redirect posix_memalign for leaks finding. */
  482. GC_API int GC_CALL GC_posix_memalign(void **memptr, size_t align, size_t lb)
  483. {
  484. /* Check alignment properly. */
  485. size_t align_minus_one = align - 1; /* to workaround a cppcheck warning */
  486. if (align < sizeof(void *) || (align_minus_one & align) != 0) {
  487. # ifdef MSWINCE
  488. return ERROR_INVALID_PARAMETER;
  489. # else
  490. return EINVAL;
  491. # endif
  492. }
  493. if ((*memptr = GC_memalign(align, lb)) == NULL) {
  494. # ifdef MSWINCE
  495. return ERROR_NOT_ENOUGH_MEMORY;
  496. # else
  497. return ENOMEM;
  498. # endif
  499. }
  500. return 0;
  501. }
  502. /* provide a version of strdup() that uses the collector to allocate the
  503. copy of the string */
  504. GC_API GC_ATTR_MALLOC char * GC_CALL GC_strdup(const char *s)
  505. {
  506. char *copy;
  507. size_t lb;
  508. if (s == NULL) return NULL;
  509. lb = strlen(s) + 1;
  510. copy = (char *)GC_malloc_atomic(lb);
  511. if (NULL == copy) {
  512. # ifndef MSWINCE
  513. errno = ENOMEM;
  514. # endif
  515. return NULL;
  516. }
  517. BCOPY(s, copy, lb);
  518. return copy;
  519. }
  520. GC_API GC_ATTR_MALLOC char * GC_CALL GC_strndup(const char *str, size_t size)
  521. {
  522. char *copy;
  523. size_t len = strlen(str); /* str is expected to be non-NULL */
  524. if (len > size)
  525. len = size;
  526. copy = (char *)GC_malloc_atomic(len + 1);
  527. if (copy == NULL) {
  528. # ifndef MSWINCE
  529. errno = ENOMEM;
  530. # endif
  531. return NULL;
  532. }
  533. if (EXPECT(len > 0, TRUE))
  534. BCOPY(str, copy, len);
  535. copy[len] = '\0';
  536. return copy;
  537. }
  538. #ifdef GC_REQUIRE_WCSDUP
  539. # include <wchar.h> /* for wcslen() */
  540. GC_API GC_ATTR_MALLOC wchar_t * GC_CALL GC_wcsdup(const wchar_t *str)
  541. {
  542. size_t lb = (wcslen(str) + 1) * sizeof(wchar_t);
  543. wchar_t *copy = (wchar_t *)GC_malloc_atomic(lb);
  544. if (copy == NULL) {
  545. # ifndef MSWINCE
  546. errno = ENOMEM;
  547. # endif
  548. return NULL;
  549. }
  550. BCOPY(str, copy, lb);
  551. return copy;
  552. }
  553. #endif /* GC_REQUIRE_WCSDUP */
  554. GC_API void * GC_CALL GC_malloc_stubborn(size_t lb)
  555. {
  556. return GC_malloc(lb);
  557. }
  558. GC_API void GC_CALL GC_change_stubborn(const void *p GC_ATTR_UNUSED)
  559. {
  560. /* Empty. */
  561. }
  562. GC_API void GC_CALL GC_end_stubborn_change(const void *p)
  563. {
  564. GC_dirty(p); /* entire object */
  565. }