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