xref: /llvm-project/clang/test/Analysis/out-of-bounds.c (revision fa8a21144ec9a6836e9bf1e3bf5cd0b2f058209e)
1 // RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-checker=core,alpha.security.ArrayBoundV2,debug.ExprInspection -verify %s
2 
3 void clang_analyzer_eval(int);
4 
5 // Tests doing an out-of-bounds access after the end of an array using:
6 // - constant integer index
7 // - constant integer size for buffer
test1(int x)8 void test1(int x) {
9   int buf[100];
10   buf[100] = 1; // expected-warning{{Out of bound access to memory}}
11 }
12 
test1_ok(int x)13 void test1_ok(int x) {
14   int buf[100];
15   buf[99] = 1; // no-warning
16 }
17 
test1_strings_underrun(int x)18 const char test1_strings_underrun(int x) {
19   const char *mystr = "mary had a little lamb";
20   return mystr[-1]; // expected-warning{{Out of bound access to memory}}
21 }
22 
test1_strings_overrun(int x)23 const char test1_strings_overrun(int x) {
24   const char *mystr = "mary had a little lamb";
25   return mystr[1000];  // expected-warning{{Out of bound access to memory}}
26 }
27 
test1_strings_ok(int x)28 const char test1_strings_ok(int x) {
29   const char *mystr = "mary had a little lamb";
30   return mystr[5]; // no-warning
31 }
32 
33 // Tests doing an out-of-bounds access after the end of an array using:
34 // - indirect pointer to buffer
35 // - constant integer index
36 // - constant integer size for buffer
test1_ptr(int x)37 void test1_ptr(int x) {
38   int buf[100];
39   int *p = buf;
40   p[101] = 1; // expected-warning{{Out of bound access to memory}}
41 }
42 
test1_ptr_ok(int x)43 void test1_ptr_ok(int x) {
44   int buf[100];
45   int *p = buf;
46   p[99] = 1; // no-warning
47 }
48 
49 // Tests doing an out-of-bounds access before the start of an array using:
50 // - indirect pointer to buffer, manipulated using simple pointer arithmetic
51 // - constant integer index
52 // - constant integer size for buffer
test1_ptr_arith(int x)53 void test1_ptr_arith(int x) {
54   int buf[100];
55   int *p = buf;
56   p = p + 100;
57   p[0] = 1; // expected-warning{{Out of bound access to memory}}
58 }
59 
test1_ptr_arith_ok(int x)60 void test1_ptr_arith_ok(int x) {
61   int buf[100];
62   int *p = buf;
63   p = p + 99;
64   p[0] = 1; // no-warning
65 }
66 
test1_ptr_arith_bad(int x)67 void test1_ptr_arith_bad(int x) {
68   int buf[100];
69   int *p = buf;
70   p = p + 99;
71   p[1] = 1; // expected-warning{{Out of bound access to memory}}
72 }
73 
test1_ptr_arith_ok2(int x)74 void test1_ptr_arith_ok2(int x) {
75   int buf[100];
76   int *p = buf;
77   p = p + 99;
78   p[-1] = 1; // no-warning
79 }
80 
81 // Tests doing an out-of-bounds access before the start of an array using:
82 // - constant integer index
83 // - constant integer size for buffer
test2(int x)84 void test2(int x) {
85   int buf[100];
86   buf[-1] = 1; // expected-warning{{Out of bound access to memory}}
87 }
88 
89 // Tests doing an out-of-bounds access before the start of an array using:
90 // - indirect pointer to buffer
91 // - constant integer index
92 // - constant integer size for buffer
test2_ptr(int x)93 void test2_ptr(int x) {
94   int buf[100];
95   int *p = buf;
96   p[-1] = 1; // expected-warning{{Out of bound access to memory}}
97 }
98 
99 // Tests doing an out-of-bounds access before the start of an array using:
100 // - indirect pointer to buffer, manipulated using simple pointer arithmetic
101 // - constant integer index
102 // - constant integer size for buffer
test2_ptr_arith(int x)103 void test2_ptr_arith(int x) {
104   int buf[100];
105   int *p = buf;
106   --p;
107   p[0] = 1; // expected-warning {{Out of bound access to memory preceding}}
108 }
109 
110 // Tests doing an out-of-bounds access before the start of a multi-dimensional
111 // array using:
112 // - constant integer indices
113 // - constant integer sizes for the array
test2_multi(int x)114 void test2_multi(int x) {
115   int buf[100][100];
116   buf[0][-1] = 1; // expected-warning{{Out of bound access to memory}}
117 }
118 
119 // Tests doing an out-of-bounds access before the start of a multi-dimensional
120 // array using:
121 // - constant integer indices
122 // - constant integer sizes for the array
test2_multi_b(int x)123 void test2_multi_b(int x) {
124   int buf[100][100];
125   buf[-1][0] = 1; // expected-warning{{Out of bound access to memory}}
126 }
127 
test2_multi_ok(int x)128 void test2_multi_ok(int x) {
129   int buf[100][100];
130   buf[0][0] = 1; // no-warning
131 }
132 
test3(int x)133 void test3(int x) {
134   int buf[100];
135   if (x < 0)
136     buf[x] = 1; // expected-warning{{Out of bound access to memory}}
137 }
138 
test4(int x)139 void test4(int x) {
140   int buf[100];
141   if (x > 99)
142     buf[x] = 1; // expected-warning{{Out of bound access to memory}}
143 }
144 
test_assume_after_access(unsigned long x)145 void test_assume_after_access(unsigned long x) {
146   int buf[100];
147   buf[x] = 1;
148   clang_analyzer_eval(x <= 99); // expected-warning{{TRUE}}
149 }
150 
151 // Don't warn when indexing below the start of a symbolic region's whose
152 // base extent we don't know.
153 int *get_symbolic(void);
test_underflow_symbolic(void)154 void test_underflow_symbolic(void) {
155   int *buf = get_symbolic();
156   buf[-1] = 0; // no-warning;
157 }
158 
159 // But warn if we understand the internal memory layout of a symbolic region.
160 typedef struct {
161   int id;
162   char name[256];
163 } user_t;
164 
165 user_t *get_symbolic_user(void);
test_underflow_symbolic_2()166 char test_underflow_symbolic_2() {
167   user_t *user = get_symbolic_user();
168   return user->name[-1]; // expected-warning{{Out of bound access to memory}}
169 }
170 
test_incomplete_struct(void)171 void test_incomplete_struct(void) {
172   extern struct incomplete incomplete;
173   int *p = (int *)&incomplete;
174   p[1] = 42; // no-warning
175 }
176 
test_extern_void(void)177 void test_extern_void(void) {
178   extern void v;
179   int *p = (int *)&v;
180   p[1] = 42; // no-warning
181 }
182 
test_assume_after_access2(unsigned long x)183 void test_assume_after_access2(unsigned long x) {
184   char buf[100];
185   buf[x] = 1;
186   clang_analyzer_eval(x <= 99); // expected-warning{{TRUE}}
187 }
188 
189 struct incomplete;
test_comparison_with_extent_symbol(struct incomplete * p)190 char test_comparison_with_extent_symbol(struct incomplete *p) {
191   // Previously this was reported as a (false positive) overflow error because
192   // the extent symbol of the area pointed by `p` was an unsigned and the '-1'
193   // was converted to its type by `evalBinOpNN`.
194   return ((char *)p)[-1]; // no-warning
195 }
196 
197