| 1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s -analyzer-config eagerly-assume=false |
| 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 | |