1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage -Wno-unsafe-buffer-usage-in-container\
// RUN: -fsafe-buffer-usage-suggestions \
// RUN: -fblocks -include %s -verify %s
// RUN: %clang -x c++ -frtti -fsyntax-only -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s
// RUN: %clang_cc1 -std=c++11 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s
// RUN: %clang_cc1 -std=c++20 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s
// CHECK-NOT: [-Wunsafe-buffer-usage]
#ifndef INCLUDED
#define INCLUDED
#pragma clang system_header
// no spanification warnings for system headers
#else
typedef __INTPTR_TYPE__ intptr_t;
namespace std {
class type_info;
class bad_cast;
class bad_typeid;
}
using size_t = __typeof(sizeof(int));
void *malloc(size_t);
void foo(int v) {
}
void foo(int *p){}
namespace std{
template <typename T> class span {
T *elements;
span(T *, unsigned){}
public:
constexpr span<T> subspan(size_t offset, size_t count) const {
return span<T> (elements+offset, count); // expected-warning{{unsafe pointer arithmetic}}
}
constexpr T* data() const noexcept {
return elements;
}
constexpr T* hello() const noexcept {
return elements;
}
};
template <typename T> class span_duplicate {
span_duplicate(T *, unsigned){}
T array[10];
public:
T* data() {
return array;
}
};
}
using namespace std;
class A {
int a, b, c;
};
class B {
int a, b, c;
};
struct Base {
virtual ~Base() = default;
};
struct Derived: Base {
int d;
};
void cast_without_data(int *ptr) {
A *a = (A*) ptr;
float *p = (float*) ptr;
}
void warned_patterns(std::span<int> span_ptr, std::span<Base> base_span, span<int> span_without_qual) {
A *a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of span::data}}
a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of span::data}}
a1 = (A*)(span_ptr.data()); // expected-warning{{unsafe invocation of span::data}}
A *a2 = (A*) (span_without_qual.data()); // expected-warning{{unsafe invocation of span::data}}
a2 = (A*) span_without_qual.data(); // expected-warning{{unsafe invocation of span::data}}
// TODO:: Should we warn when we cast from base to derived type?
Derived *b = dynamic_cast<Derived*> (base_span.data());// expected-warning{{unsafe invocation of span::data}}
// TODO:: This pattern is safe. We can add special handling for it, if we decide this
// is the recommended fixit for the unsafe invocations.
A *a3 = (A*)span_ptr.subspan(0, sizeof(A)).data(); // expected-warning{{unsafe invocation of span::data}}
}
void not_warned_patterns(std::span<A> span_ptr, std::span<Base> base_span) {
int *p = (int*) span_ptr.data(); // Cast to a smaller type
B *b = (B*) span_ptr.data(); // Cast to a type of same size.
p = (int*) span_ptr.data();
A *a = (A*) span_ptr.hello(); // Invoking other methods.
intptr_t k = (intptr_t) span_ptr.data();
k = (intptr_t) (span_ptr.data());
}
// We do not want to warn about other types
void other_classes(std::span_duplicate<int> span_ptr) {
int *p;
A *a = (A*)span_ptr.data();
a = (A*)span_ptr.data();
}
// Potential source for false negatives
A false_negatives(std::span<int> span_pt, span<A> span_A) {
int *ptr = span_pt.data();
A *a1 = (A*)ptr; //TODO: We want to warn here eventually.
A *a2= span_A.data();
return *a2; // TODO: Can cause OOB if span_pt is empty
}
#endif
|