xref: /llvm-project/clang/test/Analysis/return-ptr-range.cpp (revision 98d55095d85129c2776a9d7a227c5f88e3ce2e01)
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