1 // RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -Wno-pointer-to-int-cast -verify %s
2 
3 void clang_analyzer_eval(int);
4 void clang_analyzer_warnOnDeadSymbol(int);
5 void clang_analyzer_numTimesReached();
6 void clang_analyzer_warnIfReached();
7 
8 void exit(int);
9 
10 int conjure_index();
11 
test_that_expr_inspection_works()12 void 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 
28 int arr[3];
29 
test_element_index_lifetime_in_environment_values()30 int *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 
test_element_index_lifetime_in_store_keys()40 void 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 
49 int *ptr;
test_element_index_lifetime_in_store_values()50 void 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 
58 struct S1 {
59   int field;
60 };
61 struct S2 {
62   struct S1 array[5];
63 } s2;
64 struct S3 {
65   void *field;
66 };
67 
68 struct S1 *conjure_S1();
69 struct S3 *conjure_S3();
70 
test_element_index_lifetime_with_complicated_hierarchy_of_regions()71 void 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 
test_loc_as_integer_element_index_lifetime()80 void 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 
93 int **ptrptr;
test_region_lifetime_as_store_value(int * x)94 void 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 
produce_region_referenced_only_through_field_in_environment_value()102 int *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 
test_region_referenced_only_through_field_in_environment_value()109 void 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 
test_region_referenced_only_through_field_in_store_value()113 void 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 
test_zombie_referenced_only_through_field_in_store_value()131 void 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 
double_dereference_of_implicit_value_aux1(int * p)137 void double_dereference_of_implicit_value_aux1(int *p) {
138   *p = 0;
139 }
140 
double_dereference_of_implicit_value_aux2(int * p)141 void double_dereference_of_implicit_value_aux2(int *p) {
142   if (*p != 0)
143     clang_analyzer_warnIfReached(); // no-warning
144 }
145 
test_double_dereference_of_implicit_value(int ** x)146 void 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