From 88f7eb4d91fcb554df937652d85be8f48b9d5c85 Mon Sep 17 00:00:00 2001 From: Jeronimo Pellegrini Date: Sun, 22 Sep 2024 11:11:22 -0300 Subject: [PATCH 1/2] Upgrade libgc to 8.2.8 --- gc/AUTHORS | 4 + gc/CMakeLists.txt | 4 +- gc/ChangeLog | 106 ++++++++++++++++++++- gc/Makefile.am | 2 +- gc/Makefile.in | 2 +- gc/README.md | 2 +- gc/WCC_MAKEFILE | 20 ++-- gc/allchblk.c | 2 +- gc/alloc.c | 15 +-- gc/backgraph.c | 2 +- gc/configure | 20 ++-- gc/configure.ac | 2 +- gc/cord/tests/cordtest.c | 10 +- gc/dbg_mlc.c | 30 +++--- gc/doc/README.cmake | 2 +- gc/doc/tree.md | 49 +++++----- gc/dyn_load.c | 19 ++-- gc/gcj_mlc.c | 14 +-- gc/headers.c | 10 +- gc/include/gc.h | 8 +- gc/include/gc_mark.h | 2 +- gc/include/gc_version.h | 2 +- gc/include/leak_detector.h | 3 + gc/include/private/dbg_mlc.h | 11 +++ gc/include/private/gc_priv.h | 39 +++++--- gc/include/private/gcconfig.h | 35 ++++--- gc/mallocx.c | 11 ++- gc/mark.c | 9 +- gc/misc.c | 14 +-- gc/os_dep.c | 173 ++++++++++++++++++++++------------ gc/pthread_stop_world.c | 27 +++++- gc/ptr_chck.c | 5 +- gc/reclaim.c | 3 +- gc/specific.c | 6 +- gc/tests/leak_test.c | 1 + gc/tests/test.c | 4 + gc/tools/setjmp_t.c | 3 +- gc/typd_mlc.c | 4 - 38 files changed, 453 insertions(+), 222 deletions(-) diff --git a/gc/AUTHORS b/gc/AUTHORS index 8d1570041..f5dbbaa2b 100644 --- a/gc/AUTHORS +++ b/gc/AUTHORS @@ -120,6 +120,7 @@ Daniel R. Grayson Danny Smith Darrell Schiebel Dave Barrett +Dave Barton Dave Detlefs Dave Korn Dave Love @@ -158,6 +159,7 @@ Emmanual Stumpf Eric Benson Eric Holk Erik M. Bray +Fabian Ruffy Fabian Thylman Fabrice Fontaine Fergus Henderson @@ -363,6 +365,7 @@ Phillip Musumeci Phong Vo Pierre de Rop Pontus Rydin +Qing Guo Radek Polak Rainer Orth Ranjit Mathew @@ -396,6 +399,7 @@ Samuel Thibault Scott Ananian Scott Ferguson Scott Schwartz +Seonghyun Kim Shawn Wagner Shea Levy Shiro Kawai diff --git a/gc/CMakeLists.txt b/gc/CMakeLists.txt index cb57e5a90..faca593e4 100644 --- a/gc/CMakeLists.txt +++ b/gc/CMakeLists.txt @@ -24,14 +24,14 @@ cmake_minimum_required(VERSION 3.5) -set(PACKAGE_VERSION 8.2.6) +set(PACKAGE_VERSION 8.2.8) # Version must match that in AC_INIT of configure.ac and that in README. # Version must conform to: [0-9]+[.][0-9]+[.][0-9]+ # Info (current:revision:age) for the Libtool versioning system. # These values should match those in cord/cord.am and Makefile.am. set(LIBCORD_VER_INFO 6:1:5) -set(LIBGC_VER_INFO 6:3:5) +set(LIBGC_VER_INFO 6:4:5) set(LIBGCCPP_VER_INFO 6:0:5) option(enable_cplusplus "C++ support" OFF) diff --git a/gc/ChangeLog b/gc/ChangeLog index f22f21c20..bc381d0d7 100644 --- a/gc/ChangeLog +++ b/gc/ChangeLog @@ -1,4 +1,39 @@ +== [8.2.8] 2024-09-08 == + +* Allow GC_size() argument to be null +* Disable backtrace saving at garbage collections if DONT_SAVE_TO_LAST_STACK +* Eliminate 'cast signed to bigger unsigned' CSA warnings in GC_find_limit +* Eliminate 'x might be clobbered by longjmp' gcc warning in setjmp_t.c +* Fix 'un-mprotect vdb failed' abort with out-of-memory reason on Linux +* Fix ADD_CALL_CHAIN() placement to follow GC_store_debug_info_inner call +* Fix GC_debug_realloc to support custom kind +* Fix GC_is_visible for case of arg pointing exactly to object upper bound +* Fix GC_print_trace_inner to print the last element of the circular buffer +* Fix cordtst2.tmp file deletion in cordtest on Windows +* Fix double lock in GC_malloc called from backtrace() +* Fix handling of page-unaligned boundaries in soft_set_grungy_pages +* Fix heap blocks size computation by GC_get_memory_use +* Fix indent of a closing curly braces in GC_apply_to_all_blocks +* Fix infinite resend lost signals if a thread is restarted by SIGQUIT +* Fix null pointer dereference in GC_is_visible if type_descr is null +* Fix per_object_helper() after changing hb_sz units +* Fix pointer relational comparison in GC_do_enumerate_reachable_objects +* Fix poor thread-local allocation performance because of double EXTRA_BYTES +* Fix potential GC_add_roots_inner call with an overflowed pointer (Win32) +* Fix potential address overflow in GC_add_to_heap +* Fix potential buffer overrun during read in GC_text_mapping +* Fix various typos in comments +* Prevent GC_noop_sink from scanning by the collector +* Prevent redirected malloc call from a garbage collection routine +* Redirect malloc_usable_size() in leak_detector.h +* Remove redundant dirty/reachable_here calls in GC_malloc_explicitly_typed +* Update and fix diagrams describing the tree structure for pointer lookups +* Use atomic store to set GC_first_nonempty in GC_do_parallel_mark +* Use atomic store to set entry id and update cache_ptr in slow_getspecific +* Workaround '.obj file not found' error reported by watcom wlib + + == [8.2.6] 2024-02-04 == * Avoid unexpected heap growth in gctest for the case of VERY_SMALL_CONFIG @@ -83,7 +118,7 @@ * Adjust WoW64 workaround to work on UWP/WinRT * Adjust naming of Win32/64 and x86/64 words in comments and documentation * Avoid potential race between realloc and GC_block_was_dirty -* Do not double-clear first two words of object in GC_generic_malloc_aligned +* Do not double-clear first two words of object in GC_generic_malloc * Do not mention FASTLOCK in comment * Do not mix debug and non-debug allocations in disclaim tests * Do not prohibit threaded builds with malloc redirection on non-Linux @@ -523,6 +558,14 @@ * Workaround various cppcheck false positives +== [8.0.14] 2024-09-07 == + +* Disable backtrace saving at garbage collections if DONT_SAVE_TO_LAST_STACK +* Fix infinite resend lost signals if a thread is restarted by SIGQUIT + +Also, includes 7.6.22 changes + + == [8.0.12] 2024-02-04 == * Eliminate 'make_key is defined but unused' gcc warning in threadkeytest @@ -1052,6 +1095,17 @@ Also, includes 7.6.18 changes * Workaround Thread Sanitizer (TSan) false positive warnings +== [7.6.22] 2024-09-07 == + +* Eliminate 'cast signed to bigger unsigned' CSA warnings in GC_find_limit +* Fix GC_debug_realloc to support custom kind +* Fix heap blocks size computation by GC_get_memory_use +* Fix pointer relational comparison in GC_do_enumerate_reachable_objects +* Prevent GC_noop_sink from scanning by the collector + +Also, includes 7.4.28 changes + + == [7.6.20] 2024-02-03 == * Eliminate compiler warning of missing cast in LONG_MULT after shift @@ -1632,6 +1686,27 @@ Also, includes 7.4.6 changes Also, includes 7.4.4 changes +== [7.4.28] 2024-09-07 == + +* Avoid gcc stringop-overflow warning for intended overflow in smashtest +* Fix ADD_CALL_CHAIN() placement to follow GC_store_debug_info_inner call +* Fix GC_is_visible for case of arg pointing exactly to object upper bound +* Fix GC_print_trace_inner to print the last element of the circular buffer +* Fix cordtst2.tmp file deletion in cordtest on Windows +* Fix double lock in GC_malloc called from backtrace() +* Fix indent of a closing curly braces in GC_apply_to_all_blocks +* Fix null pointer dereference in GC_is_visible if type_descr is null +* Fix per_object_helper() after changing hb_sz units +* Fix poor thread-local allocation performance because of double EXTRA_BYTES +* Fix potential GC_add_roots_inner call with an overflowed pointer (Win32) +* Fix potential address overflow in GC_add_to_heap +* Fix potential buffer overrun during read in GC_text_mapping +* Fix typos in comments +* Prevent redirected malloc call from a garbage collection routine +* Remove redundant dirty/reachable_here calls in GC_malloc_explicitly_typed +* Update and fix diagrams describing the tree structure for pointer lookups + + == [7.4.26] 2024-02-03 == * Eliminate 'unused parameter' gcc warning in free() if IGNORE_FREE @@ -2206,6 +2281,35 @@ Also, includes 7.2e, 7.2d, 7.2c, 7.2b changes Also, includes 7.2 changes +== [7.2s] 2024-09-06 == + +* Avoid gcc stringop-overflow warning for intended overflow in smashtest +* Eliminate 'type defaults to int in declaration' warning (REDIRECT_MALLOC) +* Eliminate 'value exceeds maximum object size' GCC warning in huge_test +* Eliminate warning and simplify expression in GC_init_explicit_typing +* Fix 'GetVersion deprecated' compiler warning in os_dep (MS VC) +* Fix 'value truncated' compiler warning in CORD_cat (MS VC) +* Fix ADD_CALL_CHAIN() placement to follow GC_store_debug_info_inner call +* Fix GC_is_visible for case of arg pointing exactly to object upper bound +* Fix GC_jmp_buf multiple definition +* Fix GC_print_trace_inner to print the last element of the circular buffer +* Fix double lock in GC_malloc called from backtrace() +* Fix indent of a closing curly braces in GC_apply_to_all_blocks +* Fix null pointer dereference in GC_is_visible if type_descr is null +* Fix per_object_helper() after changing hb_sz units +* Fix poor thread-local allocation performance because of double EXTRA_BYTES +* Fix potential GC_add_roots_inner call with an overflowed pointer (Win32) +* Fix potential address overflow in GC_add_to_heap +* Fix potential buffer overrun during read in GC_text_mapping +* Fix typos in comments +* Prevent compiler warnings regarding unused argument and printf in extra +* Prevent redirected malloc call from a garbage collection routine +* Remove barrett_diagram file duplicated by tree.html +* Remove non-existing DISCARD_WORDS from GC data structure ASCII diagram +* Resolve GCC warning in setjmp_t.c +* Update and fix diagrams describing the tree structure for pointer lookups + + == [7.2r] 2024-02-03 == * Fix 'g++ not found' error on OpenBSD (Makefile.direct) diff --git a/gc/Makefile.am b/gc/Makefile.am index 2da5ce65f..1cf6dc562 100644 --- a/gc/Makefile.am +++ b/gc/Makefile.am @@ -14,7 +14,7 @@ # Info (current:revision:age) for the Libtool versioning system. # These numbers should be updated at most once just before the release, # and, optionally, at most once during the development (after the release). -LIBGC_VER_INFO = 6:3:5 +LIBGC_VER_INFO = 6:4:5 LIBGCCPP_VER_INFO = 6:0:5 ## FIXME: `make distcheck' in this directory will not currently work. diff --git a/gc/Makefile.in b/gc/Makefile.in index 7cdbeb2c0..f5ec85373 100644 --- a/gc/Makefile.in +++ b/gc/Makefile.in @@ -1050,7 +1050,7 @@ top_srcdir = @top_srcdir@ # Info (current:revision:age) for the Libtool versioning system. # These numbers should be updated at most once just before the release, # and, optionally, at most once during the development (after the release). -LIBGC_VER_INFO = 6:3:5 +LIBGC_VER_INFO = 6:4:5 LIBGCCPP_VER_INFO = 6:0:5 # We currently use the source files directly from libatomic_ops, if we diff --git a/gc/README.md b/gc/README.md index 85dfe194c..794582fdd 100644 --- a/gc/README.md +++ b/gc/README.md @@ -1,6 +1,6 @@ # Boehm-Demers-Weiser Garbage Collector -This is version 8.2.6 of a conservative garbage +This is version 8.2.8 of a conservative garbage collector for C and C++. diff --git a/gc/WCC_MAKEFILE b/gc/WCC_MAKEFILE index 49c26280e..1e53da98d 100644 --- a/gc/WCC_MAKEFILE +++ b/gc/WCC_MAKEFILE @@ -95,24 +95,24 @@ OBJS= alloc.obj reclaim.obj allchblk.obj backgraph.obj checksums.obj & gc.lib: $(OBJS) @%create $*.lb1 - @for %i in ($(OBJS)) do @%append $*.lb1 +'%i' + @for %i in ($(OBJS)) do @%append $*.lb1 +%i *wlib -b -c -n -p=512 $@ @$*.lb1 cord.lib: $(COBJS) @%create $*.lb1 - @for %i in ($(COBJS)) do @%append $*.lb1 +'%i' + @for %i in ($(COBJS)) do @%append $*.lb1 +%i *wlib -b -c -n -p=512 $@ @$*.lb1 gccpp.lib: gc_badalc.obj gc_cpp.obj @%create $*.lb1 - @%append $*.lb1 +'gc_badalc.obj' - @%append $*.lb1 +'gc_cpp.obj' + @%append $*.lb1 +gc_badalc.obj + @%append $*.lb1 +gc_cpp.obj *wlib -b -c -n -p=512 $@ @$*.lb1 # The same as gccpp.lib but contains only gc_badalc.obj. gctba.lib: gc_badalc.obj @%create $*.lb1 - @%append $*.lb1 +'gc_badalc.obj' + @%append $*.lb1 +gc_badalc.obj *wlib -b -c -n -p=512 $@ @$*.lb1 !else @@ -134,7 +134,7 @@ gc.dll: gc.obj .AUTODEPEND !endif @%append $*.lnk op case @%append $*.lnk name $* - @%append $*.lnk file 'gc.obj' + @%append $*.lnk file gc.obj *wlink @$*.lnk cord.lib: cord.dll @@ -151,7 +151,7 @@ cord.dll: $(COBJS) gc.lib .AUTODEPEND !endif @%append $*.lnk op case @%append $*.lnk name $* - @for %i in ($(COBJS)) do @%append $*.lnk file '%i' + @for %i in ($(COBJS)) do @%append $*.lnk file %i @%append $*.lnk library gc.lib *wlink @$*.lnk @@ -169,8 +169,8 @@ gccpp.dll: gc_badalc.obj gc_cpp.obj gc.lib .AUTODEPEND !endif @%append $*.lnk op case @%append $*.lnk name $* - @%append $*.lnk file 'gc_badalc.obj' - @%append $*.lnk file 'gc_cpp.obj' + @%append $*.lnk file gc_badalc.obj + @%append $*.lnk file gc_cpp.obj @%append $*.lnk library gc.lib @%append $*.lnk library wr7$(CALLING)dll.lib *wlink @$*.lnk @@ -189,7 +189,7 @@ gctba.dll: gc_badalc.obj gc.lib .AUTODEPEND !endif @%append $*.lnk op case @%append $*.lnk name $* - @%append $*.lnk file 'gc_badalc.obj' + @%append $*.lnk file gc_badalc.obj @%append $*.lnk library gc.lib @%append $*.lnk library wr7$(CALLING)dll.lib *wlink @$*.lnk diff --git a/gc/allchblk.c b/gc/allchblk.c index cc4cfd7f8..6d31968b2 100644 --- a/gc/allchblk.c +++ b/gc/allchblk.c @@ -621,7 +621,7 @@ STATIC struct hblk * GC_get_first_part(struct hblk *h, hdr *hhdr, * appropriate free list. * N replaces h in the original free list. * - * Nhdr is not completely filled in, since it is about to allocated. + * Nhdr is not completely filled in, since it is about to be allocated. * It may in fact end up on the wrong free list for its size. * That's not a disaster, since n is about to be allocated * by our caller. diff --git a/gc/alloc.c b/gc/alloc.c index 95b0e666d..9627c79d2 100644 --- a/gc/alloc.c +++ b/gc/alloc.c @@ -530,9 +530,7 @@ STATIC void GC_maybe_gc(void) /* used instead of GC_never_stop_func here. */ if (GC_stopped_mark(GC_time_limit == GC_TIME_UNLIMITED? GC_never_stop_func : GC_timeout_stop_func)) { -# ifdef SAVE_CALL_CHAIN - GC_save_callers(GC_last_stack); -# endif + SAVE_CALLERS_TO_LAST_STACK(); GC_finish_collection(); } else { if (!GC_is_full_gc) { @@ -621,9 +619,7 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func) } GC_invalidate_mark_state(); /* Flush mark stack. */ GC_clear_marks(); -# ifdef SAVE_CALL_CHAIN - GC_save_callers(GC_last_stack); -# endif + SAVE_CALLERS_TO_LAST_STACK(); GC_is_full_gc = TRUE; if (!GC_stopped_mark(stop_func)) { if (!GC_incremental) { @@ -736,9 +732,7 @@ GC_INNER void GC_collect_a_little_inner(int n) if (i < max_deficit && !GC_dont_gc) { /* Need to finish a collection. */ -# ifdef SAVE_CALL_CHAIN - GC_save_callers(GC_last_stack); -# endif + SAVE_CALLERS_TO_LAST_STACK(); # ifdef PARALLEL_MARK if (GC_parallel) GC_wait_for_reclaim(); @@ -1408,7 +1402,7 @@ STATIC void GC_add_to_heap(struct hblk *p, size_t bytes) if (0 == bytes) return; } endp = (word)p + bytes; - if (endp <= (word)p) { + while (endp <= (word)p) { /* Address wrapped. */ bytes -= HBLKSIZE; if (0 == bytes) return; @@ -1474,6 +1468,7 @@ STATIC void GC_add_to_heap(struct hblk *p, size_t bytes) GC_greatest_real_heap_addr = endp; } # endif + GC_handle_protected_regions_limit(); if (old_capacity > 0) { # ifndef GWW_VDB /* Recycling may call GC_add_to_heap() again but should not */ diff --git a/gc/backgraph.c b/gc/backgraph.c index 8caad4c4b..733edea2b 100644 --- a/gc/backgraph.c +++ b/gc/backgraph.c @@ -294,7 +294,7 @@ static void per_object_helper(struct hblk *h, word fn) do { f((ptr_t)(h -> hb_body + i), sz, descr); i += sz; - } while (i + sz <= BYTES_TO_WORDS(HBLKSIZE)); + } while (i + sz <= HBLKSIZE); } GC_INLINE void GC_apply_to_each_object(per_object_func f) diff --git a/gc/configure b/gc/configure index fc661d55b..2d26d667d 100755 --- a/gc/configure +++ b/gc/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for gc 8.2.6. +# Generated by GNU Autoconf 2.71 for gc 8.2.8. # # Report bugs to . # @@ -621,8 +621,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='gc' PACKAGE_TARNAME='gc' -PACKAGE_VERSION='8.2.6' -PACKAGE_STRING='gc 8.2.6' +PACKAGE_VERSION='8.2.8' +PACKAGE_STRING='gc 8.2.8' PACKAGE_BUGREPORT='https://github.com/ivmai/bdwgc/issues' PACKAGE_URL='' @@ -1469,7 +1469,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures gc 8.2.6 to adapt to many kinds of systems. +\`configure' configures gc 8.2.8 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1541,7 +1541,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of gc 8.2.6:";; + short | recursive ) echo "Configuration of gc 8.2.8:";; esac cat <<\_ACEOF @@ -1714,7 +1714,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -gc configure 8.2.6 +gc configure 8.2.8 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -2099,7 +2099,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by gc $as_me 8.2.6, which was +It was created by gc $as_me 8.2.8, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -3733,7 +3733,7 @@ fi # Define the identity of the package. PACKAGE='gc' - VERSION='8.2.6' + VERSION='8.2.8' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -19880,7 +19880,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by gc $as_me 8.2.6, which was +This file was extended by gc $as_me 8.2.8, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -19948,7 +19948,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -gc config.status 8.2.6 +gc config.status 8.2.8 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff --git a/gc/configure.ac b/gc/configure.ac index 1b5cc4d2b..c8deb0840 100644 --- a/gc/configure.ac +++ b/gc/configure.ac @@ -14,7 +14,7 @@ dnl Process this file with autoconf to produce configure. dnl Initialization. -AC_INIT(gc,8.2.6,https://github.com/ivmai/bdwgc/issues) +AC_INIT(gc,8.2.8,https://github.com/ivmai/bdwgc/issues) dnl Version must conform to: [0-9]+[.][0-9]+[.][0-9]+ AC_CONFIG_SRCDIR(gcj_mlc.c) diff --git a/gc/cord/tests/cordtest.c b/gc/cord/tests/cordtest.c index e81db5c0b..44df3e1b6 100644 --- a/gc/cord/tests/cordtest.c +++ b/gc/cord/tests/cordtest.c @@ -11,7 +11,7 @@ * modified is included with the above copyright notice. */ -# include "gc.h" /* For GC_INIT() only */ +# include "gc.h" # include "cord.h" # include @@ -230,9 +230,6 @@ void test_extras(void) /* But we cannot call fclose as it might lead to double close. */ fprintf(stderr, "WARNING: remove failed: " FNAME1 "\n"); } - if (remove(FNAME2) != 0) { - fprintf(stderr, "WARNING: remove failed: " FNAME2 "\n"); - } } int wrap_vprintf(CORD format, ...) @@ -344,6 +341,11 @@ int main(void) test_basics(); test_extras(); test_printf(); + + GC_gcollect(); /* to close f2 before the file removal */ + if (remove(FNAME2) != 0) { + fprintf(stderr, "WARNING: remove failed: " FNAME2 "\n"); + } CORD_fprintf(stdout, "SUCCEEDED\n"); return(0); } diff --git a/gc/dbg_mlc.c b/gc/dbg_mlc.c index 05e8735ef..2c3c35676 100644 --- a/gc/dbg_mlc.c +++ b/gc/dbg_mlc.c @@ -299,8 +299,8 @@ static void *store_debug_info(void *p, size_t lb, LOCK(); if (!GC_debugging_started) GC_start_debugging_inner(); - ADD_CALL_CHAIN(p, ra); result = GC_store_debug_info_inner(p, (word)lb, s, i); + ADD_CALL_CHAIN(p, ra); UNLOCK(); return result; } @@ -574,11 +574,11 @@ STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS) /* case, we need to make sure that all objects have debug headers. */ GC_INNER void * GC_debug_generic_malloc_inner(size_t lb, int k) { - void * result; + void *base, *result; GC_ASSERT(I_HOLD_LOCK()); - result = GC_generic_malloc_inner(SIZET_SAT_ADD(lb, DEBUG_BYTES), k); - if (NULL == result) { + base = GC_generic_malloc_inner(SIZET_SAT_ADD(lb, DEBUG_BYTES), k); + if (NULL == base) { GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n", (unsigned long) lb); return(0); @@ -586,19 +586,20 @@ STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS) if (!GC_debugging_started) { GC_start_debugging_inner(); } - ADD_CALL_CHAIN(result, GC_RETURN_ADDR); - return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", 0)); + result = GC_store_debug_info_inner(base, (word)lb, "INTERNAL", 0); + ADD_CALL_CHAIN(base, GC_RETURN_ADDR); + return result; } GC_INNER void * GC_debug_generic_malloc_inner_ignore_off_page(size_t lb, int k) { - void * result; + void *base, *result; GC_ASSERT(I_HOLD_LOCK()); - result = GC_generic_malloc_inner_ignore_off_page( + base = GC_generic_malloc_inner_ignore_off_page( SIZET_SAT_ADD(lb, DEBUG_BYTES), k); - if (NULL == result) { + if (NULL == base) { GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n", (unsigned long) lb); return(0); @@ -606,8 +607,9 @@ STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS) if (!GC_debugging_started) { GC_start_debugging_inner(); } - ADD_CALL_CHAIN(result, GC_RETURN_ADDR); - return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", 0)); + result = GC_store_debug_info_inner(base, (word)lb, "INTERNAL", 0); + ADD_CALL_CHAIN_INNER(base); + return result; } #endif /* DBG_HDRS_ALL */ @@ -877,8 +879,8 @@ GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS) break; # endif default: - result = NULL; /* initialized to prevent warning. */ - ABORT_RET("GC_debug_realloc: encountered bad kind"); + result = GC_debug_generic_malloc(lb, hhdr -> hb_obj_kind, OPT_RA s, i); + break; } if (result != NULL) { @@ -973,7 +975,7 @@ STATIC void GC_check_heap_block(struct hblk *hbp, word dummy GC_ATTR_UNUSED) } else { plim = hbp->hb_body + HBLKSIZE - sz; } - /* go through all words in block */ + /* go through all objects in block */ for (bit_no = 0; (word)p <= (word)plim; bit_no += MARK_BIT_OFFSET(sz), p += sz) { if (mark_bit_from_hdr(hhdr, bit_no) && GC_HAS_DEBUG_INFO((ptr_t)p)) { diff --git a/gc/doc/README.cmake b/gc/doc/README.cmake index bec4a03bb..d38ac6ac2 100644 --- a/gc/doc/README.cmake +++ b/gc/doc/README.cmake @@ -55,7 +55,7 @@ HOW TO IMPORT BDWGC Another project could add bdwgc as one of its dependencies with something like this in their CMakeLists.txt: -find_package(BDWgc 8.2.6 REQUIRED) +find_package(BDWgc 8.2.8 REQUIRED) add_executable(Foo foo.c) target_link_libraries(Foo BDWgc::gc) diff --git a/gc/doc/tree.md b/gc/doc/tree.md index 53551633f..0fd3401d5 100644 --- a/gc/doc/tree.md +++ b/gc/doc/tree.md @@ -94,7 +94,7 @@ contributed originally by Dave Barrett. --- +--------------+ | | | ^ | | | | | | | | | | | - TOP_SZ +--------------+<--+ | | + TOP_SZ +--------------+<--+ | | (items)+-<| [] | * | | | | +--------------+ if 0 < bi< HBLKSIZE | | | | | | then large object | | @@ -104,8 +104,8 @@ contributed originally by Dave Barrett. v | aligned) | bi= |GET_BI(p){->hash_link}->key==hi | | v | | - | (bottom_index) \ scratch_alloc'd | | - | ( struct bi ) / by get_index() | | + | (bottom_index) \ GC_scratch_alloc'd | | + | (struct bi) / by get_index() | | --- +->+--------------+ | | ^ | | | | | | | | | @@ -124,43 +124,48 @@ contributed originally by Dave Barrett. | +--------------+ | +-+-+-----+-+-+-+-+ --- | | |<----MAP_LEN---->| | | =HBLKSIZE/GRANULE_BYTES - HDR(p)| GC_find_header(p) | (1024 on Alpha) - | \ from | (8/16 bits each) + HDR(p)| GC_find_header(p) | (1024 elements on Alpha) + | \ from | (16 bits each) | (hdr) (struct hblkhdr) / alloc_hdr() | +--->+----------------------+ | - GET_HDR(p)| word hb_sz (words) | | + GET_HDR(p)| struct hblk *hb_next | | +----------------------+ | - | struct hblk *hb_next | | + | ... | | +----------------------+ | - | word hb_descr | | + | uchar hb_obj_kind | | +----------------------+ | - | char * hb_map |>------------+ - +----------------------+ - | uchar hb_obj_kind | - +----------------------+ - | uchar hb_flags | + | uchar hb_flags | | + +----------------------+ | + | hb_last_reclaimed | | + +----------------------+ | + | size_t hb_sz | | + +----------------------+ | + | word hb_descr | | + +----------------------+ | + | ushort *hb_map |>------------+ +----------------------+ - | hb_last_reclaimed | + | AO_t hb_n_marks | --- +----------------------+ ^ | | - MARK_BITS_SZ| hb_marks[] | * if hdr is free, hb_sz is the size of - (words) | | a heap chunk (struct hblk) of at least - v | | MININCR*HBLKSIZE bytes (below), - --- +----------------------+ otherwise, size of each object in chunk. + | | | * if hdr is free, hb_sz is the size + MARK_BITS_SZ| char/word hb_marks[] | of a heap chunk (struct hblk) of at + | | | least MINHINCR*HBLKSIZE bytes (below); + v | | otherwise, size of each object in chunk. + --- +----------------------+ Dynamic data structures above are interleaved throughout the heap in blocks -of size `MININCR * HBLKSIZE` bytes as done by `gc_scratch_alloc` which cannot +of size `MINHINCR * HBLKSIZE` bytes as done by `GC_scratch_alloc` which cannot be freed; free lists are used (e.g. `alloc_hdr`). `hblk`'s below are collected. (struct hblk) --- +----------------------+ < HBLKSIZE --- - ^ +-----hb_body----------+ (and WORDSZ) ^ --- --- - | | | aligned | ^ ^ + ^ +-----hb_body----------+ (and WORDSZ- ^ --- --- + | | | aligned) | ^ ^ + | | | | | | | | | | hb_sz | - | | | | (words) | | | Object 0 | | | | | | | i |(word- v | | + - - - - - - - - - - -+ --- (bytes)|aligned) --- | diff --git a/gc/dyn_load.c b/gc/dyn_load.c index 0ca4d2465..c73897e6b 100644 --- a/gc/dyn_load.c +++ b/gc/dyn_load.c @@ -1003,7 +1003,7 @@ GC_INNER void GC_register_dynamic_libraries(void) DWORD protect; LPVOID p; char * base; - char * limit, * new_limit; + char * limit; # ifdef MSWIN32 if (GC_no_win32_dlls) return; @@ -1015,17 +1015,19 @@ GC_INNER void GC_register_dynamic_libraries(void) # ifdef MSWINCE if (result == 0) { - /* Page is free; advance to the next possible allocation base */ - new_limit = (char *) - (((DWORD) p + GC_sysinfo.dwAllocationGranularity) - & ~(GC_sysinfo.dwAllocationGranularity-1)); + if ((word)p > GC_WORD_MAX - GC_sysinfo.dwAllocationGranularity) + break; /* overflow */ + /* Page is free; advance to the next possible allocation base. */ + p = (LPVOID)(((DWORD)p + GC_sysinfo.dwAllocationGranularity) + & ~(GC_sysinfo.dwAllocationGranularity-1)); } else # endif /* else */ { if (result != sizeof(buf)) { ABORT("Weird VirtualQuery result"); } - new_limit = (char *)p + buf.RegionSize; + if ((word)p > GC_WORD_MAX - buf.RegionSize) break; /* overflow */ + protect = buf.Protect; if (buf.State == MEM_COMMIT && (protect == PAGE_EXECUTE_READWRITE @@ -1051,11 +1053,10 @@ GC_INNER void GC_register_dynamic_libraries(void) GC_cond_add_roots(base, limit); base = (char *)p; } - limit = new_limit; + limit = (char *)p + buf.RegionSize; } + p = (char *)p + buf.RegionSize; } - if ((word)p > (word)new_limit /* overflow */) break; - p = (LPVOID)new_limit; } GC_cond_add_roots(base, limit); } diff --git a/gc/gcj_mlc.c b/gc/gcj_mlc.c index 478206fbe..10525d21d 100644 --- a/gc/gcj_mlc.c +++ b/gc/gcj_mlc.c @@ -192,28 +192,28 @@ static void maybe_finalize(void) GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr, GC_EXTRA_PARAMS) { - void * result; + void *base, *result; DCL_LOCK_STATE; /* We're careful to avoid extra calls, which could */ /* confuse the backtrace. */ LOCK(); maybe_finalize(); - result = GC_generic_malloc_inner(SIZET_SAT_ADD(lb, DEBUG_BYTES), - GC_gcj_debug_kind); - if (result == 0) { + base = GC_generic_malloc_inner(SIZET_SAT_ADD(lb, DEBUG_BYTES), + GC_gcj_debug_kind); + if (NULL == base) { GC_oom_func oom_fn = GC_oom_fn; UNLOCK(); GC_err_printf("GC_debug_gcj_malloc(%lu, %p) returning NULL (%s:%d)\n", (unsigned long)lb, ptr_to_struct_containing_descr, s, i); return((*oom_fn)(lb)); } - *((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr; + *((void **)((ptr_t)base + sizeof(oh))) = ptr_to_struct_containing_descr; if (!GC_debugging_started) { GC_start_debugging_inner(); } - ADD_CALL_CHAIN(result, ra); - result = GC_store_debug_info_inner(result, (word)lb, s, i); + result = GC_store_debug_info_inner(base, (word)lb, s, i); + ADD_CALL_CHAIN(base, ra); UNLOCK(); GC_dirty(result); REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr); diff --git a/gc/headers.c b/gc/headers.c index 38ef23827..c7517dba9 100644 --- a/gc/headers.c +++ b/gc/headers.c @@ -344,13 +344,13 @@ void GC_apply_to_all_blocks(void (*fn)(struct hblk *h, word client_data), client_data); } j--; - } else if (index_p->index[j] == 0) { + } else if (index_p->index[j] == 0) { j--; - } else { + } else { j -= (signed_word)(index_p->index[j]); - } - } - } + } + } + } } GC_INNER struct hblk * GC_next_block(struct hblk *h, GC_bool allow_free) diff --git a/gc/include/gc.h b/gc/include/gc.h index a1506f2f9..78c6a4bab 100644 --- a/gc/include/gc.h +++ b/gc/include/gc.h @@ -598,9 +598,11 @@ GC_API void * GC_CALL GC_base(void * /* displaced_pointer */); GC_API int GC_CALL GC_is_heap_ptr(const void *); /* Given a pointer to the base of an object, return its size in bytes. */ -/* The returned size may be slightly larger than what was originally */ -/* requested. */ -GC_API size_t GC_CALL GC_size(const void * /* obj_addr */) GC_ATTR_NONNULL(1); +/* (For small objects this also happens to work from interior pointers, */ +/* but that should not be relied upon.) The returned size may be */ +/* slightly larger than what was originally requested. The argument */ +/* may be NULL (causing 0 to be returned). */ +GC_API size_t GC_CALL GC_size(const void * /* obj_addr */); /* For compatibility with C library. This is occasionally faster than */ /* a malloc followed by a bcopy. But if you rely on that, either here */ diff --git a/gc/include/gc_mark.h b/gc/include/gc_mark.h index 058a13e9f..215e41c5b 100644 --- a/gc/include/gc_mark.h +++ b/gc/include/gc_mark.h @@ -245,7 +245,7 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL #endif /* !GC_DEBUG */ /* Similar to GC_size but returns object kind. Size is returned too */ -/* if psize is not NULL. */ +/* if psize is not NULL. The object pointer should not be NULL. */ GC_API int GC_CALL GC_get_kind_and_size(const void *, size_t * /* psize */) GC_ATTR_NONNULL(1); diff --git a/gc/include/gc_version.h b/gc/include/gc_version.h index 2e561b312..b58d0128d 100644 --- a/gc/include/gc_version.h +++ b/gc/include/gc_version.h @@ -30,7 +30,7 @@ /* it to keep the old-style build process working. */ #define GC_TMP_VERSION_MAJOR 8 #define GC_TMP_VERSION_MINOR 2 -#define GC_TMP_VERSION_MICRO 6 /* 8.2.6 */ +#define GC_TMP_VERSION_MICRO 8 /* 8.2.8 */ #ifdef GC_VERSION_MAJOR # if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR \ diff --git a/gc/include/leak_detector.h b/gc/include/leak_detector.h index f8161b27e..c85502c44 100644 --- a/gc/include/leak_detector.h +++ b/gc/include/leak_detector.h @@ -57,6 +57,9 @@ #undef posix_memalign #define posix_memalign(p,a,n) GC_posix_memalign(p,a,n) +#undef malloc_usable_size +#define malloc_usable_size(p) GC_size(p) + #ifndef CHECK_LEAKS # define CHECK_LEAKS() GC_gcollect() /* Note 1: CHECK_LEAKS does not have GC prefix (preserved for */ diff --git a/gc/include/private/dbg_mlc.h b/gc/include/private/dbg_mlc.h index 1df0019e4..0e510ceef 100644 --- a/gc/include/private/dbg_mlc.h +++ b/gc/include/private/dbg_mlc.h @@ -131,6 +131,12 @@ typedef struct { GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]); GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]); # define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci) +# if defined(REDIRECT_MALLOC) && defined(THREADS) && defined(DBG_HDRS_ALL) \ + && NARGS == 0 && NFRAMES % 2 == 0 && defined(GC_HAVE_BUILTIN_BACKTRACE) + GC_INNER void GC_save_callers_no_unlock(struct callinfo info[NFRAMES]); +# define ADD_CALL_CHAIN_INNER(base) \ + GC_save_callers_no_unlock(((oh *)(base)) -> oh_ci) +# endif # define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci) #elif defined(GC_ADD_CALLER) struct callinfo; @@ -142,6 +148,11 @@ typedef struct { # define PRINT_CALL_CHAIN(base) #endif +#if !defined(ADD_CALL_CHAIN_INNER) && defined(DBG_HDRS_ALL) + /* A variant of ADD_CALL_CHAIN() used for internal allocations. */ +# define ADD_CALL_CHAIN_INNER(base) ADD_CALL_CHAIN(base, GC_RETURN_ADDR) +#endif + #ifdef GC_ADD_CALLER # define OPT_RA ra, #else diff --git a/gc/include/private/gc_priv.h b/gc/include/private/gc_priv.h index 736b6b7b6..a398e48d5 100644 --- a/gc/include/private/gc_priv.h +++ b/gc/include/private/gc_priv.h @@ -1097,9 +1097,6 @@ union word_ptr_ao_u { # endif }; -/* We maintain layout maps for heap blocks containing objects of a given */ -/* size. Each entry in this map describes a byte offset and has the */ -/* following type. */ struct hblkhdr { struct hblk * hb_next; /* Link field for hblk free list */ /* and for lists of chunks waiting to be */ @@ -1453,12 +1450,14 @@ struct _GC_arrays { # ifdef USE_MUNMAP # define GC_unmapped_bytes GC_arrays._unmapped_bytes word _unmapped_bytes; -# ifdef COUNT_UNMAPPED_REGIONS -# define GC_num_unmapped_regions GC_arrays._num_unmapped_regions - signed_word _num_unmapped_regions; -# endif # else # define GC_unmapped_bytes 0 +# endif +# if defined(COUNT_UNMAPPED_REGIONS) && defined(USE_MUNMAP) +# define GC_num_unmapped_regions GC_arrays._num_unmapped_regions + signed_word _num_unmapped_regions; +# else +# define GC_num_unmapped_regions 0 # endif bottom_index * _all_nils; # define GC_scan_ptr GC_arrays._scan_ptr @@ -1486,6 +1485,8 @@ struct _GC_arrays { # define GC_trace_addr GC_arrays._trace_addr ptr_t _trace_addr; # endif +# define GC_noop_sink GC_arrays._noop_sink + volatile word _noop_sink; # define GC_capacity_heap_sects GC_arrays._capacity_heap_sects size_t _capacity_heap_sects; # define GC_n_heap_sects GC_arrays._n_heap_sects @@ -1565,13 +1566,17 @@ struct _GC_arrays { # define GC_root_index GC_arrays._root_index struct roots * _root_index[RT_SIZE]; # endif -# ifdef SAVE_CALL_CHAIN -# define GC_last_stack GC_arrays._last_stack +# if defined(SAVE_CALL_CHAIN) && !defined(DONT_SAVE_TO_LAST_STACK) \ + && (!defined(REDIRECT_MALLOC) || !defined(GC_HAVE_BUILTIN_BACKTRACE)) struct callinfo _last_stack[NFRAMES]; /* Stack at last garbage collection. Useful for */ /* debugging mysterious object disappearances. In the */ /* multi-threaded case, we currently only save the */ - /* calling stack. */ + /* calling stack. Not supported in case of malloc */ + /* redirection because backtrace() may call malloc(). */ +# define SAVE_CALLERS_TO_LAST_STACK() GC_save_callers(GC_arrays._last_stack) +# else +# define SAVE_CALLERS_TO_LAST_STACK() (void)0 # endif # ifndef SEPARATE_GLOBALS # define GC_objfreelist GC_arrays._objfreelist @@ -1922,12 +1927,12 @@ GC_INNER void GC_invalidate_mark_state(void); /* ones, and roots may point to */ /* unmarked objects. Reset mark stack. */ GC_INNER GC_bool GC_mark_some(ptr_t cold_gc_frame); - /* Perform about one pages worth of marking */ + /* Perform about one page of marking */ /* work of whatever kind is needed. Returns */ /* quickly if no collection is in progress. */ - /* Return TRUE if mark phase finished. */ + /* Return TRUE if mark phase is finished. */ GC_INNER void GC_initiate_gc(void); - /* initiate collection. */ + /* Initiate collection. */ /* If the mark state is invalid, this */ /* becomes full collection. Otherwise */ /* it's partial. */ @@ -2619,6 +2624,14 @@ GC_EXTERN GC_bool GC_print_back_height; # define REACHABLE_AFTER_DIRTY(p) GC_reachable_here(p) #endif /* !GC_DISABLE_INCREMENTAL */ +#if defined(COUNT_PROTECTED_REGIONS) && defined(MPROTECT_VDB) + /* Do actions on heap growth, if needed, to prevent hitting the */ + /* kernel limit on the VM map regions. */ + GC_INNER void GC_handle_protected_regions_limit(void); +#else +# define GC_handle_protected_regions_limit() (void)0 +#endif + /* Same as GC_base but excepts and returns a pointer to const object. */ #define GC_base_C(p) ((const void *)GC_base((/* no const */ void *)(p))) diff --git a/gc/include/private/gcconfig.h b/gc/include/private/gcconfig.h index 4460e0aa6..c1cf80fb1 100644 --- a/gc/include/private/gcconfig.h +++ b/gc/include/private/gcconfig.h @@ -2824,20 +2824,6 @@ EXTERN_C_BEGIN # define MUNMAP_THRESHOLD 2 #endif -#if defined(USE_MUNMAP) && defined(COUNT_UNMAPPED_REGIONS) \ - && !defined(GC_UNMAPPED_REGIONS_SOFT_LIMIT) - /* The default limit of vm.max_map_count on Linux is ~65530. */ - /* There is approximately one mapped region to every unmapped region. */ - /* Therefore if we aim to use up to half of vm.max_map_count for the */ - /* GC (leaving half for the rest of the process) then the number of */ - /* unmapped regions should be one quarter of vm.max_map_count. */ -# if defined(__DragonFly__) -# define GC_UNMAPPED_REGIONS_SOFT_LIMIT (1000000 / 4) -# else -# define GC_UNMAPPED_REGIONS_SOFT_LIMIT 16384 -# endif -#endif - #if defined(GC_DISABLE_INCREMENTAL) || defined(DEFAULT_VDB) # undef GWW_VDB # undef MPROTECT_VDB @@ -2934,6 +2920,27 @@ EXTERN_C_BEGIN # define NO_VDB_FOR_STATIC_ROOTS #endif +#if defined(MPROTECT_VDB) && !defined(DONT_COUNT_PROTECTED_REGIONS) \ + && !defined(COUNT_PROTECTED_REGIONS) \ + && (defined(LINUX) || defined(__DragonFly__)) +# define COUNT_PROTECTED_REGIONS +#endif + +#if (defined(COUNT_PROTECTED_REGIONS) || defined(COUNT_UNMAPPED_REGIONS)) \ + && !defined(GC_UNMAPPED_REGIONS_SOFT_LIMIT) + /* The default limit of vm.max_map_count on Linux is ~65530. */ + /* There is approximately one mapped region to every protected or */ + /* unmapped region. Therefore if we aim to use up to half of */ + /* vm.max_map_count for the GC (leaving half for the rest of the */ + /* process) then the number of such regions should be one quarter */ + /* of vm.max_map_count. */ +# if defined(__DragonFly__) +# define GC_UNMAPPED_REGIONS_SOFT_LIMIT (1000000 / 4) +# else +# define GC_UNMAPPED_REGIONS_SOFT_LIMIT 16384 +# endif +#endif + #if ((defined(UNIX_LIKE) && (defined(DARWIN) || defined(HAIKU) \ || defined(HURD) || defined(OPENBSD) \ || defined(ARM32) \ diff --git a/gc/mallocx.c b/gc/mallocx.c index cd6e07e7d..21c35e317 100644 --- a/gc/mallocx.c +++ b/gc/mallocx.c @@ -293,7 +293,8 @@ GC_API size_t GC_CALL GC_get_expl_freed_bytes_since_gc(void) /* GC_malloc_many or friends to replenish it. (We do not round up */ /* object sizes, since a call indicates the intention to consume many */ /* objects of exactly this size.) */ -/* We assume that the size is a multiple of GRANULE_BYTES. */ +/* We assume that the size is non-zero and a multiple of */ +/* GRANULE_BYTES, and that it already includes EXTRA_BYTES value. */ /* We return the free-list by assigning it to *result, since it is */ /* not safe to return, e.g. a linked list of pointer-free objects, */ /* since the collector would not retain the entire list if it were */ @@ -315,8 +316,8 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result) /* Currently a single object is always allocated if manual VDB. */ /* TODO: GC_dirty should be called for each linked object (but */ /* the last one) to support multiple objects allocation. */ - if (!SMALL_OBJ(lb) || GC_manual_vdb) { - op = GC_generic_malloc(lb, k); + if (!EXPECT(lb <= MAXOBJBYTES, TRUE) || GC_manual_vdb) { + op = GC_generic_malloc(lb - EXTRA_BYTES, k); if (EXPECT(0 != op, TRUE)) obj_link(op) = 0; *result = op; @@ -334,7 +335,7 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result) if (EXPECT(get_have_errors(), FALSE)) GC_print_all_errors(); GC_INVOKE_FINALIZERS(); - GC_DBG_COLLECT_AT_MALLOC(lb); + GC_DBG_COLLECT_AT_MALLOC(lb - EXTRA_BYTES); if (!EXPECT(GC_is_initialized, TRUE)) GC_init(); LOCK(); /* Do our share of marking work */ @@ -473,7 +474,7 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result) /* As a last attempt, try allocating a single object. Note that */ /* this may trigger a collection or expand the heap. */ - op = GC_generic_malloc_inner(lb, k); + op = GC_generic_malloc_inner(lb - EXTRA_BYTES, k); if (0 != op) obj_link(op) = 0; out: diff --git a/gc/mark.c b/gc/mark.c index 5b268d2f5..50e6cfd7c 100644 --- a/gc/mark.c +++ b/gc/mark.c @@ -34,8 +34,6 @@ void GC_noop6(word arg1 GC_ATTR_UNUSED, word arg2 GC_ATTR_UNUSED, # endif } -volatile word GC_noop_sink; - /* Single argument version, robust against whole program analysis. */ GC_ATTR_NO_SANITIZE_THREAD GC_API void GC_CALL GC_noop1(word x) @@ -1087,7 +1085,7 @@ STATIC void GC_do_parallel_mark(void) ABORT("Tried to start parallel mark in bad state"); GC_VERBOSE_LOG_PRINTF("Starting marking for mark phase number %lu\n", (unsigned long)GC_mark_no); - GC_first_nonempty = (AO_t)GC_mark_stack; + AO_store(&GC_first_nonempty, (AO_t)GC_mark_stack); GC_active_count = 0; GC_helper_count = 1; GC_help_wanted = TRUE; @@ -1435,7 +1433,7 @@ GC_API void GC_CALL GC_print_trace_inner(GC_word gc_no) { int i; - for (i = GC_trace_buf_ptr-1; i != GC_trace_buf_ptr; i--) { + for (i = GC_trace_buf_ptr-1;; i--) { struct trace_entry *p; if (i < 0) i = TRACE_ENTRIES-1; @@ -1449,6 +1447,7 @@ GC_API void GC_CALL GC_print_trace_inner(GC_word gc_no) p -> kind, (unsigned)(p -> gc_no), (unsigned long)(p -> bytes_allocd), (long)p->arg1 ^ 0x80000000L, (long)p->arg2 ^ 0x80000000L); + if (i == GC_trace_buf_ptr) break; } GC_printf("Trace incomplete\n"); } @@ -1800,7 +1799,7 @@ STATIC void GC_push_marked(struct hblk *h, hdr *hhdr) /* the disclaim notifiers. */ /* To determine whether an object has been reclaimed, we require that */ /* any live object has a non-zero as one of the two lowest bits of the */ -/* first word. On the other hand, a reclaimed object is a members of */ +/* first word. On the other hand, a reclaimed object is a member of */ /* free-lists, and thus contains a word-aligned next-pointer as the */ /* first word. */ GC_ATTR_NO_SANITIZE_THREAD diff --git a/gc/misc.c b/gc/misc.c index caab713dd..91cb193a0 100644 --- a/gc/misc.c +++ b/gc/misc.c @@ -462,20 +462,21 @@ GC_API int GC_CALL GC_is_heap_ptr(const void *p) return HDR_FROM_BI(bi, p) != 0; } -/* Return the size of an object, given a pointer to its base. */ -/* (For small objects this also happens to work from interior pointers, */ -/* but that shouldn't be relied upon.) */ GC_API size_t GC_CALL GC_size(const void * p) { - hdr * hhdr = HDR(p); + hdr *hhdr; + /* Accept NULL for compatibility with malloc_usable_size(). */ + if (EXPECT(NULL == p, FALSE)) return 0; + + hhdr = HDR(p); return (size_t)hhdr->hb_sz; } - /* These getters remain unsynchronized for compatibility (since some */ /* clients could call some of them from a GC callback holding the */ /* allocator lock). */ + GC_API size_t GC_CALL GC_get_heap_size(void) { /* ignore the memory space returned to OS (i.e. count only the */ @@ -2352,8 +2353,7 @@ GC_API void * GC_CALL GC_do_blocking(GC_fn_type fn, void * client_data) static void block_add_size(struct hblk *h, word pbytes) { hdr *hhdr = HDR(h); - *(word *)pbytes += (WORDS_TO_BYTES(hhdr->hb_sz) + (HBLKSIZE - 1)) - & ~(word)(HBLKSIZE - 1); + *(word *)pbytes += (hhdr -> hb_sz + (HBLKSIZE - 1)) & ~(word)(HBLKSIZE - 1); } GC_API size_t GC_CALL GC_get_memory_use(void) diff --git a/gc/os_dep.c b/gc/os_dep.c index b7679b6a3..e90c77250 100644 --- a/gc/os_dep.c +++ b/gc/os_dep.c @@ -386,7 +386,7 @@ GC_INNER const char * GC_get_maps(void) /* Set p to point just past last slash, if any. */ while (*p != '\0' && *p != '\n' && *p != ' ' && *p != '\t') ++p; - while (*p != '/' && (word)p >= (word)map_path) --p; + while ((word)p >= (word)map_path && *p != '/') --p; ++p; if (strncmp(nm, p, nm_len) == 0) { *startp = my_start; @@ -619,7 +619,7 @@ GC_INNER const char * GC_get_maps(void) result = bound; } else { result += pgsz; /* no overflow expected */ - GC_noop1((word)(*result)); + GC_noop1((word)(unsigned char)(*result)); } } @@ -1026,7 +1026,7 @@ GC_INNER size_t GC_page_size = 0; } result -= MIN_PAGE_SIZE; /* no underflow expected */ } - GC_noop1((word)(*result)); + GC_noop1((word)(unsigned char)(*result)); } } GC_reset_fault_handler(); @@ -1966,25 +1966,21 @@ void GC_register_data_segments(void) p = base = limit = GC_least_described_address(static_root); while ((word)p < (word)GC_sysinfo.lpMaximumApplicationAddress) { size_t result = VirtualQuery(p, &buf, sizeof(buf)); - char * new_limit; DWORD protect; if (result != sizeof(buf) || buf.AllocationBase == 0 || GC_is_heap_base(buf.AllocationBase)) break; - new_limit = (char *)p + buf.RegionSize; + if ((word)p > GC_WORD_MAX - buf.RegionSize) break; /* overflow */ protect = buf.Protect; if (buf.State == MEM_COMMIT && is_writable(protect)) { - if ((char *)p == limit) { - limit = new_limit; - } else { + if ((char *)p != limit) { if (base != limit) GC_add_roots_inner(base, limit, FALSE); base = (char *)p; - limit = new_limit; } + limit = (char *)p + buf.RegionSize; } - if ((word)p > (word)new_limit /* overflow */) break; - p = (LPVOID)new_limit; + p = (char *)p + buf.RegionSize; } if (base != limit) GC_add_roots_inner(base, limit, FALSE); } @@ -2032,10 +2028,11 @@ void GC_register_data_segments(void) } else { GC_reset_fault_handler(); /* We got here via a longjmp. The address is not readable. */ - /* This is known to happen under Solaris 2.4 + gcc, which place */ - /* string constants in the text segment, but after etext. */ - /* Use plan B. Note that we now know there is a gap between */ - /* text and data segments, so plan A brought us something. */ + /* This is known to happen under Solaris 2.4 + gcc, which */ + /* places string constants in the text segment, but after */ + /* etext. Use plan B. Note that we now know there is a gap */ + /* between text and data segments, so plan A brought us */ + /* something. */ result = (char *)GC_find_limit(DATAEND, FALSE); } return (/* no volatile */ ptr_t)result; @@ -3142,9 +3139,7 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) * to the write-protected heap. Probably the best way to do this is to * ensure that system calls write at most to pointer-free objects in the * heap, and do even that only if we are on a platform on which those - * are not protected. Another alternative is to wrap system calls - * (see example for read below), but the current implementation holds - * applications. + * are not protected. * We assume the page size is a multiple of HBLKSIZE. * We prefer them to be the same. We avoid protecting pointer-free * objects only if they are the same. @@ -3436,6 +3431,19 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) { # if !defined(MSWIN32) && !defined(MSWINCE) struct sigaction act, oldact; +# endif + +# ifdef COUNT_PROTECTED_REGIONS + GC_ASSERT(GC_page_size != 0); + if ((signed_word)(GC_heapsize / (word)GC_page_size) + >= ((signed_word)GC_UNMAPPED_REGIONS_SOFT_LIMIT + - GC_num_unmapped_regions) * 2) { + GC_COND_LOG_PRINTF("Cannot turn on GC incremental mode" + " as heap contains too many pages\n"); + return FALSE; + } +# endif +# if !defined(MSWIN32) && !defined(MSWINCE) act.sa_flags = SA_RESTART | SA_SIGINFO; act.sa_sigaction = GC_write_fault_handler; (void)sigemptyset(&act.sa_mask); @@ -3610,16 +3618,44 @@ STATIC void GC_protect_heap(void) } } -/* - * Acquiring the allocation lock here is dangerous, since this - * can be called from within GC_call_with_alloc_lock, and the cord - * package does so. On systems that allow nested lock acquisition, this - * happens to work. - */ +# if defined(CAN_HANDLE_FORK) && defined(DARWIN) && defined(THREADS) \ + || defined(COUNT_PROTECTED_REGIONS) + /* Remove protection for the entire heap not updating GC_dirty_pages. */ + STATIC void GC_unprotect_all_heap(void) + { + unsigned i; + + GC_ASSERT(I_HOLD_LOCK()); + GC_ASSERT(GC_auto_incremental); + for (i = 0; i < GC_n_heap_sects; i++) { + UNPROTECT(GC_heap_sects[i].hs_start, GC_heap_sects[i].hs_bytes); + } + } +# endif /* CAN_HANDLE_FORK && DARWIN && THREADS || COUNT_PROTECTED_REGIONS */ + +# ifdef COUNT_PROTECTED_REGIONS + GC_INNER void GC_handle_protected_regions_limit(void) + { + GC_ASSERT(GC_page_size != 0); + /* To prevent exceeding the limit of vm.max_map_count, the most */ + /* trivial (though highly restrictive) way is to turn off the */ + /* incremental collection mode (based on mprotect) once the */ + /* number of pages in the heap reaches that limit. */ + if (GC_auto_incremental && !GC_GWW_AVAILABLE() + && (signed_word)(GC_heapsize / (word)GC_page_size) + >= ((signed_word)GC_UNMAPPED_REGIONS_SOFT_LIMIT + - GC_num_unmapped_regions) * 2) { + GC_unprotect_all_heap(); +# ifdef DARWIN + GC_task_self = 0; +# endif + GC_incremental = FALSE; + WARN("GC incremental mode is turned off" + " to prevent hitting VM maps limit\n", 0); + } + } +# endif /* COUNT_PROTECTED_REGIONS */ -/* We no longer wrap read by default, since that was causing too many */ -/* problems. It is preferred that the client instead avoids writing */ -/* to the write-protected heap with a system call. */ #endif /* MPROTECT_VDB */ #if !defined(THREADS) && (defined(PROC_VDB) || defined(SOFT_VDB)) @@ -4055,19 +4091,24 @@ GC_INLINE void GC_proc_read_dirty(GC_bool output_unneeded) return &soft_vdb_buf[ofs / sizeof(pagemap_elem_t)]; } - static void soft_set_grungy_pages(ptr_t vaddr /* start */, ptr_t limit, + static void soft_set_grungy_pages(ptr_t start, ptr_t limit, ptr_t next_start_hint) { + word vaddr = (word)start & ~(word)(GC_page_size-1); + off_t next_fpos_hint; + + GC_ASSERT(modHBLKSZ((word)start) == 0); GC_ASSERT(GC_page_size != 0); - while ((word)vaddr < (word)limit) { + next_fpos_hint = (off_t)((word)next_start_hint / GC_page_size + * sizeof(pagemap_elem_t)); + while (vaddr < (word)limit) { size_t res; word limit_buf; const pagemap_elem_t *bufp = pagemap_buffered_read(&res, - (off_t)((word)vaddr / GC_page_size * sizeof(pagemap_elem_t)), - (size_t)((((word)limit - (word)vaddr + GC_page_size-1) - / GC_page_size) * sizeof(pagemap_elem_t)), - (off_t)((word)next_start_hint / GC_page_size - * sizeof(pagemap_elem_t))); + (off_t)(vaddr / GC_page_size * sizeof(pagemap_elem_t)), + (size_t)(((word)limit - vaddr + GC_page_size-1) / GC_page_size + * sizeof(pagemap_elem_t)), + next_fpos_hint); if (res % sizeof(pagemap_elem_t) != 0) { /* Punt: */ @@ -4076,19 +4117,23 @@ GC_INLINE void GC_proc_read_dirty(GC_bool output_unneeded) break; } - limit_buf = ((word)vaddr & ~(word)(GC_page_size-1)) - + (res / sizeof(pagemap_elem_t)) * GC_page_size; - for (; (word)vaddr < limit_buf; vaddr += GC_page_size, bufp++) + limit_buf = vaddr + (res / sizeof(pagemap_elem_t)) * GC_page_size; + for (; vaddr < limit_buf; vaddr += GC_page_size, bufp++) if ((*bufp & PM_SOFTDIRTY_MASK) != 0) { struct hblk * h; - ptr_t next_vaddr = vaddr + GC_page_size; + word next_vaddr = vaddr + GC_page_size; + if (EXPECT(next_vaddr > (word)limit, FALSE)) + next_vaddr = (word)limit; /* If the bit is set, the respective PTE was written to */ /* since clearing the soft-dirty bits. */ # ifdef DEBUG_DIRTY_BITS GC_log_printf("dirty page at: %p\n", (void *)vaddr); # endif - for (h = (struct hblk *)vaddr; (word)h < (word)next_vaddr; h++) { + h = (struct hblk *)vaddr; + if (EXPECT(vaddr < (word)start, FALSE)) + h = (struct hblk *)start; + for (; (word)h < next_vaddr; h++) { word index = PHT_HASH(h); set_pht_entry_from_index(GC_grungy_pages, index); } @@ -4124,9 +4169,9 @@ GC_INLINE void GC_proc_read_dirty(GC_bool output_unneeded) pagemap_buf_len = 0; /* invalidate soft_vdb_buf */ for (i = 0; i != GC_n_heap_sects; ++i) { - ptr_t vaddr = GC_heap_sects[i].hs_start; + ptr_t start = GC_heap_sects[i].hs_start; - soft_set_grungy_pages(vaddr, vaddr + GC_heap_sects[i].hs_bytes, + soft_set_grungy_pages(start, start + GC_heap_sects[i].hs_bytes, i < GC_n_heap_sects-1 ? GC_heap_sects[i+1].hs_start : NULL); } @@ -4136,7 +4181,7 @@ GC_INLINE void GC_proc_read_dirty(GC_bool output_unneeded) # ifndef NO_VDB_FOR_STATIC_ROOTS for (i = 0; (int)i < n_root_sets; ++i) { - soft_set_grungy_pages(GC_static_roots[i].r_start, + soft_set_grungy_pages((ptr_t)HBLKPTR(GC_static_roots[i].r_start), GC_static_roots[i].r_end, (int)i < n_root_sets-1 ? GC_static_roots[i+1].r_start : NULL); @@ -4555,19 +4600,12 @@ typedef enum { # ifdef CAN_HANDLE_FORK GC_INNER void GC_dirty_update_child(void) { - unsigned i; - GC_ASSERT(I_HOLD_LOCK()); if (0 == GC_task_self) return; /* GC incremental mode is off */ - GC_ASSERT(GC_auto_incremental); GC_ASSERT(GC_mprotect_state == GC_MP_NORMAL); - - /* Unprotect the entire heap not updating GC_dirty_pages. */ GC_task_self = mach_task_self(); /* needed by UNPROTECT() */ - for (i = 0; i < GC_n_heap_sects; i++) { - UNPROTECT(GC_heap_sects[i].hs_start, GC_heap_sects[i].hs_bytes); - } + GC_unprotect_all_heap(); /* Restore the old task exception ports. */ /* TODO: Should we do it in fork_prepare/parent_proc? */ @@ -5142,13 +5180,32 @@ GC_API int GC_CALL GC_get_pages_executable(void) /* you could use something like pthread_getspecific. */ # endif GC_bool GC_in_save_callers = FALSE; -#endif + +# if defined(THREADS) && defined(DBG_HDRS_ALL) +# include "private/dbg_mlc.h" + + /* A dummy version of GC_save_callers() which does not call */ + /* backtrace(). */ + GC_INNER void GC_save_callers_no_unlock(struct callinfo info[NFRAMES]) + { + GC_ASSERT(I_HOLD_LOCK()); + info[0].ci_pc = (word)(&GC_save_callers_no_unlock); + BZERO(&info[1], sizeof(void *) * (NFRAMES - 1)); + } +# endif +#endif /* REDIRECT_MALLOC */ GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]) { void * tmp_info[NFRAMES + 1]; int npcs, i; + GC_ASSERT(I_HOLD_LOCK()); + /* backtrace may call dl_iterate_phdr which is also */ + /* used by GC_register_dynamic_libraries, and */ + /* dl_iterate_phdr is not guaranteed to be reentrant. */ + + GC_STATIC_ASSERT(sizeof(struct callinfo) == sizeof(void *)); # ifdef REDIRECT_MALLOC if (GC_in_save_callers) { info[0].ci_pc = (word)(&GC_save_callers); @@ -5156,17 +5213,15 @@ GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]) return; } GC_in_save_callers = TRUE; + /* backtrace() might call a redirected malloc. */ + UNLOCK(); + npcs = backtrace((void **)tmp_info, NFRAMES + 1); + LOCK(); +# else + npcs = backtrace((void **)tmp_info, NFRAMES + 1); # endif - - GC_ASSERT(I_HOLD_LOCK()); - /* backtrace may call dl_iterate_phdr which is also */ - /* used by GC_register_dynamic_libraries, and */ - /* dl_iterate_phdr is not guaranteed to be reentrant. */ - /* We retrieve NFRAMES+1 pc values, but discard the first one, since */ /* it points to our own frame. */ - GC_STATIC_ASSERT(sizeof(struct callinfo) == sizeof(void *)); - npcs = backtrace((void **)tmp_info, NFRAMES + 1); i = 0; if (npcs > 1) { i = npcs - 1; diff --git a/gc/pthread_stop_world.c b/gc/pthread_stop_world.c index 2b4548905..f903f6fe2 100644 --- a/gc/pthread_stop_world.c +++ b/gc/pthread_stop_world.c @@ -1262,6 +1262,10 @@ GC_INNER void GC_stop_world(void) #else /* !NACL */ +# ifndef GC_OPENBSD_UTHREADS + static GC_bool in_resend_restart_signals; +# endif + /* Restart all threads that were suspended by the collector. */ /* Return the number of restart signals that were sent. */ STATIC int GC_restart_all(void) @@ -1285,8 +1289,24 @@ GC_INNER void GC_stop_world(void) # endif if (GC_retry_signals && AO_load(&p->stop_info.last_stop_count) - == (AO_t)((word)GC_stop_count | THREAD_RESTARTED)) - continue; /* The thread has been restarted. */ + == (AO_t)((word)GC_stop_count | THREAD_RESTARTED)) { + /* The thread has been restarted. */ + if (!in_resend_restart_signals) { + /* Some user signal (which we do not block, e.g. SIGQUIT) */ + /* has already restarted the thread, but nonetheless we */ + /* need to count the thread in n_live_threads, so that */ + /* to decrement the semaphore's value proper amount of */ + /* times. (We are also sending the restart signal to the */ + /* thread, it is not needed actually but does not hurt.) */ + } else { + continue; + /* FIXME: Still, an extremely low chance exists that the */ + /* user signal restarts the thread after the restart */ + /* signal has been lost (causing sem_timedwait() to fail) */ + /* while retrying, causing finally a mismatch between */ + /* GC_suspend_ack_sem and n_live_threads. */ + } + } n_live_threads++; # endif # ifdef DEBUG_THREADS @@ -1337,13 +1357,16 @@ GC_INNER void GC_start_world(void) /* The updated value should now be visible to the */ /* signal handler (note that pthread_kill is not on */ /* the list of functions which synchronize memory). */ + GC_ASSERT(!in_resend_restart_signals); # endif n_live_threads = GC_restart_all(); # ifdef GC_OPENBSD_UTHREADS (void)n_live_threads; # else if (GC_retry_signals) { + in_resend_restart_signals = TRUE; resend_lost_signals_retry(n_live_threads, GC_restart_all); + in_resend_restart_signals = FALSE; } /* else */ # ifdef GC_NETBSD_THREADS_WORKAROUND else { diff --git a/gc/ptr_chck.c b/gc/ptr_chck.c index bd5cbb899..2d8e9b46c 100644 --- a/gc/ptr_chck.c +++ b/gc/ptr_chck.c @@ -227,7 +227,7 @@ GC_API void * GC_CALL GC_is_visible(void *p) retry: switch(descr & GC_DS_TAGS) { case GC_DS_LENGTH: - if ((word)p - (word)base > descr) goto fail; + if ((word)p - (word)base >= descr) goto fail; break; case GC_DS_BITMAP: if ((word)p - (word)base >= WORDS_TO_BYTES(BITMAP_BITS) @@ -245,6 +245,9 @@ GC_API void * GC_CALL GC_is_visible(void *p) + (descr & ~(word)GC_DS_TAGS)); } else { ptr_t type_descr = *(ptr_t *)base; + + if (EXPECT(NULL == type_descr, FALSE)) + goto fail; /* see comment in GC_mark_from */ descr = *(word *)(type_descr - (descr - (word)(GC_DS_PER_OBJECT - GC_INDIR_PER_OBJ_BIAS))); diff --git a/gc/reclaim.c b/gc/reclaim.c index 3af6bb550..926d4b641 100644 --- a/gc/reclaim.c +++ b/gc/reclaim.c @@ -833,7 +833,8 @@ STATIC void GC_do_enumerate_reachable_objects(struct hblk *hbp, word ped) plim = hbp->hb_body + HBLKSIZE - sz; } /* Go through all words in block. */ - for (bit_no = 0; p <= plim; bit_no += MARK_BIT_OFFSET(sz), p += sz) { + for (bit_no = 0; (word)p <= (word)plim; + bit_no += MARK_BIT_OFFSET(sz), p += sz) { if (mark_bit_from_hdr(hhdr, bit_no)) { ((struct enumerate_reachable_s *)ped)->proc(p, sz, ((struct enumerate_reachable_s *)ped)->client_data); diff --git a/gc/specific.c b/gc/specific.c index 88988b397..6dae5d463 100644 --- a/gc/specific.c +++ b/gc/specific.c @@ -146,14 +146,12 @@ GC_INNER void * GC_slow_getspecific(tsd * key, word qtid, } if (entry == NULL) return NULL; /* Set cache_entry. */ - entry -> qtid = (AO_t)qtid; + AO_store(&(entry -> qtid), qtid); /* It's safe to do this asynchronously. Either value */ /* is safe, though may produce spurious misses. */ /* We're replacing one qtid with another one for the */ /* same thread. */ - *cache_ptr = entry; - /* Again this is safe since pointer assignments are */ - /* presumed atomic, and either pointer is valid. */ + AO_store((volatile AO_t *)cache_ptr, (AO_t)entry); return TS_REVEAL_PTR(entry -> value); } diff --git a/gc/tests/leak_test.c b/gc/tests/leak_test.c index 37fa26b3f..f13d08138 100644 --- a/gc/tests/leak_test.c +++ b/gc/tests/leak_test.c @@ -23,6 +23,7 @@ int main(void) { for (i = 0; i < 10; ++i) { p[i] = (char*)malloc(sizeof(int)+i); CHECK_OUT_OF_MEMORY(p[i]); + (void)malloc_usable_size(p[i]); } CHECK_LEAKS(); for (i = 1; i < 10; ++i) { diff --git a/gc/tests/test.c b/gc/tests/test.c index 501a864cc..529ca33d8 100644 --- a/gc/tests/test.c +++ b/gc/tests/test.c @@ -1896,6 +1896,10 @@ void check_heap_stats(void) (void)GC_get_size_map_at(-1); (void)GC_get_size_map_at(1); # endif + if (GC_size(NULL) != 0) { + GC_printf("GC_size(NULL) failed\n"); + FAIL; + } # ifdef NO_CLOCK GC_printf("Completed %u collections\n", (unsigned)GC_get_gc_no()); diff --git a/gc/tools/setjmp_t.c b/gc/tools/setjmp_t.c index 4a7cdf799..b2ae60d5c 100644 --- a/gc/tools/setjmp_t.c +++ b/gc/tools/setjmp_t.c @@ -87,7 +87,8 @@ int main(void) volatile word sp; unsigned ps = GETPAGESIZE(); JMP_BUF b; -# if !defined(__cplusplus) || __cplusplus < 201703L /* before c++17 */ +# if (!defined(__cplusplus) || __cplusplus < 201703L /* before c++17 */) \ + && (!defined(__GNUC__) || defined(__OPTIMIZE__)) register # endif int x = (int)strlen(a_str); /* 1, slightly disguised */ diff --git a/gc/typd_mlc.c b/gc/typd_mlc.c index 74ab90626..c5b8ae0e8 100644 --- a/gc/typd_mlc.c +++ b/gc/typd_mlc.c @@ -598,8 +598,6 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_explicitly_typed(size_t lb, /* the former might be updated asynchronously. */ lg = BYTES_TO_GRANULES(GC_size(op)); set_obj_descr(op, GRANULES_TO_WORDS(lg), d); - GC_dirty(op + GRANULES_TO_WORDS(lg) - 1); - REACHABLE_AFTER_DIRTY(d); return op; } @@ -644,8 +642,6 @@ GC_API GC_ATTR_MALLOC void * GC_CALL lg = BYTES_TO_GRANULES(GC_size(op)); } set_obj_descr(op, GRANULES_TO_WORDS(lg), d); - GC_dirty((word *)op + GRANULES_TO_WORDS(lg) - 1); - REACHABLE_AFTER_DIRTY(d); return op; } From de386faeb43e6ead80a059260e85e075dcd126c9 Mon Sep 17 00:00:00 2001 From: Erick Gallesio Date: Mon, 23 Sep 2024 15:50:37 +0200 Subject: [PATCH 2/2] Updated GC version in PACKAGE_USED --- PACKAGES-USED | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PACKAGES-USED b/PACKAGES-USED index 93b097855..f758bdf00 100644 --- a/PACKAGES-USED +++ b/PACKAGES-USED @@ -18,7 +18,7 @@ the full version counterpart. GC: The Boehm's conservative garbage collector for C and C++ ============================================================ - - Version: 8.2.6 + - Version: 8.2.8 - License: Free (BSD-like) - Home Page: https://www.hboehm.info/gc/