1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.security.ReturnPtrRange -analyzer-output text -verify %s
2
3 int conjure_index();
4
5 namespace test_element_index_lifetime {
6
7 int arr[10]; // expected-note{{Original object declared here}} expected-note{{Original object declared here}}
8 int *ptr;
9
test_global_ptr()10 int *test_global_ptr() {
11 do { // expected-note{{Loop condition is false. Exiting loop}}
12 int x = conjure_index();
13 ptr = arr + x; // expected-note{{Value assigned to 'ptr'}}
14 if (x != 20) // expected-note{{Assuming 'x' is equal to 20}}
15 // expected-note@-1{{Taking false branch}}
16 return arr; // no-warning
17 } while(0);
18 return ptr; // expected-warning{{Returned pointer value points outside the original object (potential buffer overflow) [alpha.security.ReturnPtrRange]}}
19 // expected-note@-1{{Returned pointer value points outside the original object (potential buffer overflow)}}
20 // expected-note@-2{{Original object 'arr' is an array of 10 'int' objects}}
21 }
22
test_local_ptr()23 int *test_local_ptr() {
24 int *local_ptr;
25 do { // expected-note{{Loop condition is false. Exiting loop}}
26 int x = conjure_index();
27 local_ptr = arr + x; // expected-note{{Value assigned to 'local_ptr'}}
28 if (x != 20) // expected-note{{Assuming 'x' is equal to 20}}
29 // expected-note@-1{{Taking false branch}}
30 return arr; // no-warning
31 } while(0);
32 return local_ptr; // expected-warning{{Returned pointer value points outside the original object (potential buffer overflow) [alpha.security.ReturnPtrRange]}}
33 // expected-note@-1{{Returned pointer value points outside the original object (potential buffer overflow)}}
34 // expected-note@-2{{Original object 'arr' is an array of 10 'int' objects}}
35 }
36
37 }
38
39 template <typename T, int N>
end(T (& arr)[N])40 T* end(T (&arr)[N]) {
41 return arr + N; // no-warning, because we want to avoid false positives on returning the end() iterator of a container.
42 }
43
get_end_of_array()44 void get_end_of_array() {
45 static int arr[10];
46 end(arr);
47 }
48
49 template <int N>
50 class Iterable {
51 int buffer[N];
52 int *start, *finish;
53
54 public:
Iterable()55 Iterable() : start(buffer), finish(buffer + N) {}
56
begin()57 int* begin() { return start; }
end()58 int* end() { return finish; }
59 };
60
use_iterable_object()61 void use_iterable_object() {
62 Iterable<20> iter;
63 iter.end();
64 }
65
66 template <int N>
67 class BadIterable {
68 int buffer[N]; // expected-note{{Original object declared here}}
69 int *start, *finish;
70
71 public:
BadIterable()72 BadIterable() : start(buffer), finish(buffer + N) {} // expected-note{{Value assigned to 'iter.finish'}}
73
begin()74 int* begin() { return start; }
end()75 int* end() { return finish + 1; } // expected-warning{{Returned pointer value points outside the original object}}
76 // expected-note@-1{{Returned pointer value points outside the original object}}
77 // expected-note@-2{{Original object 'buffer' is an array of 20 'int' objects, returned pointer points at index 21}}
78 };
79
use_bad_iterable_object()80 void use_bad_iterable_object() {
81 BadIterable<20> iter; // expected-note{{Calling default constructor for 'BadIterable<20>'}}
82 // expected-note@-1{{Returning from default constructor for 'BadIterable<20>'}}
83 iter.end(); // expected-note{{Calling 'BadIterable::end'}}
84 }
85
test_idx_sym(int I)86 int *test_idx_sym(int I) {
87 static int arr[10]; // expected-note{{Original object declared here}} expected-note{{'arr' initialized here}}
88
89 if (I != 11) // expected-note{{Assuming 'I' is equal to 11}}
90 // expected-note@-1{{Taking false branch}}
91 return arr;
92 return arr + I; // expected-warning{{Returned pointer value points outside the original object}}
93 // expected-note@-1{{Returned pointer value points outside the original object}}
94 // expected-note@-2{{Original object 'arr' is an array of 10 'int' objects, returned pointer points at index 11}}
95 }
96
97 namespace test_array_of_struct {
98
99 struct Data {
100 int A;
101 char *B;
102 };
103
104 Data DataArr[10]; // expected-note{{Original object declared here}}
105
test_struct_array()106 Data *test_struct_array() {
107 int I = conjure_index();
108 if (I != 11) // expected-note{{Assuming 'I' is equal to 11}}
109 // expected-note@-1{{Taking false branch}}
110 return DataArr;
111 return DataArr + I; // expected-warning{{Returned pointer value points outside the original object}}
112 // expected-note@-1{{Returned pointer value points outside the original object}}
113 // expected-note@-2{{Original object 'DataArr' is an array of 10 'test_array_of_struct::Data' objects, returned pointer points at index 11}}
114 }
115
116 }
117
118 namespace std {
119 // A builtin function with the body generated on the fly.
120 template <typename T> T&& move(T &&) noexcept;
121 } // namespace std
122
123 char buf[2];
124
top()125 void top() {
126 // see https://github.com/llvm/llvm-project/issues/55347
127 (void)std::move(*(buf + 3)); // no-crash
128 }
129