1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s 2 3 // Tests for c11 atomics. Many of these tests currently yield unknown 4 // because we don't fully model the atomics and instead imprecisely 5 // treat their arguments as escaping. 6 7 typedef unsigned int uint32_t; 8 typedef enum memory_order { 9 memory_order_relaxed = __ATOMIC_RELAXED, 10 memory_order_consume = __ATOMIC_CONSUME, 11 memory_order_acquire = __ATOMIC_ACQUIRE, 12 memory_order_release = __ATOMIC_RELEASE, 13 memory_order_acq_rel = __ATOMIC_ACQ_REL, 14 memory_order_seq_cst = __ATOMIC_SEQ_CST 15 } memory_order; 16 17 void clang_analyzer_eval(int); 18 19 struct RefCountedStruct { 20 uint32_t refCount; 21 void *ptr; 22 }; 23 24 void test_atomic_fetch_add(struct RefCountedStruct *s) { 25 s->refCount = 1; 26 27 uint32_t result = __c11_atomic_fetch_add((volatile _Atomic(uint32_t) *)&s->refCount,- 1, memory_order_relaxed); 28 29 // When we model atomics fully this should (probably) be FALSE. It should never 30 // be TRUE (because the operation mutates the passed in storage). 31 clang_analyzer_eval(s->refCount == 1); // expected-warning {{UNKNOWN}} 32 33 // When fully modeled this should be TRUE 34 clang_analyzer_eval(result == 1); // expected-warning {{UNKNOWN}} 35 } 36 37 void test_atomic_load(struct RefCountedStruct *s) { 38 s->refCount = 1; 39 40 uint32_t result = __c11_atomic_load((volatile _Atomic(uint32_t) *)&s->refCount, memory_order_relaxed); 41 42 // When we model atomics fully this should (probably) be TRUE. 43 clang_analyzer_eval(s->refCount == 1); // expected-warning {{UNKNOWN}} 44 45 // When fully modeled this should be TRUE 46 clang_analyzer_eval(result == 1); // expected-warning {{UNKNOWN}} 47 } 48 49 void test_atomic_store(struct RefCountedStruct *s) { 50 s->refCount = 1; 51 52 __c11_atomic_store((volatile _Atomic(uint32_t) *)&s->refCount, 2, memory_order_relaxed); 53 54 // When we model atomics fully this should (probably) be FALSE. It should never 55 // be TRUE (because the operation mutates the passed in storage). 56 clang_analyzer_eval(s->refCount == 1); // expected-warning {{UNKNOWN}} 57 } 58 59 void test_atomic_exchange(struct RefCountedStruct *s) { 60 s->refCount = 1; 61 62 uint32_t result = __c11_atomic_exchange((volatile _Atomic(uint32_t) *)&s->refCount, 2, memory_order_relaxed); 63 64 // When we model atomics fully this should (probably) be FALSE. It should never 65 // be TRUE (because the operation mutates the passed in storage). 66 clang_analyzer_eval(s->refCount == 1); // expected-warning {{UNKNOWN}} 67 68 // When fully modeled this should be TRUE 69 clang_analyzer_eval(result == 1); // expected-warning {{UNKNOWN}} 70 } 71 72 73 void test_atomic_compare_exchange_strong(struct RefCountedStruct *s) { 74 s->refCount = 1; 75 uint32_t expected = 2; 76 uint32_t desired = 3; 77 _Bool result = __c11_atomic_compare_exchange_strong((volatile _Atomic(uint32_t) *)&s->refCount, &expected, desired, memory_order_relaxed, memory_order_relaxed); 78 79 // For now we expect both expected and refCount to be invalidated by the 80 // call. In the future we should model more precisely. 81 clang_analyzer_eval(s->refCount == 3); // expected-warning {{UNKNOWN}} 82 clang_analyzer_eval(expected == 2); // expected-warning {{UNKNOWN}} 83 } 84 85 void test_atomic_compare_exchange_weak(struct RefCountedStruct *s) { 86 s->refCount = 1; 87 uint32_t expected = 2; 88 uint32_t desired = 3; 89 _Bool result = __c11_atomic_compare_exchange_weak((volatile _Atomic(uint32_t) *)&s->refCount, &expected, desired, memory_order_relaxed, memory_order_relaxed); 90 91 // For now we expect both expected and refCount to be invalidated by the 92 // call. In the future we should model more precisely. 93 clang_analyzer_eval(s->refCount == 3); // expected-warning {{UNKNOWN}} 94 clang_analyzer_eval(expected == 2); // expected-warning {{UNKNOWN}} 95 } 96