summaryrefslogtreecommitdiff
path: root/mach_dep.c
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2022-01-30 23:34:49 +0300
committerIvan Maidanski <ivmai@mail.ru>2022-02-01 12:10:15 +0300
commit990dcdba1f1fc89cd3903bec3c6dda2fc8b3cc9f (patch)
treeee6f87a8ec58f162bd3c9474c53d101fc6ca99ab /mach_dep.c
parent5e576c0b5373b2af633629e509d81001e420e8fb (diff)
downloadbdwgc-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.c67
1 files changed, 41 insertions, 26 deletions
diff --git a/mach_dep.c b/mach_dep.c
index 6a4db79a..28e44867 100644
--- a/mach_dep.c
+++ b/mach_dep.c
@@ -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 */