// 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