xref: /llvm-project/clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp (revision 78606af606deca9dd4de2ac1aec17a966c114bc2)
1 // RUN: %clang_cc1 -std=c++20  -Wno-all -Wunsafe-buffer-usage -Wno-unsafe-buffer-usage-in-container\
2 // RUN:            -fsafe-buffer-usage-suggestions \
3 // RUN:            -fblocks -include %s -verify %s
4 
5 // RUN: %clang -x c++ -frtti -fsyntax-only -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s
6 // RUN: %clang_cc1 -std=c++11 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s
7 // RUN: %clang_cc1 -std=c++20 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s
8 // CHECK-NOT: [-Wunsafe-buffer-usage]
9 
10 #ifndef INCLUDED
11 #define INCLUDED
12 #pragma clang system_header
13 
14 // no spanification warnings for system headers
15 #else
16 
17 typedef __INTPTR_TYPE__ intptr_t;
18 
19 namespace std {
20   class type_info;
21   class bad_cast;
22   class bad_typeid;
23 }
24 using size_t = __typeof(sizeof(int));
25 void *malloc(size_t);
26 
27 void foo(int v) {
28 }
29 
30 void foo(int *p){}
31 
32 namespace std{
33   template <typename T> class span {
34 
35    T *elements;
36 
37    span(T *, unsigned){}
38 
39    public:
40 
41    constexpr span<T> subspan(size_t offset, size_t count) const {
42      return span<T> (elements+offset, count); // expected-warning{{unsafe pointer arithmetic}}
43    }
44 
45    constexpr T* data() const noexcept {
46      return elements;
47    }
48 
49    constexpr T* hello() const noexcept {
50      return elements;
51    }
52  };
53 
54  template <typename T> class vector {
55 
56    T *elements;
57 
58    public:
59 
60    vector(size_t n) {
61      elements = new T[n];
62    }
63 
64    constexpr T* data() const noexcept {
65       return elements;
66    }
67 
68    ~vector() {
69      delete[] elements;
70    }
71  };
72 
73  template <class T, size_t N>
74  class array {
75    T elements[N];
76 
77    public:
78 
79    constexpr const T* data() const noexcept {
80       return elements;
81    }
82 
83  };
84 
85  template <typename T> class span_duplicate {
86    span_duplicate(T *, unsigned){}
87 
88    T array[10];
89 
90    public:
91 
92    T* data() {
93      return array;
94    }
95 
96  };
97 }
98 
99 using namespace std;
100 
101 class A {
102   int a, b, c;
103 };
104 
105 class B {
106   int a, b, c;
107 };
108 
109 struct Base {
110    virtual ~Base() = default;
111 };
112 
113 struct Derived: Base {
114   int d;
115 };
116 
117 void cast_without_data(int *ptr) {
118  A *a = (A*) ptr;
119  float *p = (float*) ptr;
120 }
121 
122 void warned_patterns_span(std::span<int> span_ptr, std::span<Base> base_span, span<int> span_without_qual) {
123     A *a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of 'data'}}
124     a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of 'data'}}
125 
126     a1 = (A*)(span_ptr.data()); // expected-warning{{unsafe invocation of 'data'}}
127     A *a2 = (A*) (span_without_qual.data()); // expected-warning{{unsafe invocation of 'data'}}
128 
129     a2 = (A*) span_without_qual.data(); // expected-warning{{unsafe invocation of 'data'}}
130 
131      // TODO:: Should we warn when we cast from base to derived type?
132      Derived *b = dynamic_cast<Derived*> (base_span.data());// expected-warning{{unsafe invocation of 'data'}}
133 
134     // TODO:: This pattern is safe. We can add special handling for it, if we decide this
135     // is the recommended fixit for the unsafe invocations.
136     A *a3 = (A*)span_ptr.subspan(0, sizeof(A)).data(); // expected-warning{{unsafe invocation of 'data'}}
137 }
138 
139 void warned_patterns_array(std::array<int, 5> array_ptr, std::array<Base, 10> base_span, span<int> span_without_qual) {
140     const A *a1 = (A*)array_ptr.data(); // expected-warning{{unsafe invocation of 'data'}}
141     a1 = (A*)array_ptr.data(); // expected-warning{{unsafe invocation of 'data'}}
142 
143     a1 = (A*)(array_ptr.data()); // expected-warning{{unsafe invocation of 'data'}}
144 }
145 
146 void not_warned_patterns(std::span<A> span_ptr, std::span<Base> base_span) {
147     int *p = (int*) span_ptr.data(); // Cast to a smaller type
148 
149     B *b = (B*) span_ptr.data(); // Cast to a type of same size.
150 
151     p = (int*) span_ptr.data();
152     A *a = (A*) span_ptr.hello(); // Invoking other methods.
153 
154      intptr_t k = (intptr_t) span_ptr.data();
155     k = (intptr_t) (span_ptr.data());
156 }
157 
158 // We do not want to warn about other types
159 void other_classes(std::span_duplicate<int> span_ptr) {
160     int *p;
161     A *a = (A*)span_ptr.data();
162     a = (A*)span_ptr.data();
163 }
164 
165 // Potential source for false negatives
166 
167 A false_negatives(std::span<int> span_pt, span<A> span_A) {
168   int *ptr = span_pt.data();
169 
170   A *a1 = (A*)ptr; //TODO: We want to warn here eventually.
171 
172   A *a2= span_A.data();
173   return *a2; // TODO: Can cause OOB if span_pt is empty
174 
175 }
176 
177 void test_incomplete_type(std::span<char> S) {
178   (struct IncompleteStruct *)S.data(); // expected-warning{{unsafe invocation of 'data'}}
179   (class IncompleteClass *)S.data();   // expected-warning{{unsafe invocation of 'data'}}
180   (union IncompleteUnion *)S.data();   // expected-warning{{unsafe invocation of 'data'}}
181 }
182 
183 void test_complete_type(std::span<long> S) {
184   (struct CompleteStruct *)S.data(); // no warn as the struct size is smaller than long
185   (class CompleteClass *)S.data();   // no warn as the class size is smaller than long
186   (union CompleteUnion *)S.data();   // no warn as the union size is smaller than long
187 
188   struct CompleteStruct {};
189   class CompleteClass {};
190   union CompleteUnion {};
191 }
192 
193 #endif
194