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