311 lines · cpp
1// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \2// RUN: -fsafe-buffer-usage-suggestions -verify %s3 4[[clang::unsafe_buffer_usage]]5void deprecatedFunction3();6 7void deprecatedFunction4(int z);8 9void someFunction();10 11[[clang::unsafe_buffer_usage]]12void overloading(int* x);13 14void overloading(char c[]);15 16void overloading(int* x, int size);17 18[[clang::unsafe_buffer_usage]]19void deprecatedFunction4(int z);20 21void caller(int z, int* x, int size, char c[]) {22 deprecatedFunction3(); // expected-warning{{function introduces unsafe buffer manipulation}}23 deprecatedFunction4(z); // expected-warning{{function introduces unsafe buffer manipulation}}24 someFunction();25 26 overloading(x); // expected-warning{{function introduces unsafe buffer manipulation}}27 overloading(x, size);28 overloading(c);29}30 31[[clang::unsafe_buffer_usage]]32void overloading(char c[]);33 34// Test variadics35[[clang::unsafe_buffer_usage]]36void testVariadics(int *ptr, ...);37 38template<typename T, typename... Args>39[[clang::unsafe_buffer_usage]]40T adder(T first, Args... args);41 42template <typename T>43void foo(T t) {}44 45template<>46[[clang::unsafe_buffer_usage]]47void foo<int *>(int *t) {}48 49void caller1(int *p, int *q) {50 testVariadics(p, q); // expected-warning{{function introduces unsafe buffer manipulation}}51 adder(p, q); // expected-warning{{function introduces unsafe buffer manipulation}}52 53 int x;54 foo(x);55 foo(&x); // expected-warning{{function introduces unsafe buffer manipulation}}56}57 58// Test virtual functions59class BaseClass {60public:61 [[clang::unsafe_buffer_usage]]62 virtual void func() {}63 64 virtual void func1() {}65};66 67class DerivedClass : public BaseClass {68public:69 void func() {}70 71 [[clang::unsafe_buffer_usage]]72 void func1() {}73};74 75void testInheritance() {76 DerivedClass DC;77 DC.func();78 DC.func1(); // expected-warning{{function introduces unsafe buffer manipulation}}79 80 BaseClass *BC;81 BC->func(); // expected-warning{{function introduces unsafe buffer manipulation}}82 BC->func1();83 84 BC = &DC;85 BC->func(); // expected-warning{{function introduces unsafe buffer manipulation}}86 BC->func1();87}88 89class UnsafeMembers {90public:91 UnsafeMembers() {}92 93 [[clang::unsafe_buffer_usage]]94 UnsafeMembers(int) {}95 96 [[clang::unsafe_buffer_usage]]97 explicit operator int() { return 0; }98 99 [[clang::unsafe_buffer_usage]]100 void Method() {}101 102 [[clang::unsafe_buffer_usage]]103 void operator()() {}104 105 [[clang::unsafe_buffer_usage]]106 int operator+(UnsafeMembers) { return 0; }107};108 109template <class... Vs>110int testFoldExpression(Vs&&... v) {111 return (... + v); // expected-warning{{function introduces unsafe buffer manipulation}}112}113 114struct HoldsUnsafeMembers {115 HoldsUnsafeMembers()116 : FromCtor(3), // expected-warning{{function introduces unsafe buffer manipulation}}117 FromCtor2{3} // expected-warning{{function introduces unsafe buffer manipulation}}118 {}119 120 [[clang::unsafe_buffer_usage]]121 HoldsUnsafeMembers(int i)122 : FromCtor(i),123 FromCtor2{i} {}124 125 HoldsUnsafeMembers(float f)126 : HoldsUnsafeMembers(0) {} // expected-warning{{function introduces unsafe buffer manipulation}}127 128 UnsafeMembers FromCtor;129 UnsafeMembers FromCtor2;130 UnsafeMembers FromField{3}; // expected-warning {{function introduces unsafe buffer manipulation}}131};132 133struct SubclassUnsafeMembers : public UnsafeMembers {134 SubclassUnsafeMembers()135 : UnsafeMembers(3) // expected-warning{{function introduces unsafe buffer manipulation}}136 {}137 138 [[clang::unsafe_buffer_usage]]139 SubclassUnsafeMembers(int i)140 : UnsafeMembers(i){}141};142 143// https://github.com/llvm/llvm-project/issues/80482144void testClassMembers() {145 UnsafeMembers(3); // expected-warning{{function introduces unsafe buffer manipulation}}146 147 (void)static_cast<int>(UnsafeMembers()); // expected-warning{{function introduces unsafe buffer manipulation}}148 149 UnsafeMembers().Method(); // expected-warning{{function introduces unsafe buffer manipulation}}150 151 UnsafeMembers()(); // expected-warning{{function introduces unsafe buffer manipulation}}152 153 testFoldExpression(UnsafeMembers(), UnsafeMembers());154 155 HoldsUnsafeMembers();156 HoldsUnsafeMembers(3); // expected-warning{{function introduces unsafe buffer manipulation}}157 158 SubclassUnsafeMembers();159 SubclassUnsafeMembers(3); // expected-warning{{function introduces unsafe buffer manipulation}}160}161 162// Not an aggregate, so its constructor is not implicit code and will be163// visited/checked for warnings.164struct NotCalledHoldsUnsafeMembers {165 NotCalledHoldsUnsafeMembers()166 : FromCtor(3), // expected-warning{{function introduces unsafe buffer manipulation}}167 FromCtor2{3} // expected-warning{{function introduces unsafe buffer manipulation}}168 {}169 170 UnsafeMembers FromCtor;171 UnsafeMembers FromCtor2;172 UnsafeMembers FromField{3}; // expected-warning{{function introduces unsafe buffer manipulation}}173};174 175// An aggregate, so its constructor is implicit code. Since it's not called, it176// is never generated.177struct AggregateUnused {178 UnsafeMembers f1;179 // While this field would trigger the warning during initialization, since180 // it's unused, there's no code generated that does the initialization, so181 // no warning.182 UnsafeMembers f2{3};183};184 185struct AggregateExplicitlyInitializedSafe {186 UnsafeMembers f1;187 // The warning is not fired as the field is always explicltly initialized188 // elsewhere. This initializer is never used.189 UnsafeMembers f2{3};190};191 192void testAggregateExplicitlyInitializedSafe() {193 AggregateExplicitlyInitializedSafe A{194 .f2 = UnsafeMembers(), // A safe constructor.195 };196}197 198struct AggregateExplicitlyInitializedUnsafe {199 UnsafeMembers f1;200 // The warning is not fired as the field is always explicltly initialized201 // elsewhere. This initializer is never used.202 UnsafeMembers f2{3};203};204 205void testAggregateExplicitlyInitializedUnsafe() {206 AggregateExplicitlyInitializedUnsafe A{207 .f2 = UnsafeMembers(3), // expected-warning{{function introduces unsafe buffer manipulation}}208 };209}210 211struct AggregateViaAggregateInit {212 UnsafeMembers f1;213 // FIXME: A construction of this class does initialize the field through214 // this initializer, so it should warn. Ideally it should also point to215 // where the site of the construction is in testAggregateViaAggregateInit().216 UnsafeMembers f2{3};217};218 219void testAggregateViaAggregateInit() {220 AggregateViaAggregateInit A{};221};222 223struct AggregateViaValueInit {224 UnsafeMembers f1;225 // FIXME: A construction of this class does initialize the field through226 // this initializer, so it should warn. Ideally it should also point to227 // where the site of the construction is in testAggregateViaValueInit().228 UnsafeMembers f2{3};229};230 231void testAggregateViaValueInit() {232 auto A = AggregateViaValueInit();233};234 235struct AggregateViaDefaultInit {236 UnsafeMembers f1;237 // FIXME: A construction of this class does initialize the field through238 // this initializer, so it should warn. Ideally it should also point to239 // where the site of the construction is in testAggregateViaValueInit().240 UnsafeMembers f2{3};241};242 243void testAggregateViaDefaultInit() {244 AggregateViaDefaultInit A;245};246 247struct A {248 int arr[2];249 250 [[clang::unsafe_buffer_usage]]251 int *ptr;252};253 254namespace std{255 template <typename T> class span {256 257 T *elements;258 259 public:260 261 constexpr span(T *, unsigned){}262 263 template<class Begin, class End>264 constexpr span(Begin first, End last){}265 266 constexpr T* data() const noexcept {267 return elements;268 }269 };270}271 272[[clang::unsafe_buffer_usage]]273void check_no_warnings(unsigned idx) {274 int *arr = new int[20];275 276 int k = arr[idx]; // no-warning277 278 std::span<int> sp = {arr, 20}; // no-warning279 A *ptr = reinterpret_cast<A*> (sp.data()); // no-warning280 A a;281 a.ptr = arr; // no-warning282}283 284[[clang::unsafe_buffer_usage]]285void check_no_warning_variadic(unsigned idx, int arr[20], ...) {286 int k = arr[idx]; // no-warning287 288 std::span<int> sp = {arr, 20}; // no-warning289 A *ptr = reinterpret_cast<A*> (sp.data()); // no-warning290 A a;291 a.ptr = arr; // no-warning292}293 294template<typename T>295[[clang::unsafe_buffer_usage]]296void check_no_warnings_template(unsigned idx, T* arr) {297 int k = arr[idx]; // no-warning298 299 std::span<int> sp = {arr, 20}; // no-warning300 A *ptr = reinterpret_cast<A*> (sp.data()); // no-warning301 A a;302 a.ptr = arr; // no-warning303}304 305void invoke_methods() {306 int array[20];307 check_no_warnings(30); //expected-warning{{function introduces unsafe buffer manipulation}}308 check_no_warning_variadic(15, array); //expected-warning{{function introduces unsafe buffer manipulation}}309 check_no_warnings_template(10, array); //expected-warning{{function introduces unsafe buffer manipulation}}310}311