[tsan] Fix the behavior of OSAtomicTestAndClear

The system implementation of OSAtomicTestAndClear returns the original bit, but the TSan interceptor has a bug which always returns zero from the function. This patch fixes this and adds a test.

Differential Revision: https://reviews.llvm.org/D23061

llvm-svn: 277461
This commit is contained in:
Kuba Brecka 2016-08-02 14:30:52 +00:00
parent 58f562887b
commit 3a748d6067
2 changed files with 43 additions and 10 deletions

View File

@ -119,24 +119,23 @@ OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwap32, __tsan_atomic32, a32,
OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwap64, __tsan_atomic64, a64,
int64_t)
#define OSATOMIC_INTERCEPTOR_BITOP(f, op, m, mo) \
#define OSATOMIC_INTERCEPTOR_BITOP(f, op, clear, mo) \
TSAN_INTERCEPTOR(bool, f, uint32_t n, volatile void *ptr) { \
SCOPED_TSAN_INTERCEPTOR(f, n, ptr); \
char *byte_ptr = ((char *)ptr) + (n >> 3); \
char bit_index = n & 7; \
char mask = m; \
char bit = 0x80u >> (n & 7); \
char mask = clear ? ~bit : bit; \
char orig_byte = op((a8 *)byte_ptr, mask, mo); \
return orig_byte & mask; \
return orig_byte & bit; \
}
#define OSATOMIC_INTERCEPTORS_BITOP(f, op, m) \
OSATOMIC_INTERCEPTOR_BITOP(f, op, m, kMacOrderNonBarrier) \
OSATOMIC_INTERCEPTOR_BITOP(f##Barrier, op, m, kMacOrderBarrier)
#define OSATOMIC_INTERCEPTORS_BITOP(f, op, clear) \
OSATOMIC_INTERCEPTOR_BITOP(f, op, clear, kMacOrderNonBarrier) \
OSATOMIC_INTERCEPTOR_BITOP(f##Barrier, op, clear, kMacOrderBarrier)
OSATOMIC_INTERCEPTORS_BITOP(OSAtomicTestAndSet, __tsan_atomic8_fetch_or,
0x80u >> bit_index)
OSATOMIC_INTERCEPTORS_BITOP(OSAtomicTestAndSet, __tsan_atomic8_fetch_or, false)
OSATOMIC_INTERCEPTORS_BITOP(OSAtomicTestAndClear, __tsan_atomic8_fetch_and,
~(0x80u >> bit_index))
true)
TSAN_INTERCEPTOR(void, OSAtomicEnqueue, OSQueueHead *list, void *item,
size_t offset) {

View File

@ -0,0 +1,34 @@
// RUN: %clangxx_tsan %s -o %t -framework Foundation -std=c++11
// RUN: %run %t 2>&1 | FileCheck %s
#import <Foundation/Foundation.h>
#import <libkern/OSAtomic.h>
int main(int argc, const char *argv[]) {
int value = 1;
bool ret = OSAtomicTestAndClear(7, &value);
fprintf(stderr, "value = %d, ret = %d\n", value, ret);
// CHECK: value = 0, ret = 1
ret = OSAtomicTestAndSet(4, &value);
fprintf(stderr, "value = %d, ret = %d\n", value, ret);
// CHECK: value = 8, ret = 0
ret = OSAtomicTestAndClear(4, &value);
fprintf(stderr, "value = %d, ret = %d\n", value, ret);
// CHECK: value = 0, ret = 1
ret = OSAtomicTestAndSet(12, &value);
fprintf(stderr, "value = %d, ret = %d\n", value, ret);
// CHECK: value = 2048, ret = 0
ret = OSAtomicTestAndSet(13, &value);
fprintf(stderr, "value = %d, ret = %d\n", value, ret);
// CHECK: value = 3072, ret = 0
ret = OSAtomicTestAndClear(12, &value);
fprintf(stderr, "value = %d, ret = %d\n", value, ret);
// CHECK: value = 1024, ret = 1
return 0;
}