diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2022-03-16 06:54:03 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2022-03-16 11:07:15 +0300 |
commit | 673f0cf3f25ad914bd273d50d9973f9dc92ff801 (patch) | |
tree | 48c14975710b24adef8e8267e0fbdea957d4e8e0 /tests | |
parent | 4f57974b53c3acab0cfca1ee655a75026ccd5f7e (diff) | |
download | bdwgc-673f0cf3f25ad914bd273d50d9973f9dc92ff801.tar.gz |
Fix SIGSEGV caused by dropped stack access from child process in gctest
(fix of commit c808151a0)
Issue #256 (bdwgc).
Previously, a local variable was passed in gctest to
GC_move_disappearing_link as a link to clear, this led to a memory
access violation during garbage collection in the child process
if the fork occurred between GC_move_disappearing_link(..., &new_link)
and GC_unregister_disappearing_link(&new_link).
This commit changes the mentioned local variable (new_link) use - now
it contains a pointer to a heap-allocated link rather then containing
just a link.
* tests/gctest.c (mktree): Change type of new_link from void* to
void**; initialize it to GC_NEW(void*) and ensure it is non-null;
replace new_link with *new_link; add comment new_link object is
reclaimed correctly even if the thread is dropped in the child
process between GC_move_disappearing_link(new_link) and
GC_unregister_disappearing_link.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/gctest.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/tests/gctest.c b/tests/gctest.c index 86692503..97081afa 100644 --- a/tests/gctest.c +++ b/tests/gctest.c @@ -932,9 +932,10 @@ tn * mktree(int n) if (AO_fetch_and_add1(&extra_count) % 119 == 0) { # ifndef GC_NO_FINALIZATION int my_index; - void *new_link; + void **new_link = GC_NEW(void *); # endif + CHECK_OUT_OF_MEMORY(new_link); { FINALIZER_LOCK(); /* Losing a count here causes erroneous report of failure. */ @@ -964,18 +965,23 @@ tn * mktree(int n) GC_printf("GC_move_disappearing_link(link,link) failed\n"); FAIL; } - new_link = (void *)live_indicators[my_index]; + *new_link = (void *)live_indicators[my_index]; if (GC_move_disappearing_link((void **)(&(live_indicators[my_index])), - &new_link) != GC_SUCCESS) { + new_link) != GC_SUCCESS) { GC_printf("GC_move_disappearing_link(new_link) failed\n"); FAIL; } - if (GC_unregister_disappearing_link(&new_link) == 0) { + /* Note: if other thread is performing fork at this moment, */ + /* then the stack of the current thread is dropped (together */ + /* with new_link variable) in the child process, and */ + /* GC_dl_hashtbl entry with the link equal to new_link will be */ + /* removed when a collection occurs (as expected). */ + if (GC_unregister_disappearing_link(new_link) == 0) { GC_printf("GC_unregister_disappearing_link failed\n"); FAIL; } if (GC_move_disappearing_link((void **)(&(live_indicators[my_index])), - &new_link) != GC_NOT_FOUND) { + new_link) != GC_NOT_FOUND) { GC_printf("GC_move_disappearing_link(new_link) failed 2\n"); FAIL; } @@ -994,18 +1000,18 @@ tn * mktree(int n) GC_printf("GC_move_long_link(link,link) failed\n"); FAIL; } - new_link = live_long_refs[my_index]; + *new_link = live_long_refs[my_index]; if (GC_move_long_link(&live_long_refs[my_index], - &new_link) != GC_SUCCESS) { + new_link) != GC_SUCCESS) { GC_printf("GC_move_long_link(new_link) failed\n"); FAIL; } - if (GC_unregister_long_link(&new_link) == 0) { + if (GC_unregister_long_link(new_link) == 0) { GC_printf("GC_unregister_long_link failed\n"); FAIL; } if (GC_move_long_link(&live_long_refs[my_index], - &new_link) != GC_NOT_FOUND) { + new_link) != GC_NOT_FOUND) { GC_printf("GC_move_long_link(new_link) failed 2\n"); FAIL; } |