summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2022-03-16 06:54:03 +0300
committerIvan Maidanski <ivmai@mail.ru>2022-04-24 17:07:20 +0300
commit35d17ba4317433820494d422d19a7a8db8d92a01 (patch)
tree5daa3c2fed6c328a1b629fa218659b24c6c45ca4
parent47bb700fc4125bf0898bfbfbf024a9712f33d3c3 (diff)
downloadbdwgc-35d17ba4317433820494d422d19a7a8db8d92a01.tar.gz
Fix SIGSEGV caused by dropped stack access from child process in gctest
(a cherry-pick of commit 296320cd3 from 'release-7_6') 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/test.c [!GC_NO_FINALIZATION] (mktree): Change type of new_link from void* to void**; initialize it to GC_NEW(void*) and ensure it is non-null; increment collectable_count, 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.
-rw-r--r--tests/test.c27
1 files changed, 17 insertions, 10 deletions
diff --git a/tests/test.c b/tests/test.c
index 7dc0a754..a6085028 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -841,9 +841,11 @@ tn * mktree(int n)
if (counter++ % 119 == 0) {
# ifndef GC_NO_FINALIZATION
int my_index;
- void *new_link;
-# endif
+ void **new_link = GC_NEW(void *);
+ CHECK_OUT_OF_MEMORY(new_link);
+ collectable_count++;
+# endif
{
FINALIZER_LOCK();
/* Losing a count here causes erroneous report of failure. */
@@ -873,18 +875,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;
}
@@ -903,18 +910,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;
}