diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2022-01-30 23:34:49 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2022-02-01 12:10:15 +0300 |
commit | 990dcdba1f1fc89cd3903bec3c6dda2fc8b3cc9f (patch) | |
tree | ee6f87a8ec58f162bd3c9474c53d101fc6ca99ab /mach_dep.c | |
parent | 5e576c0b5373b2af633629e509d81001e420e8fb (diff) | |
download | bdwgc-990dcdba1f1fc89cd3903bec3c6dda2fc8b3cc9f.tar.gz |
Fix recursive malloc during pthread_create (E2K)
(fix of commit 9ddbbae8e)
Issue #411 (bdwgc).
Use of malloc/free inside an asynchronous signal is not safe and may
lead to a crash inside malloc, e.g. if the signal occurs when malloc
is called from pthread_create. Also, malloc cannot be used by the
code executed during stop-the-world if the collector is built with
enabled malloc redirection.
This commit replaces malloc/free used to get procedure (register)
stack with alloca or GC_INTERNAL_MALLOC (the latter is not used during
stop-the-world).
This commit also prevents accessing freed procedure stack buffers from
GC_push_all_stacks when the world is not stopped.
* include/private/gc_priv.h [E2K] (GC_get_procedure_stack): Change the
arguments to accept buf and its size; update the comment.
* include/private/gc_priv.h [E2K] (PROCEDURE_STACK_ALLOCA_AND_STORE):
Define macro.
* include/private/gc_priv.h [E2K && THREADS]
(GC_alloc_and_get_procedure_stack): New function declaration.
* include/private/pthread_support.h [E2K || IA64]
(GC_Thread_Rep.backing_store_end): Add comment.
* mach_dep.c [E2K] (GC_get_procedure_stack): Change the implementation
to according to the updated declaration (do allocate the buffer
internally); remove FIXME.
* mach_dep.c [E2K && THREADS] (GC_alloc_and_get_procedure_stack):
Implement.
* mark_rts.c [!THREADS] (GC_push_current_stack): Use
PROCEDURE_STACK_ALLOCA_AND_STORE() instead of GC_get_procedure_stack();
do no call free().
* pthread_stop_world.c [!GC_OPENBSD_UTHREADS && !NACL && E2K]
(GC_push_all_stacks): Likewise.
* pthread_stop_world.c [!GC_OPENBSD_UTHREADS && !NACL && E2K]
(GC_store_stack_ptr): Do not declare bs_lo and stack_size local
variables; do not call GC_get_procedure_stack().
* pthread_stop_world.c [!GC_OPENBSD_UTHREADS && !NACL && E2K]
(GC_suspend_handler_inner): Declare bs_lo and stack_size local
variables; call PROCEDURE_STACK_ALLOCA_AND_STORE(); set
backing_store_end and backing_store_ptr fields of me (and clear these
fields before function return); do not call free().
* pthread_stop_world.c [!GC_OPENBSD_UTHREADS && !NACL && E2K]
(GC_push_all_stacks): Define is_stopped local variable; move
stack_size local variable declaration to the innermost scope (where
it is used); do not call GC_push_all_register_sections() if the
procedure stack buffer has been already freed.
* pthread_support.c (first_thread): Update comment; move upper to be
before GC_push_thread_structures.
* pthread_support.c [E2K] (GC_push_thread_structures): Push also
first_thread.backing_store_end.
* pthread_support.c [E2K] (GC_do_blocking_inner,
GC_call_with_gc_active): Do no declare bs_lo local variable; call
GC_alloc_and_get_procedure_stack (holding the lock) instead of
GC_get_procedure_stack; call GC_INTERNAL_FREE() instead of free();
update comment.
Diffstat (limited to 'mach_dep.c')
-rw-r--r-- | mach_dep.c | 67 |
1 files changed, 41 insertions, 26 deletions
@@ -66,43 +66,36 @@ >> (63-E2K_PSHTP_SIZE)); \ } while (0) - GC_INNER size_t GC_get_procedure_stack(ptr_t *buf_ptr) { + GC_INNER size_t GC_get_procedure_stack(ptr_t buf, size_t buf_sz) { word ps; - ptr_t buf = NULL; - word buf_sz = 0; word new_sz = 0; - get_stack_index(&ps); + GC_ASSERT(0 == buf_sz || buf != NULL); for (;;) { - int res = syscall(__NR_access_hw_stacks, E2K_READ_PROCEDURE_STACK, - &ps, buf, buf_sz, &new_sz); - - if (res != -1) break; - if (ENOMEM == errno && buf_sz != new_sz) { - /* FIXME: use GC_scratch_alloc to support malloc redirection? */ - free(buf); - buf = malloc((size_t)new_sz); - if (NULL == buf) - ABORT_ARG1("Could not allocate memory for procedure stack", - ", %lu bytes requested", (unsigned long)new_sz); - if (0 == buf_sz) { - buf_sz = new_sz; - continue; /* skip get_stack_index() once */ - } - buf_sz = new_sz; + get_stack_index(&ps); + if (syscall(__NR_access_hw_stacks, E2K_READ_PROCEDURE_STACK, + &ps, buf, buf_sz, &new_sz) != -1) + break; + + if (ENOMEM == errno && (word)buf_sz < new_sz) { +# ifdef LOG_E2K_ALLOCS + if (buf_sz > 0) /* probably may happen */ + GC_log_printf("GC_get_procedure_stack():" + " buffer size/requested %lu/%lu bytes, GC #%lu\n", + (unsigned long)buf_sz, (unsigned long)new_sz, + (unsigned long)GC_gc_no); +# endif + return (size_t)new_sz; /* buffer not enough */ } else if (errno != EAGAIN) { ABORT_ARG1("Cannot read procedure stack", ": errno= %d", errno); } - get_stack_index(&ps); } - if (buf_sz != new_sz) - ABORT_ARG2("Buffer size mismatch while reading procedure stack", + if ((word)buf_sz < new_sz) + ABORT_ARG2("Buffer overflow while reading procedure stack", ": buf_sz= %lu, new_sz= %lu", (unsigned long)buf_sz, (unsigned long)new_sz); - GC_ASSERT(buf != NULL); - *buf_ptr = buf; - return (size_t)buf_sz; + return (size_t)new_sz; } ptr_t GC_save_regs_in_stack(void) { @@ -110,6 +103,28 @@ return NULL; } +# ifdef THREADS + GC_INNER size_t GC_alloc_and_get_procedure_stack(ptr_t *pbuf) + { + ptr_t buf = NULL; + size_t new_sz, buf_sz; + + GC_ASSERT(I_HOLD_LOCK()); + for (buf_sz = 0; ; buf_sz = new_sz) { + new_sz = GC_get_procedure_stack(buf, buf_sz); + if (new_sz <= buf_sz) break; + + if (EXPECT(buf != NULL, FALSE)) + GC_INTERNAL_FREE(buf); + buf = (ptr_t)GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(new_sz, PTRFREE); + if (NULL == buf) + ABORT("Could not allocate memory for procedure stack"); + } + *pbuf = buf; + return new_sz; + } +# endif /* THREADS */ + # undef VLIW_CMD_BRACES_PREFIX # undef get_stack_index #endif /* E2K */ |