Clang Project

clang_source_code/test/Analysis/symbol-reaper.c
1// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -verify %s
2
3void clang_analyzer_eval(int);
4void clang_analyzer_warnOnDeadSymbol(int);
5void clang_analyzer_numTimesReached();
6void clang_analyzer_warnIfReached();
7
8void exit(int);
9
10int conjure_index();
11
12void test_that_expr_inspection_works() {
13  do {
14    int x = conjure_index();
15    clang_analyzer_warnOnDeadSymbol(x);
16  } while(0); // expected-warning{{SYMBOL DEAD}}
17
18  // Make sure we don't accidentally split state in ExprInspection.
19  clang_analyzer_numTimesReached(); // expected-warning{{1}}
20}
21
22// These tests verify the reaping of symbols that are only referenced as
23// index values in element regions. Most of the time, depending on where
24// the element region, as Loc value, is stored, it is possible to
25// recover the index symbol in checker code, which is also demonstrated
26// in the return_ptr_range.c test file.
27
28int arr[3];
29
30int *test_element_index_lifetime_in_environment_values() {
31  int *ptr;
32  do {
33    int x = conjure_index();
34    clang_analyzer_warnOnDeadSymbol(x);
35    ptr = arr + x;
36  } while (0);
37  return ptr;
38}
39
40void test_element_index_lifetime_in_store_keys() {
41  do {
42    int x = conjure_index();
43    clang_analyzer_warnOnDeadSymbol(x);
44    arr[x] = 1;
45    if (x) {}
46  } while (0); // no-warning
47}
48
49int *ptr;
50void test_element_index_lifetime_in_store_values() {
51  do {
52    int x = conjure_index();
53    clang_analyzer_warnOnDeadSymbol(x);
54    ptr = arr + x;
55  } while (0); // no-warning
56}
57
58struct S1 {
59  int field;
60};
61struct S2 {
62  struct S1 array[5];
63} s2;
64struct S3 {
65  void *field;
66};
67
68struct S1 *conjure_S1();
69struct S3 *conjure_S3();
70
71void test_element_index_lifetime_with_complicated_hierarchy_of_regions() {
72  do {
73    int x = conjure_index();
74    clang_analyzer_warnOnDeadSymbol(x);
75    s2.array[x].field = 1;
76    if (x) {}
77  } while (0); // no-warning
78}
79
80void test_loc_as_integer_element_index_lifetime() {
81  do {
82    int x;
83    struct S3 *s = conjure_S3();
84    clang_analyzer_warnOnDeadSymbol((int)s);
85    x = (int)&(s->field);
86    ptr = &arr[x];
87    if (s) {}
88  } while (0);
89}
90
91// Test below checks lifetime of SymbolRegionValue in certain conditions.
92
93int **ptrptr;
94void test_region_lifetime_as_store_value(int *x) {
95  clang_analyzer_warnOnDeadSymbol((int) x);
96  *x = 1;
97  ptrptr = &x;
98  (void)0; // No-op; make sure the environment forgets things and the GC runs.
99  clang_analyzer_eval(**ptrptr); // expected-warning{{TRUE}}
100} // no-warning
101
102int *produce_region_referenced_only_through_field_in_environment_value() {
103  struct S1 *s = conjure_S1();
104  clang_analyzer_warnOnDeadSymbol((int) s);
105  int *x = &s->field;
106  return x;
107}
108
109void test_region_referenced_only_through_field_in_environment_value() {
110  produce_region_referenced_only_through_field_in_environment_value();
111} // expected-warning{{SYMBOL DEAD}}
112
113void test_region_referenced_only_through_field_in_store_value() {
114  struct S1 *s = conjure_S1();
115  clang_analyzer_warnOnDeadSymbol((int) s);
116  ptr = &s->field; // Write the symbol into a global. It should live forever.
117  if (!s) {
118    exit(0); // no-warning (symbol should not die here)
119    // exit() is noreturn.
120    clang_analyzer_warnIfReached(); // no-warning
121  }
122  if (!ptr) { // no-warning (symbol should not die here)
123    // We exit()ed under these constraints earlier.
124    clang_analyzer_warnIfReached(); // no-warning
125  }
126  // The exit() call invalidates globals. The symbol will die here because
127  // the exit() statement itself is already over and there's no better statement
128  // to put the diagnostic on.
129} // expected-warning{{SYMBOL DEAD}}
130
131void test_zombie_referenced_only_through_field_in_store_value() {
132  struct S1 *s = conjure_S1();
133  clang_analyzer_warnOnDeadSymbol((int) s);
134  int *x = &s->field;
135} // expected-warning{{SYMBOL DEAD}}
136
137void double_dereference_of_implicit_value_aux1(int *p) {
138  *p = 0;
139}
140
141void double_dereference_of_implicit_value_aux2(int *p) {
142  if (*p != 0)
143    clang_analyzer_warnIfReached(); // no-warning
144}
145
146void test_double_dereference_of_implicit_value(int **x) {
147  clang_analyzer_warnOnDeadSymbol(**x);
148  int **y = x;
149  {
150    double_dereference_of_implicit_value_aux1(*y);
151    // Give time for symbol reaping to happen.
152    ((void)0);
153    // The symbol for **y was cleaned up from the Store at this point,
154    // even though it was not perceived as dead when asked explicitly.
155    // For that reason the SYMBOL DEAD warning never appeared at this point.
156    double_dereference_of_implicit_value_aux2(*y);
157  }
158  // The symbol is generally reaped here regardless.
159  ((void)0); // expected-warning{{SYMBOL DEAD}}
160}
161