reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s -analyzer-config eagerly-assume=false

// Tests for c11 atomics. Many of these tests currently yield unknown
// because we don't fully model the atomics and instead imprecisely
// treat their arguments as escaping.

typedef unsigned int uint32_t;
typedef enum memory_order {
  memory_order_relaxed = __ATOMIC_RELAXED,
  memory_order_consume = __ATOMIC_CONSUME,
  memory_order_acquire = __ATOMIC_ACQUIRE,
  memory_order_release = __ATOMIC_RELEASE,
  memory_order_acq_rel = __ATOMIC_ACQ_REL,
  memory_order_seq_cst = __ATOMIC_SEQ_CST
} memory_order;

void clang_analyzer_eval(int);

struct RefCountedStruct {
  uint32_t refCount;
  void *ptr;
};

void test_atomic_fetch_add(struct RefCountedStruct *s) {
  s->refCount = 1;

  uint32_t result = __c11_atomic_fetch_add((volatile _Atomic(uint32_t) *)&s->refCount,- 1, memory_order_relaxed);

  // When we model atomics fully this should (probably) be FALSE. It should never
  // be TRUE (because the operation mutates the passed in storage).
  clang_analyzer_eval(s->refCount == 1); // expected-warning {{UNKNOWN}}

  // When fully modeled this should be TRUE
  clang_analyzer_eval(result == 1); // expected-warning {{UNKNOWN}}
}

void test_atomic_load(struct RefCountedStruct *s) {
  s->refCount = 1;

  uint32_t result = __c11_atomic_load((volatile _Atomic(uint32_t) *)&s->refCount, memory_order_relaxed);

  // When we model atomics fully this should (probably) be TRUE.
  clang_analyzer_eval(s->refCount == 1); // expected-warning {{UNKNOWN}}

  // When fully modeled this should be TRUE
  clang_analyzer_eval(result == 1); // expected-warning {{UNKNOWN}}
}

void test_atomic_store(struct RefCountedStruct *s) {
  s->refCount = 1;

  __c11_atomic_store((volatile _Atomic(uint32_t) *)&s->refCount, 2, memory_order_relaxed);

  // When we model atomics fully this should (probably) be FALSE. It should never
  // be TRUE (because the operation mutates the passed in storage).
  clang_analyzer_eval(s->refCount == 1); // expected-warning {{UNKNOWN}}
}

void test_atomic_exchange(struct RefCountedStruct *s) {
  s->refCount = 1;

  uint32_t result = __c11_atomic_exchange((volatile _Atomic(uint32_t) *)&s->refCount, 2, memory_order_relaxed);

  // When we model atomics fully this should (probably) be FALSE. It should never
  // be TRUE (because the operation mutates the passed in storage).
  clang_analyzer_eval(s->refCount == 1); // expected-warning {{UNKNOWN}}

  // When fully modeled this should be TRUE
  clang_analyzer_eval(result == 1); // expected-warning {{UNKNOWN}}
}


void test_atomic_compare_exchange_strong(struct RefCountedStruct *s) {
  s->refCount = 1;
  uint32_t expected = 2;
  uint32_t desired = 3;
  _Bool result = __c11_atomic_compare_exchange_strong((volatile _Atomic(uint32_t) *)&s->refCount, &expected, desired, memory_order_relaxed, memory_order_relaxed);

  // For now we expect both expected and refCount to be invalidated by the
  // call. In the future we should model more precisely.
  clang_analyzer_eval(s->refCount == 3); // expected-warning {{UNKNOWN}}
  clang_analyzer_eval(expected == 2); // expected-warning {{UNKNOWN}}
}

void test_atomic_compare_exchange_weak(struct RefCountedStruct *s) {
  s->refCount = 1;
  uint32_t expected = 2;
  uint32_t desired = 3;
  _Bool result = __c11_atomic_compare_exchange_weak((volatile _Atomic(uint32_t) *)&s->refCount, &expected, desired, memory_order_relaxed, memory_order_relaxed);

  // For now we expect both expected and refCount to be invalidated by the
  // call. In the future we should model more precisely.
  clang_analyzer_eval(s->refCount == 3); // expected-warning {{UNKNOWN}}
  clang_analyzer_eval(expected == 2); // expected-warning {{UNKNOWN}}
}