194 lines · cpp
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 %s4 5// RUN: %clang -x c++ -frtti -fsyntax-only -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s6// RUN: %clang_cc1 -std=c++11 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s7// RUN: %clang_cc1 -std=c++20 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s8// CHECK-NOT: [-Wunsafe-buffer-usage]9 10#ifndef INCLUDED11#define INCLUDED12#pragma clang system_header13 14// no spanification warnings for system headers15#else16 17typedef __INTPTR_TYPE__ intptr_t;18 19namespace std {20 class type_info;21 class bad_cast;22 class bad_typeid;23}24using size_t = __typeof(sizeof(int));25void *malloc(size_t);26 27void foo(int v) {28}29 30void foo(int *p){}31 32namespace 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 99using namespace std;100 101class A {102 int a, b, c;103};104 105class B {106 int a, b, c;107};108 109struct Base {110 virtual ~Base() = default;111};112 113struct Derived: Base {114 int d;115};116 117void cast_without_data(int *ptr) {118 A *a = (A*) ptr;119 float *p = (float*) ptr;120}121 122void 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 this135 // 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 139void 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 146void not_warned_patterns(std::span<A> span_ptr, std::span<Base> base_span) {147 int *p = (int*) span_ptr.data(); // Cast to a smaller type148 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 types159void 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 negatives166 167A 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 empty174 175}176 177void 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 183void test_complete_type(std::span<long> S) {184 (struct CompleteStruct *)S.data(); // no warn as the struct size is smaller than long185 (class CompleteClass *)S.data(); // no warn as the class size is smaller than long186 (union CompleteUnion *)S.data(); // no warn as the union size is smaller than long187 188 struct CompleteStruct {};189 class CompleteClass {};190 union CompleteUnion {};191}192 193#endif194