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
7typedef unsigned int uint32_t;
8typedef 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
17void clang_analyzer_eval(int);
18
19struct RefCountedStruct {
20  uint32_t refCount;
21  void *ptr;
22};
23
24void 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
37void 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
49void 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
59void 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
73void 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
85void 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