From 675a3022f75e5b1323769b3982244af93a8f1866 Mon Sep 17 00:00:00 2001 From: KennyTM~ Date: Tue, 26 Jul 2011 18:38:06 +0800 Subject: [PATCH 1/2] Fixes bug 6376: core.thread.thread_scanAll doesn't scan the stack due to ASLR on Mac OS X 10.7 When ASLR is enabled, the stack address of Mac OS X is no longer fixed at 0xc000_0000 -- actually, often higher than this. Previously, the function rt.memory.rt_stackBottom returns a hard-coded value of 0xc000_0000, which is no longer valid with ASLR. Functions which rely on this function could no longer work properly. In particular, core.thread.thread_scanAll cannot scan the main thread's stack since the stack pointer bounds are reversed. The GC, which marks whether pointers shouldn't be freed yet, will miss all the objects on stack as thread_scanAll is used. This causes pre-mature deallocation when a GC collection is invoked. In particular, when throwing an exception (the pointer is on stack), the TraceInfo allocated is > 2 KiB, which will cause a page allocation that invokes the GC. This makes the exception object be destroyed before checking its type, making it totally uncatchable and ignored, thus previously unreachable statements after the 'throw' will now be reachable, and other undefined behavior will arise. --- src/rt/memory.d | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/rt/memory.d b/src/rt/memory.d index 67bd5e977a1..3afd4eda822 100644 --- a/src/rt/memory.d +++ b/src/rt/memory.d @@ -42,6 +42,11 @@ private extern (C) extern __gshared void* __libc_stack_end; } } + version( OSX ) + { + import core.sys.posix.pthread; + extern(C) void* pthread_get_stackaddr_np(pthread_t thread); + } extern (C) void gc_addRange( void* p, size_t sz ); extern (C) void gc_removeRange( void* p ); } @@ -100,7 +105,7 @@ extern (C) void* rt_stackBottom() } else version( OSX ) { - return cast(void*) 0xc0000000; + return pthread_get_stackaddr_np(pthread_self()); } else version( FreeBSD ) { From f58ea3b90584a1effe22e9190a5dfbf068e4d2c2 Mon Sep 17 00:00:00 2001 From: KennyTM~ Date: Wed, 27 Jul 2011 14:39:26 +0800 Subject: [PATCH 2/2] OS X pthread additions. --- src/core/sys/posix/pthread.d | 81 ++++++++++++++++++++++++++++++++++++ src/rt/memory.d | 1 - 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/core/sys/posix/pthread.d b/src/core/sys/posix/pthread.d index d66d3147454..7c5de5f7030 100644 --- a/src/core/sys/posix/pthread.d +++ b/src/core/sys/posix/pthread.d @@ -563,6 +563,22 @@ int pthread_mutexattr_getprotocol(in pthread_mutexattr_t*, int*); (TPI|TPP) int pthread_mutexattr_setprioceiling(pthread_mutexattr_t*, int); (TPP) int pthread_mutexattr_setprotocol(pthread_mutexattr_t*, int); (TPI|TPP) */ +version( OSX ) +{ + enum + { + PTHREAD_PRIO_NONE, + PTHREAD_PRIO_INHERIT, + PTHREAD_PRIO_PROTECT + } + + int pthread_mutex_getprioceiling(in pthread_mutex_t*, int*); + int pthread_mutex_setprioceiling(pthread_mutex_t*, int, int*); + int pthread_mutexattr_getprioceiling(in pthread_mutexattr_t*, int*); + int pthread_mutexattr_getprotocol(in pthread_mutexattr_t*, int*); + int pthread_mutexattr_setprioceiling(pthread_mutexattr_t*, int); + int pthread_mutexattr_setprotocol(pthread_mutexattr_t*, int); +} // // Scheduling (TPS) @@ -697,4 +713,69 @@ version( FreeBSD ) int pthread_rwlockattr_getpshared(in pthread_rwlockattr_t*, int*); int pthread_rwlockattr_setpshared(pthread_rwlockattr_t*, int); } +else version( OSX ) +{ + int pthread_condattr_getpshared(in pthread_condattr_t*, int*); + int pthread_condattr_setpshared(pthread_condattr_t*, int); + int pthread_mutexattr_getpshared(in pthread_mutexattr_t*, int*); + int pthread_mutexattr_setpshared(pthread_mutexattr_t*, int); + int pthread_rwlockattr_getpshared(in pthread_rwlockattr_t*, int*); + int pthread_rwlockattr_setpshared(pthread_rwlockattr_t*, int); +} + +// +// Non-POSIX OS-Specific Additions +// + +version( OSX ) +{ + import core.sys.osx.mach.port; + + // returns non-zero if pthread_create or cthread_fork have been called + int pthread_is_threaded_np(); + + int pthread_threadid_np(pthread_t, ulong*); + // ^ __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2) + + int pthread_rwlock_longrdlock_np(pthread_rwlock_t*); + int pthread_rwlock_yieldwrlock_np(pthread_rwlock_t*); + // ^ __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + int pthread_rwlock_downgrade_np(pthread_rwlock_t*); + int pthread_rwlock_upgrade_np(pthread_rwlock_t*); + int pthread_rwlock_tryupgrade_np(pthread_rwlock_t*); + int pthread_rwlock_held_np(pthread_rwlock_t*); + int pthread_rwlock_rdheld_np(pthread_rwlock_t*); + int pthread_rwlock_wrheld_np(pthread_rwlock_t*); + + // SPI to set and get pthread name + int pthread_getname_np(pthread_t, char*, size_t); + int pthread_setname_np(in char*); + // ^ __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2) + + // returns non-zero if the current thread is the main thread + int pthread_main_np(); + + // return the mach thread bound to the pthread + mach_port_t pthread_mach_thread_np(pthread_t); + size_t pthread_get_stacksize_np(pthread_t); + void* pthread_get_stackaddr_np(pthread_t); + + // Like pthread_cond_signal(), but only wake up the specified pthread + int pthread_cond_signal_thread_np(pthread_cond_t*, pthread_t); + + // Like pthread_cond_timedwait, but use a relative timeout + int pthread_cond_timedwait_relative_np(pthread_cond_t*, pthread_mutex_t*, in timespec*); + + // Like pthread_create(), but leaves the thread suspended + int pthread_create_suspended_np(pthread_t*, in pthread_attr_t*, void* function(void*), void*); + int pthread_kill(pthread_t, int); + + pthread_t pthread_from_mach_thread_np(mach_port_t); + // ^ __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0) + + int pthread_sigmask(int, in sigset_t*, sigset_t*); + // ^ __DARWIN_ALIAS(pthread_sigmask) + + void pthread_yield_np(); +} diff --git a/src/rt/memory.d b/src/rt/memory.d index 3afd4eda822..def424a1d03 100644 --- a/src/rt/memory.d +++ b/src/rt/memory.d @@ -45,7 +45,6 @@ private version( OSX ) { import core.sys.posix.pthread; - extern(C) void* pthread_get_stackaddr_np(pthread_t thread); } extern (C) void gc_addRange( void* p, size_t sz ); extern (C) void gc_removeRange( void* p );