diff options
4 files changed, 61 insertions, 7 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 7092aaa9d1b..4e653fa266d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -5114,21 +5114,26 @@ INTERCEPTOR(__sanitizer_FILE *, fopencookie, void *cookie, const char *mode, #endif // SANITIZER_INTERCEPT_FOPENCOOKIE #if SANITIZER_INTERCEPT_SEM -INTERCEPTOR(int, sem_init, void *s, int pshared, unsigned value) { +INTERCEPTOR(int, sem_init, __sanitizer_sem_t *s, int pshared, unsigned value) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sem_init, s, pshared, value); + // Workaround a bug in glibc's "old" semaphore implementation by + // zero-initializing the sem_t contents. This has to be done here because + // interceptors bind to the lowest symbols version by default, hitting the + // buggy code path while the non-sanitized build of the same code works fine. + REAL(memset)(s, 0, sizeof(*s)); int res = REAL(sem_init)(s, pshared, value); return res; } -INTERCEPTOR(int, sem_destroy, void *s) { +INTERCEPTOR(int, sem_destroy, __sanitizer_sem_t *s) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sem_destroy, s); int res = REAL(sem_destroy)(s); return res; } -INTERCEPTOR(int, sem_wait, void *s) { +INTERCEPTOR(int, sem_wait, __sanitizer_sem_t *s) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sem_wait, s); int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_wait)(s); @@ -5138,7 +5143,7 @@ INTERCEPTOR(int, sem_wait, void *s) { return res; } -INTERCEPTOR(int, sem_trywait, void *s) { +INTERCEPTOR(int, sem_trywait, __sanitizer_sem_t *s) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sem_trywait, s); int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_trywait)(s); @@ -5148,7 +5153,7 @@ INTERCEPTOR(int, sem_trywait, void *s) { return res; } -INTERCEPTOR(int, sem_timedwait, void *s, void *abstime) { +INTERCEPTOR(int, sem_timedwait, __sanitizer_sem_t *s, void *abstime) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sem_timedwait, s, abstime); COMMON_INTERCEPTOR_READ_RANGE(ctx, abstime, struct_timespec_sz); @@ -5159,7 +5164,7 @@ INTERCEPTOR(int, sem_timedwait, void *s, void *abstime) { return res; } -INTERCEPTOR(int, sem_post, void *s) { +INTERCEPTOR(int, sem_post, __sanitizer_sem_t *s) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sem_post, s); COMMON_INTERCEPTOR_RELEASE(ctx, (uptr)s); @@ -5167,7 +5172,7 @@ INTERCEPTOR(int, sem_post, void *s) { return res; } -INTERCEPTOR(int, sem_getvalue, void *s, int *sval) { +INTERCEPTOR(int, sem_getvalue, __sanitizer_sem_t *s, int *sval) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sem_getvalue, s, sval); int res = REAL(sem_getvalue)(s, sval); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc index 5f98099d1ce..9cfaec5cc8e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -122,6 +122,7 @@ # if defined(__mips64) || defined(__aarch64__) # include <asm/ptrace.h> # endif +# include <semaphore.h> #endif #if !SANITIZER_ANDROID @@ -1241,4 +1242,8 @@ CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek); CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close); #endif +#if SANITIZER_LINUX || SANITIZER_FREEBSD +CHECK_TYPE_SIZE(sem_t); +#endif + #endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index a2d01e2f6f2..c598fe0d716 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -150,6 +150,18 @@ namespace __sanitizer { }; const unsigned old_sigset_t_sz = sizeof(unsigned long); + + struct __sanitizer_sem_t { +#if SANITIZER_ANDROID && defined(_LP64) + int data[4]; +#elif SANITIZER_ANDROID && !defined(_LP64) + int data; +#elif SANITIZER_LINUX + uptr data[4]; +#elif SANITIZER_FREEBSD + u32 data[4]; +#endif + }; #endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if SANITIZER_ANDROID diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc b/compiler-rt/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc new file mode 100644 index 00000000000..f17453b2d51 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/sem_init_glibc.cc @@ -0,0 +1,32 @@ +// RUN: %clangxx -O0 -g %s -lutil -o %t && %run %t +// This test depends on the glibc layout of struct sem_t and checks that we +// don't leave sem_t::private uninitialized. +// UNSUPPORTED: android +#include <assert.h> +#include <semaphore.h> +#include <string.h> + +void my_sem_init(bool priv, int value, unsigned *a, unsigned char *b) { + sem_t sem; + memset(&sem, 0xAB, sizeof(sem)); + sem_init(&sem, priv, value); + + char *p = (char *)&sem; + memcpy(a, p, sizeof(unsigned)); + memcpy(b, p + sizeof(unsigned), sizeof(char)); + + sem_destroy(&sem); +} + +int main() { + unsigned a; + unsigned char b; + + my_sem_init(false, 42, &a, &b); + assert(a == 42); + assert(b != 0xAB); + + my_sem_init(true, 43, &a, &b); + assert(a == 43); + assert(b != 0xAB); +} |