[tsan]: Fix GNU version of strerror_r interceptor

GNU version of strerror_r returns a result pointer that doesn't match the input
buffer. The result pointer is in fact a pointer to some internal storage.
TSAN was recording a write to this location, which was incorrect.

Fixed https://github.com/google/sanitizers/issues/696

llvm-svn: 304858
This commit is contained in:
Vitaly Buka 2017-06-07 01:53:38 +00:00
parent 7945248267
commit d9bc851fb3
4 changed files with 51 additions and 1 deletions

View File

@ -3395,7 +3395,10 @@ INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
char *res = REAL(strerror_r)(errnum, buf, buflen);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
if (res == buf)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
else
COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
return res;
}
#endif //(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE ||

View File

@ -345,6 +345,7 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
StatInc(thr, StatMopRange);
if (*shadow_mem == kShadowRodata) {
DCHECK(!is_write);
// Access to .rodata section, no races here.
// Measurements show that it can be 10-20% of all memory accesses.
StatInc(thr, StatMopRangeRodata);

View File

@ -0,0 +1,18 @@
// RUN: %clang_msan -O0 -g %s -o %t && %run %t
#include <assert.h>
#include <errno.h>
#include <string.h>
int main() {
char buf[1000];
char *res = strerror_r(EINVAL, buf, sizeof(buf));
assert(res);
volatile int z = strlen(res);
res = strerror_r(-1, buf, sizeof(buf));
assert(res);
z = strlen(res);
return 0;
}

View File

@ -0,0 +1,28 @@
// RUN: %clangxx_tsan -O1 -DTEST_ERROR=ERANGE %s -o %t && %run %t 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-SYS %s
// RUN: %clangxx_tsan -O1 -DTEST_ERROR=-1 %s -o %t && not %run %t 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-USER %s
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
char buffer[1000];
void *Thread(void *p) {
return strerror_r(TEST_ERROR, buffer, sizeof(buffer));
}
int main() {
pthread_t th[2];
pthread_create(&th[0], 0, Thread, 0);
pthread_create(&th[1], 0, Thread, 0);
pthread_join(th[0], 0);
pthread_join(th[1], 0);
fprintf(stderr, "DONE\n");
}
// CHECK-USER: WARNING: ThreadSanitizer: data race
// CHECK-SYS-NOT: WARNING: ThreadSanitizer: data race
// CHECK: DONE