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
test_atomic_fetch_add(struct RefCountedStruct * s)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
test_atomic_load(struct RefCountedStruct * s)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
test_atomic_store(struct RefCountedStruct * s)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
test_atomic_exchange(struct RefCountedStruct * s)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
test_atomic_compare_exchange_strong(struct RefCountedStruct * s)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
test_atomic_compare_exchange_weak(struct RefCountedStruct * s)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