|
| 1 | +// Test that dylibs interposing write, and then calling functions intercepted |
| 2 | +// by TSan don't deadlock (self-lock) |
| 3 | + |
| 4 | +// RUN: %clang_tsan %s -o %t |
| 5 | +// RUN: %clang_tsan %s -o %t.dylib -fno-sanitize=thread -dynamiclib -DSHARED_LIB |
| 6 | + |
| 7 | +// Note that running the below command with out `lock_during_write` should |
| 8 | +// deadlock (self-lock) |
| 9 | +// RUN: env DYLD_INSERT_LIBRARIES=%t.dylib TSAN_OPTIONS=verbosity=2:lock_during_write=disable_for_current_process %run %t 2>&1 | FileCheck %s |
| 10 | + |
| 11 | +#include <stdio.h> |
| 12 | + |
| 13 | +#if defined(SHARED_LIB) |
| 14 | + |
| 15 | +// dylib implementation - interposes write() calls |
| 16 | +# include <os/lock.h> |
| 17 | +# include <unistd.h> |
| 18 | + |
| 19 | +struct interpose_substitution { |
| 20 | + const void *replacement; |
| 21 | + const void *original; |
| 22 | +}; |
| 23 | + |
| 24 | +# define INTERPOSE(replacement, original) \ |
| 25 | + __attribute__((used)) static const struct interpose_substitution \ |
| 26 | + substitution_##original[] \ |
| 27 | + __attribute__((section("__DATA, __interpose"))) = { \ |
| 28 | + {(const void *)(replacement), (const void *)(original)}} |
| 29 | + |
| 30 | +static ssize_t my_write(int fd, const void *buf, size_t count) { |
| 31 | + struct os_unfair_lock_s lock = OS_UNFAIR_LOCK_INIT; |
| 32 | + os_unfair_lock_lock(&lock); |
| 33 | + printf("Interposed write called: fd=%d, count=%zu\n", fd, count); |
| 34 | + ssize_t res = write(fd, buf, count); |
| 35 | + os_unfair_lock_unlock(&lock); |
| 36 | + return res; |
| 37 | +} |
| 38 | +INTERPOSE(my_write, write); |
| 39 | + |
| 40 | +#else // defined(SHARED_LIB) |
| 41 | + |
| 42 | +int main() { |
| 43 | + printf("Write test completed\n"); |
| 44 | + return 0; |
| 45 | +} |
| 46 | + |
| 47 | +#endif // defined(SHARED_LIB) |
| 48 | + |
| 49 | +// CHECK: Interposed write called: fd={{[0-9]+}}, count={{[0-9]+}} |
| 50 | +// CHECK: Write test completed |
0 commit comments