This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG237ca436adf4: [-Wunsafe-buffer-usage] Group diagnostics by variable (authored by jkorous). Herald added a project: clang. Herald added a subscriber: cfe-commits.
Changed prior to commit: https://reviews.llvm.org/D141356?vs=489936&id=490308#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D141356/new/ https://reviews.llvm.org/D141356 Files: clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Analysis/UnsafeBufferUsage.cpp clang/lib/Sema/AnalysisBasedWarnings.cpp clang/test/SemaCXX/unsafe-buffer-usage-diag-type.cpp clang/test/SemaCXX/warn-unsafe-buffer-usage-source-ranges.cpp clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp @@ -1,4 +1,10 @@ -// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fblocks -include %s -verify %s +// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage -fblocks -include %s -verify %s + +// RUN: %clang -x c++ -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 @@ -18,41 +24,50 @@ #else -void testIncrement(char *p) { - ++p; // expected-warning{{unchecked operation on raw buffer in expression}} - p++; // expected-warning{{unchecked operation on raw buffer in expression}} - --p; // expected-warning{{unchecked operation on raw buffer in expression}} - p--; // expected-warning{{unchecked operation on raw buffer in expression}} +void testIncrement(char *p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}} + ++p; // expected-note{{used in pointer arithmetic here}} + p++; // expected-note{{used in pointer arithmetic here}} + --p; // expected-note{{used in pointer arithmetic here}} + p--; // expected-note{{used in pointer arithmetic here}} } void * voidPtrCall(void); char * charPtrCall(void); void testArraySubscripts(int *p, int **pp) { - foo(p[1], // expected-warning{{unchecked operation on raw buffer in expression}} - pp[1][1], // expected-warning2{{unchecked operation on raw buffer in expression}} - 1[1[pp]], // expected-warning2{{unchecked operation on raw buffer in expression}} - 1[pp][1] // expected-warning2{{unchecked operation on raw buffer in expression}} +// expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} +// expected-warning@-2{{'pp' is an unsafe pointer used for buffer access}} + foo(p[1], // expected-note{{used in buffer access here}} + pp[1][1], // expected-note{{used in buffer access here}} + // expected-warning@-1{{unsafe buffer access}} + 1[1[pp]], // expected-note{{used in buffer access here}} + // expected-warning@-1{{unsafe buffer access}} + 1[pp][1] // expected-note{{used in buffer access here}} + // expected-warning@-1{{unsafe buffer access}} ); - if (p[3]) { // expected-warning{{unchecked operation on raw buffer in expression}} + if (p[3]) { // expected-note{{used in buffer access here}} void * q = p; - foo(((int*)q)[10]); // expected-warning{{unchecked operation on raw buffer in expression}} + foo(((int*)q)[10]); // expected-warning{{unsafe buffer access}} } - foo(((int*)voidPtrCall())[3], // expected-warning{{unchecked operation on raw buffer in expression}} - 3[(int*)voidPtrCall()], // expected-warning{{unchecked operation on raw buffer in expression}} - charPtrCall()[3], // expected-warning{{unchecked operation on raw buffer in expression}} - 3[charPtrCall()] // expected-warning{{unchecked operation on raw buffer in expression}} + foo(((int*)voidPtrCall())[3], // expected-warning{{unsafe buffer access}} + 3[(int*)voidPtrCall()], // expected-warning{{unsafe buffer access}} + charPtrCall()[3], // expected-warning{{unsafe buffer access}} + 3[charPtrCall()] // expected-warning{{unsafe buffer access}} ); - int a[10], b[10][10]; + int a[10]; // expected-warning{{'a' is an unsafe buffer that does not perform bounds checks}} + int b[10][10]; // expected-warning{{'b' is an unsafe buffer that does not perform bounds checks}} - foo(a[1], 1[a], // expected-warning2{{unchecked operation on raw buffer in expression}} - b[3][4], // expected-warning2{{unchecked operation on raw buffer in expression}} - 4[b][3], // expected-warning2{{unchecked operation on raw buffer in expression}} - 4[3[b]]); // expected-warning2{{unchecked operation on raw buffer in expression}} + foo(a[1], 1[a], // expected-note2{{used in buffer access here}} + b[3][4], // expected-warning{{unsafe buffer access}} + // expected-note@-1{{used in buffer access here}} + 4[b][3], // expected-warning{{unsafe buffer access}} + // expected-note@-1{{used in buffer access here}} + 4[3[b]]); // expected-warning{{unsafe buffer access}} + // expected-note@-1{{used in buffer access here}} // Not to warn when index is zero foo(p[0], pp[0][0], 0[0[pp]], 0[pp][0], @@ -65,37 +80,41 @@ void testArraySubscriptsWithAuto(int *p, int **pp) { int a[10]; + auto ap1 = a; // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} - auto ap1 = a; + foo(ap1[1]); // expected-note{{used in buffer access here}} - foo(ap1[1]); // expected-warning{{unchecked operation on raw buffer in expression}} + auto ap2 = p; // expected-warning{{'ap2' is an unsafe pointer used for buffer access}} - auto ap2 = p; + foo(ap2[1]); // expected-note{{used in buffer access here}} - foo(ap2[1]); // expected-warning{{unchecked operation on raw buffer in expression}} + auto ap3 = pp; // expected-warning{{'ap3' is an unsafe pointer used for buffer access}} - auto ap3 = pp; + foo(ap3[1][1]); // expected-note{{used in buffer access here}} + // expected-warning@-1{{unsafe buffer access}} - foo(ap3[1][1]); // expected-warning2{{unchecked operation on raw buffer in expression}} + auto ap4 = *pp; // expected-warning{{'ap4' is an unsafe pointer used for buffer access}} - auto ap4 = *pp; - - foo(ap4[1]); // expected-warning{{unchecked operation on raw buffer in expression}} + foo(ap4[1]); // expected-note{{used in buffer access here}} } -void testUnevaluatedContext(int * p) { - //TODO: do not warn for unevaluated context - foo(sizeof(p[1]), // expected-warning{{unchecked operation on raw buffer in expression}} - sizeof(decltype(p[1]))); // expected-warning{{unchecked operation on raw buffer in expression}} +//TODO: do not warn for unevaluated context +void testUnevaluatedContext(int * p) {// expected-warning{{'p' is an unsafe pointer used for buffer access}} + foo(sizeof(p[1]), // expected-note{{used in buffer access here}} + sizeof(decltype(p[1]))); // expected-note{{used in buffer access here}} } -void testQualifiedParameters(const int * p, const int * const q, - const int a[10], const int b[10][10], - int (&c)[10]) { - foo(p[1], 1[p], p[-1], // expected-warning3{{unchecked operation on raw buffer in expression}} - q[1], 1[q], q[-1], // expected-warning3{{unchecked operation on raw buffer in expression}} - a[1], // expected-warning{{unchecked operation on raw buffer in expression}} `a` is of pointer type - b[1][2] // expected-warning2{{unchecked operation on raw buffer in expression}} `b[1]` is of array type +void testQualifiedParameters(const int * p, const int * const q, const int a[10], const int b[10][10]) { + // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} + // expected-warning@-2{{'q' is an unsafe pointer used for buffer access}} + // expected-warning@-3{{'a' is an unsafe pointer used for buffer access}} + // expected-warning@-4{{'b' is an unsafe pointer used for buffer access}} + + foo(p[1], 1[p], p[-1], // expected-note3{{used in buffer access here}} + q[1], 1[q], q[-1], // expected-note3{{used in buffer access here}} + a[1], // expected-note{{used in buffer access here}} `a` is of pointer type + b[1][2] // expected-note{{used in buffer access here}} `b[1]` is of array type + // expected-warning@-1{{unsafe buffer access}} ); } @@ -114,57 +133,66 @@ T_t * funRetTStar(); void testStructMembers(struct T * sp, struct T s, T_t * sp2, T_t s2) { - foo(sp->a[1], // expected-warning{{unchecked operation on raw buffer in expression}} - sp->b[1], // expected-warning{{unchecked operation on raw buffer in expression}} - sp->c.a[1], // expected-warning{{unchecked operation on raw buffer in expression}} - sp->c.b[1], // expected-warning{{unchecked operation on raw buffer in expression}} - s.a[1], // expected-warning{{unchecked operation on raw buffer in expression}} - s.b[1], // expected-warning{{unchecked operation on raw buffer in expression}} - s.c.a[1], // expected-warning{{unchecked operation on raw buffer in expression}} - s.c.b[1], // expected-warning{{unchecked operation on raw buffer in expression}} - sp2->a[1], // expected-warning{{unchecked operation on raw buffer in expression}} - sp2->b[1], // expected-warning{{unchecked operation on raw buffer in expression}} - sp2->c.a[1], // expected-warning{{unchecked operation on raw buffer in expression}} - sp2->c.b[1], // expected-warning{{unchecked operation on raw buffer in expression}} - s2.a[1], // expected-warning{{unchecked operation on raw buffer in expression}} - s2.b[1], // expected-warning{{unchecked operation on raw buffer in expression}} - s2.c.a[1], // expected-warning{{unchecked operation on raw buffer in expression}} - s2.c.b[1], // expected-warning{{unchecked operation on raw buffer in expression}} - funRetT().a[1], // expected-warning{{unchecked operation on raw buffer in expression}} - funRetT().b[1], // expected-warning{{unchecked operation on raw buffer in expression}} - funRetTStar()->a[1], // expected-warning{{unchecked operation on raw buffer in expression}} - funRetTStar()->b[1] // expected-warning{{unchecked operation on raw buffer in expression}} - ); + foo(sp->a[1], // expected-warning{{unsafe buffer access}} + sp->b[1], // expected-warning{{unsafe buffer access}} + sp->c.a[1], // expected-warning{{unsafe buffer access}} + sp->c.b[1], // expected-warning{{unsafe buffer access}} + s.a[1], // expected-warning{{unsafe buffer access}} + s.b[1], // expected-warning{{unsafe buffer access}} + s.c.a[1], // expected-warning{{unsafe buffer access}} + s.c.b[1], // expected-warning{{unsafe buffer access}} + sp2->a[1], // expected-warning{{unsafe buffer access}} + sp2->b[1], // expected-warning{{unsafe buffer access}} + sp2->c.a[1], // expected-warning{{unsafe buffer access}} + sp2->c.b[1], // expected-warning{{unsafe buffer access}} + s2.a[1], // expected-warning{{unsafe buffer access}} + s2.b[1], // expected-warning{{unsafe buffer access}} + s2.c.a[1], // expected-warning{{unsafe buffer access}} + s2.c.b[1], // expected-warning{{unsafe buffer access}} + funRetT().a[1], // expected-warning{{unsafe buffer access}} + funRetT().b[1], // expected-warning{{unsafe buffer access}} + funRetTStar()->a[1], // expected-warning{{unsafe buffer access}} + funRetTStar()->b[1] // expected-warning{{unsafe buffer access}} + ); } -int garray[10]; -int * gp = garray; -int gvar = gp[1]; // FIXME: file scope unsafe buffer access is not warned +int garray[10]; // expected-warning{{'garray' is an unsafe buffer that does not perform bounds checks}} +int * gp = garray; // expected-warning{{'gp' is an unsafe pointer used for buffer access}} +int gvar = gp[1]; // FIXME: file scope unsafe buffer access is not warned +// FIXME: Add test for lambda capture with initializer. E. g. auto Lam = [new_p = p]() {... void testLambdaCaptureAndGlobal(int * p) { - int a[10]; + // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} + int a[10]; // expected-warning{{'a' is an unsafe buffer that does not perform bounds checks}} auto Lam = [p, a]() { - return p[1] // expected-warning{{unchecked operation on raw buffer in expression}} - + a[1] + garray[1] // expected-warning2{{unchecked operation on raw buffer in expression}} - + gp[1]; // expected-warning{{unchecked operation on raw buffer in expression}} + return p[1] // expected-note{{used in buffer access here}} + + a[1] + garray[1] // expected-note2{{used in buffer access here}} + + gp[1]; // expected-note{{used in buffer access here}} }; } typedef T_t * T_ptr_t; void testTypedefs(T_ptr_t p) { - foo(p[1], // expected-warning{{unchecked operation on raw buffer in expression}} - p[1].a[1], // expected-warning2{{unchecked operation on raw buffer in expression}} - p[1].b[1] // expected-warning2{{unchecked operation on raw buffer in expression}} + // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} + foo(p[1], // expected-note{{used in buffer access here}} + p[1].a[1], // expected-note{{used in buffer access here}} + // expected-warning@-1{{unsafe buffer access}} + p[1].b[1] // expected-note{{used in buffer access here}} + // expected-warning@-1{{unsafe buffer access}} ); } template<typename T, int N> T f(T t, T * pt, T a[N], T (&b)[N]) { - foo(pt[1], // expected-warning{{unchecked operation on raw buffer in expression}} - a[1], // expected-warning{{unchecked operation on raw buffer in expression}} - b[1]); // expected-warning{{unchecked operation on raw buffer in expression}} - return &t[1]; // expected-warning{{unchecked operation on raw buffer in expression}} + // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}} + // expected-warning@-2{{'pt' is an unsafe pointer used for buffer access}} + // expected-warning@-3{{'a' is an unsafe pointer used for buffer access}} + // expected-warning@-4{{'b' is an unsafe buffer that does not perform bounds checks}} + foo(pt[1], // expected-note{{used in buffer access here}} + a[1], // expected-note{{used in buffer access here}} + b[1]); // expected-note{{used in buffer access here}} + return &t[1]; // expected-note{{used in buffer access here}} } // Testing pointer arithmetic for pointer-to-int, qualified multi-level @@ -173,30 +201,32 @@ template<typename T> void testPointerArithmetic(int * p, const int **q, T * x) { +// expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} +// expected-warning@-2{{'x' is an unsafe pointer used for buffer access}} int a[10]; - auto y = &a[0]; + auto y = &a[0]; // expected-warning{{'y' is an unsafe pointer used for buffer access}} - foo(p + 1, 1 + p, p - 1, // expected-warning3{{unchecked operation on raw buffer in expression}} - *q + 1, 1 + *q, *q - 1, // expected-warning3{{unchecked operation on raw buffer in expression}} - x + 1, 1 + x, x - 1, // expected-warning3{{unchecked operation on raw buffer in expression}} - y + 1, 1 + y, y - 1, // expected-warning3{{unchecked operation on raw buffer in expression}} - getPtr() + 1, 1 + getPtr(), getPtr() - 1 // expected-warning3{{unchecked operation on raw buffer in expression}} + foo(p + 1, 1 + p, p - 1, // expected-note3{{used in pointer arithmetic here}} + *q + 1, 1 + *q, *q - 1, // expected-warning3{{unsafe pointer arithmetic}} + x + 1, 1 + x, x - 1, // expected-note3{{used in pointer arithmetic here}} + y + 1, 1 + y, y - 1, // expected-note3{{used in pointer arithmetic here}} + getPtr() + 1, 1 + getPtr(), getPtr() - 1 // expected-warning3{{unsafe pointer arithmetic}} ); - p += 1; p -= 1; // expected-warning2{{unchecked operation on raw buffer in expression}} - *q += 1; *q -= 1; // expected-warning2{{unchecked operation on raw buffer in expression}} - y += 1; y -= 1; // expected-warning2{{unchecked operation on raw buffer in expression}} - x += 1; x -= 1; // expected-warning2{{unchecked operation on raw buffer in expression}} + p += 1; p -= 1; // expected-note2{{used in pointer arithmetic here}} + *q += 1; *q -= 1; // expected-warning2{{unsafe pointer arithmetic}} + y += 1; y -= 1; // expected-note2{{used in pointer arithmetic here}} + x += 1; x -= 1; // expected-note2{{used in pointer arithmetic here}} } void testTemplate(int * p) { int *a[10]; - foo(f(p, &p, a, a)[1]); // expected-warning{{unchecked operation on raw buffer in expression}}, \ - expected-note{{in instantiation of function template specialization 'f<int *, 10>' requested here}} + foo(f(p, &p, a, a)[1]); // expected-warning{{unsafe buffer access}} + // expected-note@-1{{in instantiation of function template specialization 'f<int *, 10>' requested here}} const int **q = const_cast<const int **>(&p); - testPointerArithmetic(p, q, p); //expected-note{{in instantiation of function template specialization 'testPointerArithmetic<int>' requested here}} + testPointerArithmetic(p, q, p); //expected-note{{in instantiation of}} } void testPointerToMember() { @@ -209,106 +239,125 @@ int * S_t::* q = &S_t::y; foo(S.*p, - (S.*q)[1]); // expected-warning{{unchecked operation on raw buffer in expression}} + (S.*q)[1]); // expected-warning{{unsafe buffer access}} } // test that nested callable definitions are scanned only once void testNestedCallableDefinition(int * p) { class A { void inner(int * p) { - p++; // expected-warning{{unchecked operation on raw buffer in expression}} + // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} + p++; // expected-note{{used in pointer arithmetic here}} } static void innerStatic(int * p) { - p++; // expected-warning{{unchecked operation on raw buffer in expression}} + // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} + p++; // expected-note{{used in pointer arithmetic here}} } void innerInner(int * p) { auto Lam = [p]() { - int * q = p; - q++; // expected-warning{{unchecked operation on raw buffer in expression}} + int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}} + q++; // expected-note{{used in pointer arithmetic here}} return *q; }; } }; auto Lam = [p]() { - int * q = p; - q++; // expected-warning{{unchecked operation on raw buffer in expression}} + int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}} + q++; // expected-note{{used in pointer arithmetic here}} return *q; }; auto LamLam = [p]() { auto Lam = [p]() { - int * q = p; - q++; // expected-warning{{unchecked operation on raw buffer in expression}} + int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}} + q++; // expected-note{{used in pointer arithmetic here}} return *q; }; }; void (^Blk)(int*) = ^(int *p) { - p++; // expected-warning{{unchecked operation on raw buffer in expression}} + // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} + p++; // expected-note{{used in pointer arithmetic here}} }; void (^BlkBlk)(int*) = ^(int *p) { void (^Blk)(int*) = ^(int *p) { - p++; // expected-warning{{unchecked operation on raw buffer in expression}} + // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} + p++; // expected-note{{used in pointer arithmetic here}} }; Blk(p); }; // lambda and block as call arguments... - foo( [p]() { int * q = p; - q++; // expected-warning{{unchecked operation on raw buffer in expression}} + foo( [p]() { int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}} + q++; // expected-note{{used in pointer arithmetic here}} return *q; }, - ^(int *p) { p++; // expected-warning{{unchecked operation on raw buffer in expression}} + ^(int *p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}} + p++; // expected-note{{used in pointer arithmetic here}} } ); } int testVariableDecls(int * p) { - int * q = p++; // expected-warning{{unchecked operation on raw buffer in expression}} - int a[p[1]]; // expected-warning{{unchecked operation on raw buffer in expression}} - int b = p[1]; // expected-warning{{unchecked operation on raw buffer in expression}} - return p[1]; // expected-warning{{unchecked operation on raw buffer in expression}} + // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} + int * q = p++; // expected-note{{used in pointer arithmetic here}} + int a[p[1]]; // expected-note{{used in buffer access here}} + int b = p[1]; // expected-note{{used in buffer access here}} + return p[1]; // expected-note{{used in buffer access here}} } - + template<typename T> void fArr(T t[]) { - foo(t[1]); // expected-warning{{unchecked operation on raw buffer in expression}} - T ar[8]; - foo(ar[5]); // expected-warning{{unchecked operation on raw buffer in expression}} + // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}} + foo(t[1]); // expected-note{{used in buffer access here}} + T ar[8]; // expected-warning{{'ar' is an unsafe buffer that does not perform bounds checks}} + foo(ar[5]); // expected-note{{used in buffer access here}} } -template void fArr<int>(int t[]); // expected-note {{in instantiation of function template specialization 'fArr<int>' requested here}} +template void fArr<int>(int t[]); // expected-note {{in instantiation of}} + +int testReturn(int t[]) { + // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}} + return t[1]; // expected-note{{used in buffer access here}} +} - int testReturn(int t[]) { - return t[1]; // expected-warning{{unchecked operation on raw buffer in expression}} - } - -//FIXME: Array access warnings on 0-indices;ArraySubscriptGadget excludes 0 index for both raw pointers and arrays! int testArrayAccesses(int n) { - - // auto deduced array type - int cArr[2][3] = {{1, 2, 3}, {4, 5, 6}}; - int d = cArr[0][0]; - foo(cArr[0][0]); - foo(cArr[1][2]); // expected-warning2{{unchecked operation on raw buffer in expression}} - auto cPtr = cArr[1][2]; // expected-warning2{{unchecked operation on raw buffer in expression}} - foo(cPtr); - - // Typdefs - typedef int A[3]; - const A tArr = {4, 5, 6}; - foo(tArr[0], tArr[1]); // expected-warning{{unchecked operation on raw buffer in expression}} - return cArr[0][1]; // expected-warning{{unchecked operation on raw buffer in expression}} + // auto deduced array type + int cArr[2][3] = {{1, 2, 3}, {4, 5, 6}}; + // expected-warning@-1{{'cArr' is an unsafe buffer that does not perform bounds checks}} + int d = cArr[0][0]; + foo(cArr[0][0]); + foo(cArr[1][2]); // expected-note{{used in buffer access here}} + // expected-warning@-1{{unsafe buffer access}} + auto cPtr = cArr[1][2]; // expected-note{{used in buffer access here}} + // expected-warning@-1{{unsafe buffer access}} + foo(cPtr); + + // Typdefs + typedef int A[3]; + const A tArr = {4, 5, 6}; + // expected-warning@-1{{'tArr' is an unsafe buffer that does not perform bounds checks}} + foo(tArr[0], tArr[1]); // expected-note{{used in buffer access here}} + return cArr[0][1]; // expected-warning{{unsafe buffer access}} } - -void testArrayPtrArithmetic(int x[]) { - foo (x + 3); // expected-warning{{unchecked operation on raw buffer in expression}} - - int y[3] = {0, 1, 2}; - foo(y + 4); // expected-warning{{unchecked operation on raw buffer in expression}} + +void testArrayPtrArithmetic(int x[]) { // expected-warning{{'x' is an unsafe pointer used for buffer access}} + foo (x + 3); // expected-note{{used in pointer arithmetic here}} + + int y[3] = {0, 1, 2}; // expected-warning{{'y' is an unsafe buffer that does not perform bounds checks}} + foo(y + 4); // expected-note{{used in pointer arithmetic here}} +} + +void testMultiLineDeclStmt(int * p) { + auto + + + ap1 = p; // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} + + foo(ap1[1]); // expected-note{{used in buffer access here}} } #endif Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-source-ranges.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-source-ranges.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-source-ranges.cpp @@ -3,47 +3,46 @@ void foo(int i) { int * ptr; - ptr++; - // CHECK-DAG: {7:3-7:6}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:3-[[@LINE-1]]:6} ptr--; - // CHECK-DAG: {9:3-9:6}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:3-[[@LINE-1]]:6} ++ptr; - // CHECK-DAG: {11:5-11:8}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:5-[[@LINE-1]]:8} --ptr; - // CHECK-DAG: {13:5-13:8}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:5-[[@LINE-1]]:8} ptr + 1; - // CHECK-DAG: {17:3-17:6}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:3-[[@LINE-1]]:6} 2 + ptr; - // CHECK-DAG: {19:7-19:10}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:7-[[@LINE-1]]:10} ptr + i; - // CHECK-DAG: {21:3-21:6}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:3-[[@LINE-1]]:6} i + ptr; - // CHECK-DAG: {23:7-23:10}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:7-[[@LINE-1]]:10} ptr - 3; - // CHECK-DAG: {27:3-27:6}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:3-[[@LINE-1]]:6} ptr - i; - // CHECK-DAG: {29:3-29:6}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:3-[[@LINE-1]]:6} ptr += 4; - // CHECK-DAG: {33:3-33:6}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:3-[[@LINE-1]]:6} ptr += i; - // CHECK-DAG: {35:3-35:6}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:3-[[@LINE-1]]:6} ptr -= 5; - // CHECK-DAG: {39:3-39:6}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:3-[[@LINE-1]]:6} ptr -= i; - // CHECK-DAG: {41:3-41:6}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:3-[[@LINE-1]]:6} ptr[5]; - // CHECK-DAG: {45:3-45:6}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:3-[[@LINE-1]]:6} 5[ptr]; - // CHECK-DAG: {47:5-47:8}{{.*}}[-Wunsafe-buffer-usage] + // CHECK-DAG: {[[@LINE-1]]:5-[[@LINE-1]]:8} } Index: clang/test/SemaCXX/unsafe-buffer-usage-diag-type.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/unsafe-buffer-usage-diag-type.cpp @@ -0,0 +1,108 @@ +// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage -verify %s + +namespace localVar { +void testRefersPtrLocalVarDecl(int i) { + int * ptr; // expected-warning{{'ptr' is an unsafe pointer used for buffer access}} + ptr + i; // expected-note{{used in pointer arithmetic here}} + ptr[i]; // expected-note{{used in buffer access here}} +} + +void testRefersArrayLocalVarDecl(int i) { + int array[i]; // expected-warning{{'array' is an unsafe buffer that does not perform bounds}} + array[i/2]; // expected-note{{used in buffer access here}} +} +} + +namespace globalVar { +int * ptr; // expected-warning{{'ptr' is an unsafe pointer used for buffer access}} +void testRefersPtrGlobalVarDecl(int i) { + ptr + i; // expected-note{{used in pointer arithmetic here}} + ptr[i]; // expected-note{{used in buffer access here}} +} + +int array[10]; // expected-warning{{'array' is an unsafe buffer that does not perform bounds}} +void testRefersArrayGlobalVarDecl(int i) { + array[i/2]; // expected-note{{used in buffer access here}} +} +} + +namespace functionParm { +void testRefersPtrParmVarDecl(int * ptr) { + // expected-warning@-1{{'ptr' is an unsafe pointer used for buffer access}} + ptr + 5; // expected-note{{used in pointer arithmetic here}} + ptr[5]; // expected-note{{used in buffer access here}} +} + +// FIXME: shall we explain the array to pointer decay to make the warning more understandable? +void testRefersArrayParmVarDecl(int array[10]) { + // expected-warning@-1{{'array' is an unsafe pointer used for buffer access}} + array[2]; // expected-note{{used in buffer access here}} +} +} + +namespace structField { +struct Struct1 { + int * ptr; // FIXME: per-declaration warning aggregated at the struct definition? +}; + +void testRefersPtrStructFieldDecl(int i) { + Struct1 s1; + s1.ptr + i; // expected-warning{{unsafe pointer arithmetic}} + s1.ptr[i]; // expected-warning{{unsafe buffer access}} +} + +struct Struct2 { + int array[10]; // FIXME: per-declaration warning aggregated at the struct definition? +}; + +void testRefersArrayStructFieldDecl(int i) { + Struct2 s2; + s2.array[i/2]; // expected-warning{{unsafe buffer access}} +} +} + +namespace structFieldFromMethod { +struct Struct1 { + int * ptr; // FIXME: per-declaration warning aggregated at the struct definition + + void testRefersPtrStructFieldDecl(int i) { + ptr + i; // expected-warning{{unsafe pointer arithmetic}} + ptr[i]; // expected-warning{{unsafe buffer access}} + } +}; + +struct Struct2 { + int array[10]; // FIXME: per-declaration warning aggregated at the struct definition + + void testRefersArrayStructFieldDecl(int i) { + Struct2 s2; + s2.array[i/2]; // expected-warning{{unsafe buffer access}} + } +}; +} + +namespace staticStructField { +struct Struct1 { + static int * ptr; // expected-warning{{'ptr' is an unsafe pointer used for buffer access}} +}; + +void testRefersPtrStructFieldDecl(int i) { + Struct1::ptr + i; // expected-note{{used in pointer arithmetic here}} + Struct1::ptr[i]; // expected-note{{used in buffer access here}} +} + +struct Struct2 { + static int array[10]; // expected-warning{{'array' is an unsafe buffer that does not perform bounds}} +}; + +void testRefersArrayStructFieldDecl(int i) { + Struct2::array[i/2]; // expected-note{{used in buffer access here}} +} +} + +int * return_ptr(); + +void testNoDeclRef(int i) { + return_ptr() + i; // expected-warning{{unsafe pointer arithmetic}} + return_ptr()[i]; // expected-warning{{unsafe buffer access}} +} Index: clang/lib/Sema/AnalysisBasedWarnings.cpp =================================================================== --- clang/lib/Sema/AnalysisBasedWarnings.cpp +++ clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2153,12 +2153,15 @@ public: UnsafeBufferUsageReporter(Sema &S) : S(S) {} - void handleUnsafeOperation(const Stmt *Operation) override { + void handleUnsafeOperation(const Stmt *Operation, + bool IsRelatedToDecl) override { SourceLocation Loc; SourceRange Range; + unsigned MsgParam = 0; if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) { Loc = ASE->getBase()->getExprLoc(); Range = ASE->getBase()->getSourceRange(); + MsgParam = 2; } else if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) { BinaryOperator::Opcode Op = BO->getOpcode(); if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub || @@ -2170,6 +2173,7 @@ Loc = BO->getRHS()->getExprLoc(); Range = BO->getRHS()->getSourceRange(); } + MsgParam = 1; } } else if (const auto *UO = dyn_cast<UnaryOperator>(Operation)) { UnaryOperator::Opcode Op = UO->getOpcode(); @@ -2177,20 +2181,27 @@ Op == UO_PostDec) { Loc = UO->getSubExpr()->getExprLoc(); Range = UO->getSubExpr()->getSourceRange(); + MsgParam = 1; } } else { Loc = Operation->getBeginLoc(); Range = Operation->getSourceRange(); } - S.Diag(Loc, diag::warn_unsafe_buffer_expression) << Range; + if (IsRelatedToDecl) + S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range; + else + S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range; } + // FIXME: rename to handleUnsafeVariable void handleFixableVariable(const VarDecl *Variable, FixItList &&Fixes) override { const auto &D = - S.Diag(Variable->getBeginLoc(), diag::warn_unsafe_buffer_variable); - D << Variable << Variable->getSourceRange(); - for (const auto &F: Fixes) + S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable); + D << Variable; + D << (Variable->getType()->isPointerType() ? 0 : 1); + D << Variable->getSourceRange(); + for (const auto &F : Fixes) D << F; } }; @@ -2489,7 +2500,7 @@ checkThrowInNonThrowingFunc(S, FD, AC); // Emit unsafe buffer usage warnings and fixits. - if (!Diags.isIgnored(diag::warn_unsafe_buffer_expression, D->getBeginLoc()) || + if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, D->getBeginLoc()) || !Diags.isIgnored(diag::warn_unsafe_buffer_variable, D->getBeginLoc())) { UnsafeBufferUsageReporter R(S); checkUnsafeBufferUsage(D, R); Index: clang/lib/Analysis/UnsafeBufferUsage.cpp =================================================================== --- clang/lib/Analysis/UnsafeBufferUsage.cpp +++ clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -680,17 +680,16 @@ // FIXME Detect overlapping FixIts. for (const auto &G : UnsafeOps.noVar) { - Handler.handleUnsafeOperation(G->getBaseStmt()); + Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/false); } for (const auto &[VD, WarningGadgets] : UnsafeOps.byVar) { auto FixItsIt = FixItsForVariable.find(VD); - if (FixItsIt != FixItsForVariable.end()) { - Handler.handleFixableVariable(VD, std::move(FixItsIt->second)); - } else { - for (const auto &G : WarningGadgets) { - Handler.handleUnsafeOperation(G->getBaseStmt()); - } + Handler.handleFixableVariable(VD, FixItsIt != FixItsForVariable.end() + ? std::move(FixItsIt->second) + : FixItList{}); + for (const auto &G : WarningGadgets) { + Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/true); } } } Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11778,12 +11778,16 @@ "this builtin requires target: loongarch64">; // Unsafe buffer usage diagnostics. -def warn_unsafe_buffer_expression : Warning< - "unchecked operation on raw buffer in expression">, - InGroup<UnsafeBufferUsage>, DefaultIgnore; def warn_unsafe_buffer_variable : Warning< - "variable %0 participates in unchecked buffer operations">, + "%0 is an %select{unsafe pointer used for buffer access|unsafe buffer that " + "does not perform bounds checks}1">, + InGroup<UnsafeBufferUsage>, DefaultIgnore; +def warn_unsafe_buffer_operation : Warning< + "%select{unsafe pointer operation|unsafe pointer arithmetic|" + "unsafe buffer access}0">, InGroup<UnsafeBufferUsage>, DefaultIgnore; +def note_unsafe_buffer_operation : Note< + "used%select{| in pointer arithmetic| in buffer access}0 here">; def err_loongarch_builtin_requires_la32 : Error< "this builtin requires target: loongarch32">; } // end of sema component. Index: clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h =================================================================== --- clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h +++ clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h @@ -31,7 +31,8 @@ using FixItList = llvm::SmallVectorImpl<FixItHint>; /// Invoked when an unsafe operation over raw pointers is found. - virtual void handleUnsafeOperation(const Stmt *Operation) = 0; + virtual void handleUnsafeOperation(const Stmt *Operation, + bool IsRelatedToDecl) = 0; /// Invoked when a fix is suggested against a variable. virtual void handleFixableVariable(const VarDecl *Variable,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits