NoQ updated this revision to Diff 552560.
NoQ added a comment.
Rebase.
Make warnings a bit more verbose than before. This plays nicely with our
attempts to categorize unemitted fixits via `-mllvm -debug-only=SafeBuffers`,
but this time it doesn't make sense to make the extra information debug-only;
it makes perfect sense as part of the warning.
TODO: Some new code paths aren't covered by tests yet (captured variables,
static member variables).
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D146773/new/
https://reviews.llvm.org/D146773
Files:
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/AnalysisBasedWarnings.cpp
clang/test/SemaCXX/unsafe-buffer-usage-diag-type.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-c-linkage.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-main.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-function-attr.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp
clang/test/SemaCXX/warn-unsafe-buffer-usage-suggestions-flag.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
@@ -41,34 +41,34 @@
// 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}}
+ // expected-warning@-1{{unsafe buffer access through raw pointer parameter variable 'pp'}}
1[1[pp]], // expected-note{{used in buffer access here}}
- // expected-warning@-1{{unsafe buffer access}}
+ // expected-warning@-1{{unsafe buffer access through raw pointer parameter variable 'pp'}}
1[pp][1] // expected-note{{used in buffer access here}}
- // expected-warning@-1{{unsafe buffer access}}
+ // expected-warning@-1{{unsafe buffer access through raw pointer parameter variable 'pp'}}
);
if (p[3]) { // expected-note{{used in buffer access here}}
void * q = p;
- foo(((int*)q)[10]); // expected-warning{{unsafe buffer access}}
+ foo(((int*)q)[10]); // expected-warning{{unsafe buffer access through raw pointer 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}}
+ foo(((int*)voidPtrCall())[3], // expected-warning{{unsafe buffer access through raw pointer expression}}
+ 3[(int*)voidPtrCall()], // expected-warning{{unsafe buffer access through raw pointer expression}}
+ charPtrCall()[3], // expected-warning{{unsafe buffer access through raw pointer return value of function 'charPtrCall'}}
+ 3[charPtrCall()] // expected-warning{{unsafe buffer access through raw pointer return value of function 'charPtrCall'}}
);
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-note2{{used in buffer access here}}
- b[3][4], // expected-warning{{unsafe buffer access}}
+ b[3][4], // expected-warning{{unsafe buffer access into raw array local variable 'b'}}
// expected-note@-1{{used in buffer access here}}
- 4[b][3], // expected-warning{{unsafe buffer access}}
+ 4[b][3], // expected-warning{{unsafe buffer access into raw array local variable 'b'}}
// expected-note@-1{{used in buffer access here}}
- 4[3[b]]); // expected-warning{{unsafe buffer access}}
+ 4[3[b]]); // expected-warning{{unsafe buffer access into raw array local variable 'b'}}
// expected-note@-1{{used in buffer access here}}
// Not to warn when index is zero
@@ -108,7 +108,7 @@
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}}
+ // expected-warning@-1{{unsafe buffer access into raw array parameter variable 'b'}}
);
}
@@ -127,26 +127,26 @@
T_t * funRetTStar();
void testStructMembers(struct T * sp, struct T s, T_t * sp2, T_t s2) {
- 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}}
+ foo(sp->a[1], // expected-warning{{unsafe buffer access into raw array member variable 'a'}}
+ sp->b[1], // expected-warning{{unsafe buffer access through raw pointer member variable 'b}}
+ sp->c.a[1], // expected-warning{{unsafe buffer access into raw array member variable 'a'}}
+ sp->c.b[1], // expected-warning{{unsafe buffer access through raw pointer member variable 'b'}}
+ s.a[1], // expected-warning{{unsafe buffer access into raw array member variable 'a'}}
+ s.b[1], // expected-warning{{unsafe buffer access through raw pointer member variable 'b'}}
+ s.c.a[1], // expected-warning{{unsafe buffer access into raw array member variable 'a'}}
+ s.c.b[1], // expected-warning{{unsafe buffer access through raw pointer member variable 'b'}}
+ sp2->a[1], // expected-warning{{unsafe buffer access into raw array member variable 'a'}}
+ sp2->b[1], // expected-warning{{unsafe buffer access through raw pointer member variable 'b'}}
+ sp2->c.a[1], // expected-warning{{unsafe buffer access into raw array member variable 'a'}}
+ sp2->c.b[1], // expected-warning{{nsafe buffer access through raw pointer member variable 'b'}}
+ s2.a[1], // expected-warning{{unsafe buffer access into raw array member variable 'a'}}
+ s2.b[1], // expected-warning{{unsafe buffer access through raw pointer member variable 'b'}}
+ s2.c.a[1], // expected-warning{{unsafe buffer access into raw array member variable 'a'}}
+ s2.c.b[1], // expected-warning{{unsafe buffer access through raw pointer member variable 'b'}}
+ funRetT().a[1], // expected-warning{{unsafe buffer access into raw array member variable 'a'}}
+ funRetT().b[1], // expected-warning{{unsafe buffer access through raw pointer member variable 'b'}}
+ funRetTStar()->a[1], // expected-warning{{unsafe buffer access into raw array member variable 'a'}}
+ funRetTStar()->b[1] // expected-warning{{unsafe buffer access through raw pointer member variable 'b'}}
);
}
@@ -209,9 +209,9 @@
// 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}}
+ // expected-warning@-1{{unsafe buffer access into raw array member variable 'a'}}
p[1].b[1] // expected-note{{used in buffer access here}}
- // expected-warning@-1{{unsafe buffer access}}
+ // expected-warning@-1{{unsafe buffer access through raw pointer member variable 'b'}}
);
}
@@ -238,26 +238,25 @@
auto y = &a[0]; // expected-warning{{'y' is an unsafe pointer used for buffer access}}
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}}
+ *q + 1, 1 + *q, *q - 1, // expected-warning3{{unsafe arithmetic over raw pointer expression}}
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}}
+ getPtr() + 1, 1 + getPtr(), getPtr() - 1 // expected-warning3{{unsafe arithmetic over raw pointer return value of function 'getPtr'}}
);
p += 1; p -= 1; // expected-note2{{used in pointer arithmetic here}}
- *q += 1; *q -= 1; // expected-warning2{{unsafe pointer arithmetic}}
+ *q += 1; *q -= 1; // expected-warning2{{unsafe arithmetic over raw pointer expression}}
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{{unsafe buffer access}}
- // FIXME: expected note@-1{{in instantiation of function template specialization 'f<int *, 10>' requested here}}
+ foo(f(p, &p, a, a)[1]); // expected-warning{{unsafe buffer access through raw pointer return value of function 'f<int *, 10>'}}
const int **q = const_cast<const int **>(&p);
- testPointerArithmetic(p, q, p); //FIXME: expected note{{in instantiation of}}
+ testPointerArithmetic(p, q, p);
}
void testPointerToMember() {
@@ -270,7 +269,7 @@
int * S_t::* q = &S_t::y;
foo(S.*p,
- (S.*q)[1]); // expected-warning{{unsafe buffer access}}
+ (S.*q)[1]); // expected-warning{{unsafe buffer access through raw pointer expression}}
}
// test that nested callable definitions are scanned only once
@@ -362,9 +361,9 @@
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}}
+ // expected-warning@-1{{unsafe buffer access into raw array local variable 'cArr'}}
auto cPtr = cArr[1][2]; // expected-note{{used in buffer access here}}
- // expected-warning@-1{{unsafe buffer access}}
+ // expected-warning@-1{{unsafe buffer access into raw array local variable 'cArr'}}
foo(cPtr);
// Typdefs
@@ -372,7 +371,7 @@
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}}
+ return cArr[0][1]; // expected-warning{{unsafe buffer access into raw array local variable 'cArr'}}
}
void testArrayPtrArithmetic(int x[]) { // expected-warning{{'x' is an unsafe pointer used for buffer access}}
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-suggestions-flag.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-suggestions-flag.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-suggestions-flag.cpp
@@ -56,11 +56,11 @@
x += 5; // \
// ON-note {{used in pointer arithmetic here}} \
- // OFF-warning{{unsafe pointer arithmetic}} \
+ // OFF-warning{{unsafe arithmetic over raw pointer parameter variable 'x'}} \
// OFF-note {{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
bar(x); // \
- // ON-warning{{function introduces unsafe buffer manipulation}} \
- // OFF-warning{{function introduces unsafe buffer manipulation}} \
+ // ON-warning{{function call introduces unsafe buffer manipulation over expression}} \
+ // OFF-warning{{function call introduces unsafe buffer manipulation over expression}} \
// OFF-note {{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
}
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp
@@ -184,7 +184,7 @@
local = ptr;
local++; // expected-note{{used in pointer arithmetic here}}
- (local = ptr) += 5; // expected-warning{{unsafe pointer arithmetic}}
+ (local = ptr) += 5; // expected-warning{{unsafe arithmetic over raw pointer expression}}
}
void check_rhs_fix() {
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-function-attr.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-function-attr.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-function-attr.cpp
@@ -19,11 +19,11 @@
void deprecatedFunction4(int z);
void caller(int z, int* x, int size, char c[]) {
- deprecatedFunction3(); // expected-warning{{function introduces unsafe buffer manipulation}}
- deprecatedFunction4(z); // expected-warning{{function introduces unsafe buffer manipulation}}
+ deprecatedFunction3(); // expected-warning{{function call introduces unsafe buffer manipulation over expression}}
+ deprecatedFunction4(z); // expected-warning{{function call introduces unsafe buffer manipulation over expression}}
someFunction();
- overloading(x); // expected-warning{{function introduces unsafe buffer manipulation}}
+ overloading(x); // expected-warning{{function call introduces unsafe buffer manipulation over expression}}
overloading(x, size);
overloading(c);
}
@@ -47,12 +47,12 @@
void foo<int *>(int *t) {}
void caller1(int *p, int *q) {
- testVariadics(p, q); // expected-warning{{function introduces unsafe buffer manipulation}}
- adder(p, q); // expected-warning{{function introduces unsafe buffer manipulation}}
-
+ testVariadics(p, q); // expected-warning{{function call introduces unsafe buffer manipulation over expression}}
+ adder(p, q); // expected-warning{{function call introduces unsafe buffer manipulation over expression}}
+
int x;
foo(x);
- foo(&x); // expected-warning{{function introduces unsafe buffer manipulation}}
+ foo(&x); // expected-warning{{function call introduces unsafe buffer manipulation over expression}}
}
// Test virtual functions
@@ -75,13 +75,13 @@
void testInheritance() {
DerivedClass DC;
DC.func();
- DC.func1(); // expected-warning{{function introduces unsafe buffer manipulation}}
-
+ DC.func1(); // expected-warning{{function call introduces unsafe buffer manipulation over expression}}
+
BaseClass *BC;
- BC->func(); // expected-warning{{function introduces unsafe buffer manipulation}}
+ BC->func(); // expected-warning{{function call introduces unsafe buffer manipulation over expression}}
BC->func1();
-
+
BC = &DC;
- BC->func(); // expected-warning{{function introduces unsafe buffer manipulation}}
+ BC->func(); // expected-warning{{function call introduces unsafe buffer manipulation over expression}}
BC->func1();
}
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp
@@ -113,12 +113,15 @@
// The following two unsupported cases are not specific to
// parm-fixits. Adding them here in case they get forgotten.
-void isArrayDecayToPointerUPC(int a[][10], int (*b)[10]) {
-// expected-warning@-1{{'a' is an unsafe pointer used for buffer access}}
-// expected-warning@-2{{'b' is an unsafe pointer used for buffer access}}
+void isArrayDecayToPointerUPC(int a[][10], int (*b)[10]) { // \
+ // expected-warning{{'a' is an unsafe pointer used for buffer access}} \
+ // expected-warning{{'b' is an unsafe pointer used for buffer access}}
int tmp;
- tmp = a[5][5] + b[5][5]; // expected-warning2{{unsafe buffer access}} expected-note2{{used in buffer access here}}
+ tmp = a[5][5] + b[5][5]; // \
+ // expected-warning{{unsafe buffer access into raw array parameter variable 'a'}} \
+ // expected-warning{{unsafe buffer access into raw array parameter variable 'b'}} \
+ // expected-note2{{used in buffer access here}}
}
// parameter having default values:
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-main.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-main.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-main.cpp
@@ -9,5 +9,5 @@
int main(int argc, char *argv[]) { // expected-warning{{'argv' is an unsafe pointer used for buffer access}}
char tmp;
tmp = argv[5][5]; // expected-note{{used in buffer access here}} \
- expected-warning{{unsafe buffer access}}
+ // expected-warning{{unsafe buffer access through raw pointer parameter variable 'argv'}}
}
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp
@@ -95,6 +95,6 @@
void test_struct_claim_use() {
auto [x] = f();
- x[6] = 8; // expected-warning{{unsafe buffer access}}
- x++; // expected-warning{{unsafe pointer arithmetic}}
+ x[6] = 8; // expected-warning{{unsafe buffer access through raw pointer structured binding 'x'}}
+ x++; // expected-warning{{unsafe arithmetic over raw pointer structured binding 'x'}}
}
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-c-linkage.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage-c-linkage.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage-c-linkage.cpp
@@ -2,7 +2,7 @@
extern "C" {
void foo(int *ptr) {
- ptr[5] = 10; // expected-warning{{unsafe buffer access}}
+ ptr[5] = 10; // expected-warning{{unsafe buffer access through raw pointer parameter variable 'ptr'}}
}
void bar(int *ptr);
@@ -13,12 +13,12 @@
}
void bar(int *ptr) {
- ptr[5] = 10; // expected-warning{{unsafe buffer access}}
+ ptr[5] = 10; // expected-warning{{unsafe buffer access through raw pointer parameter variable 'ptr'}}
}
void call_foo(int *p) {
foo(p);
struct c_struct str;
- str.name[7] = 9; // expected-warning{{unsafe buffer access}}
+ str.name[7] = 9; // expected-warning{{unsafe buffer access through raw pointer member variable 'name'}}
bar(p);
}
Index: clang/test/SemaCXX/unsafe-buffer-usage-diag-type.cpp
===================================================================
--- clang/test/SemaCXX/unsafe-buffer-usage-diag-type.cpp
+++ clang/test/SemaCXX/unsafe-buffer-usage-diag-type.cpp
@@ -48,7 +48,7 @@
void testRefersPtrStructFieldDecl(int i) {
Struct1 s1;
- s1.ptr + i; // expected-warning{{unsafe pointer arithmetic}}
+ s1.ptr + i; // expected-warning{{unsafe arithmetic over raw pointer member variable 'ptr'}}
s1.ptr[i]; // expected-warning{{unsafe buffer access}}
}
@@ -67,7 +67,7 @@
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 arithmetic over raw pointer member variable 'ptr'}}
ptr[i]; // expected-warning{{unsafe buffer access}}
}
};
@@ -104,6 +104,6 @@
int * return_ptr();
void testNoDeclRef(int i) {
- return_ptr() + i; // expected-warning{{unsafe pointer arithmetic}}
+ return_ptr() + i; // expected-warning{{unsafe arithmetic over raw pointer return value of function 'return_ptr'}}
return_ptr()[i]; // expected-warning{{unsafe buffer access}}
}
Index: clang/lib/Sema/AnalysisBasedWarnings.cpp
===================================================================
--- clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2210,57 +2210,259 @@
return AllVars;
}
-public:
- UnsafeBufferUsageReporter(Sema &S, bool SuggestSuggestions)
- : S(S), SuggestSuggestions(SuggestSuggestions) {}
+ // These enums map to diagnostic %select directives.
+ enum class OperationKindTy: unsigned {
+ AnyOperation = 0,
+ PointerArithmetic = 1,
+ BufferAccessThroughPointer = 2,
+ BufferAccessIntoArray = 3,
+ CallToUnsafeFunction = 4
+ };
- void handleUnsafeOperation(const Stmt *Operation,
- bool IsRelatedToDecl) override {
+ enum class IsCapturedTy: unsigned {
+ NoOrUnclear = 0,
+ Yes = 1
+ };
+
+ enum class LayoutKindTy: unsigned {
+ Unclear = 0,
+ Pointer = 1,
+ Array = 2,
+ };
+
+ enum class StorageKindTy: unsigned {
+ AnyExpression = 0,
+ AnyVariable = 1,
+ LocalVariable = 2,
+ ParameterVariable = 3,
+ StaticLocalVariable = 4,
+ GlobalVariable = 5,
+ MemberVariable = 6,
+ StaticMemberVariable = 7,
+ StructuredBinding = 8,
+ FunctionReturnValue = 9
+ };
+
+ struct OperandStorageWarningInfo {
+ IsCapturedTy IsCaptured;
+ StorageKindTy StorageKind;
+ const NamedDecl *Object;
+ };
+
+ struct OperandWarningInfo {
+ LayoutKindTy LayoutKind;
+ OperandStorageWarningInfo StorageInfo;
SourceLocation Loc;
SourceRange Range;
- unsigned MsgParam = 0;
+ };
+
+ struct OperationWarningInfo {
+ OperationKindTy OperationKind;
+ OperandWarningInfo OperandInfo;
+ };
+
+ StorageKindTy describeVariableStorageKind(const VarDecl *VD) {
+ if (VD->isLocalVarDecl())
+ return StorageKindTy::LocalVariable;
+
+ if (isa<ParmVarDecl>(VD))
+ return StorageKindTy::ParameterVariable;
+
+ if (VD->isStaticLocal())
+ return StorageKindTy::StaticLocalVariable;
+
+ if (VD->hasGlobalStorage())
+ return StorageKindTy::GlobalVariable;
+
+ // FIXME: Implement more cases?
+ // What about __block variables?
+ // Thread locals?
+ return StorageKindTy::AnyVariable;
+ }
+
+ OperandStorageWarningInfo dontDescribeOperandStorage() {
+ return {IsCapturedTy::NoOrUnclear /*unclear*/, StorageKindTy::AnyExpression,
+ nullptr /*no object declaration*/};
+ }
+
+ OperandStorageWarningInfo describeOperandStorage(const Expr *Operand) {
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(Operand)) {
+ const ValueDecl *ObjD = DRE->getDecl();
+ IsCapturedTy IsCaptured = DRE->refersToEnclosingVariableOrCapture()
+ ? IsCapturedTy::Yes
+ : IsCapturedTy::NoOrUnclear /*no*/;
+
+ if (const auto *VD = dyn_cast<VarDecl>(ObjD))
+ return {IsCaptured, describeVariableStorageKind(VD), VD};
+
+ if (const auto *BD = dyn_cast<BindingDecl>(ObjD))
+ return {IsCaptured, StorageKindTy::StructuredBinding, BD};
+
+ // FIXME: Are there other storage kinds that we don't support?
+ }
+
+ if (const auto *ME = dyn_cast<MemberExpr>(Operand)) {
+ const ValueDecl *MemberD = ME->getMemberDecl();
+
+ if (const auto *VD = dyn_cast<VarDecl>(MemberD)) {
+ assert(VD->isStaticDataMember() &&
+ "Non-static member VarDecl!");
+ return {IsCapturedTy::NoOrUnclear /*unclear (FIXME!)*/,
+ StorageKindTy::StaticMemberVariable, VD};
+ }
+
+ if (const auto *FD = dyn_cast<FieldDecl>(MemberD))
+ return {IsCapturedTy::NoOrUnclear /*unclear (FIXME!)*/,
+ StorageKindTy::MemberVariable, FD};
+
+ // FIXME: Documentation says that the other two cases are:
+ // * a CXXMethodDecl (producing pointer-to-member-method) and
+ // * an EnumConstantDecl (enum value).
+ // They probably can't appear here, make this an assert?
+ // Are we sure there aren't other cases?
+ }
+
+ if (const auto *CE = dyn_cast<CallExpr>(Operand)) {
+ const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl());
+ return {IsCapturedTy::NoOrUnclear /*no*/,
+ StorageKindTy::FunctionReturnValue, ND};
+ }
+
+ // Multi-dimensional case.
+ // FIXME: Say it out loud, and then explain if it's array of arrays or
+ // array of pointers etc.
+ if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operand)) {
+ return describeOperandStorage(ASE->getBase()->IgnoreParenImpCasts());
+ }
+
+ // Default behavior: say nothing.
+ return dontDescribeOperandStorage();
+ }
+
+ OperandWarningInfo dontDescribeOperand(const Stmt *Operation) {
+ return {
+ LayoutKindTy::Unclear,
+ dontDescribeOperandStorage(),
+ Operation->getBeginLoc(),
+ Operation->getSourceRange()
+ };
+ }
+
+ OperandWarningInfo describeOperand(const Expr *Operand) {
+ Operand = Operand->IgnoreParenImpCasts();
+
+ LayoutKindTy LayoutKind = Operand->getType()->isAnyPointerType()
+ ? LayoutKindTy::Pointer
+ : LayoutKindTy::Array;
+ return {
+ LayoutKind,
+ describeOperandStorage(Operand),
+ Operand->getBeginLoc(),
+ Operand->getSourceRange()
+ };
+ }
+
+ OperationWarningInfo describeOperation(const Stmt *Operation) {
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)) {
+ OperandWarningInfo OpI = describeOperand(ASE->getBase());
+ switch (OpI.LayoutKind) {
+ case LayoutKindTy::Unclear:
+ llvm_unreachable("Operand layout actively described as unclear!");
+ case LayoutKindTy::Pointer:
+ return {OperationKindTy::BufferAccessThroughPointer, OpI};
+ case LayoutKindTy::Array:
+ return {OperationKindTy::BufferAccessIntoArray, OpI};
+ }
+ }
+
+ if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
BinaryOperator::Opcode Op = BO->getOpcode();
if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
Op == BO_SubAssign) {
if (BO->getRHS()->getType()->isIntegerType()) {
- Loc = BO->getLHS()->getExprLoc();
- Range = BO->getLHS()->getSourceRange();
+ return {OperationKindTy::PointerArithmetic,
+ describeOperand(BO->getLHS())};
} else {
- Loc = BO->getRHS()->getExprLoc();
- Range = BO->getRHS()->getSourceRange();
+ return {OperationKindTy::PointerArithmetic,
+ describeOperand(BO->getRHS())};
}
- MsgParam = 1;
}
- } else if (const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
+ }
+
+ if (const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
UnaryOperator::Opcode Op = UO->getOpcode();
if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
Op == UO_PostDec) {
- Loc = UO->getSubExpr()->getExprLoc();
- Range = UO->getSubExpr()->getSourceRange();
- MsgParam = 1;
- }
- } else {
- if (isa<CallExpr>(Operation)) {
- // note_unsafe_buffer_operation doesn't have this mode yet.
- assert(!IsRelatedToDecl && "Not implemented yet!");
- MsgParam = 3;
+ return {OperationKindTy::PointerArithmetic,
+ describeOperand(UO->getSubExpr())};
}
- Loc = Operation->getBeginLoc();
- Range = Operation->getSourceRange();
}
+
+ if (isa<CallExpr>(Operation)) {
+ return {OperationKindTy::CallToUnsafeFunction,
+ dontDescribeOperand(Operation)};
+ }
+
+ // Every time this is reached, it means we needed to do better above.
+ return {OperationKindTy::AnyOperation, dontDescribeOperand(Operation)};
+ }
+
+public:
+ UnsafeBufferUsageReporter(Sema &S, bool SuggestSuggestions)
+ : S(S), SuggestSuggestions(SuggestSuggestions) {}
+
+ void handleUnsafeOperation(const Stmt *Operation,
+ bool IsRelatedToDecl) override {
+ OperationWarningInfo Info = describeOperation(Operation);
+
if (IsRelatedToDecl) {
assert(!SuggestSuggestions &&
"Variables blamed for unsafe buffer usage without suggestions!");
- S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;
+ assert(Info.OperationKind != OperationKindTy::CallToUnsafeFunction &&
+ "Not implemented yet!");
+
+ unsigned OperationKind;
+ switch (Info.OperationKind) {
+ case OperationKindTy::AnyOperation:
+ OperationKind = 0;
+ break;
+ case OperationKindTy::PointerArithmetic:
+ OperationKind = 1;
+ break;
+ case OperationKindTy::BufferAccessThroughPointer:
+ OperationKind = 2;
+ break;
+ case OperationKindTy::BufferAccessIntoArray:
+ OperationKind = 2; // We don't have a separate mode for this.
+ break;
+ case OperationKindTy::CallToUnsafeFunction:
+ llvm_unreachable("Not implemented yet!");
+ }
+
+ S.Diag(Info.OperandInfo.Loc, diag::note_unsafe_buffer_operation)
+ << OperationKind << Info.OperandInfo.Range;
} else {
- S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range;
+ // Introduce a scope so that the warning got emitted first.
+ {
+ auto D =
+ S.Diag(Info.OperandInfo.Loc, diag::warn_unsafe_buffer_operation);
+ D << (unsigned)Info.OperationKind
+ << (unsigned)Info.OperandInfo.StorageInfo.IsCaptured
+ << (unsigned)Info.OperandInfo.LayoutKind
+ << (unsigned)Info.OperandInfo.StorageInfo.StorageKind;
+ if (Info.OperandInfo.StorageInfo.Object) {
+ D << 1 /*provide the object name*/
+ << Info.OperandInfo.StorageInfo.Object;
+
+ } else {
+ D << 0 /*don't provide object name*/;
+ }
+ D << Info.OperandInfo.Range;
+ }
+
if (SuggestSuggestions) {
- S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled);
+ S.Diag(Info.OperandInfo.Loc,
+ diag::note_safe_buffer_usage_suggestions_disabled);
}
}
}
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11902,9 +11902,27 @@
"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|function introduces unsafe buffer manipulation}0">,
- InGroup<UnsafeBufferUsage>, DefaultIgnore;
+ "%select{"
+ "unsafe buffer operation in|"
+ "unsafe arithmetic over|"
+ "unsafe buffer access through|"
+ "unsafe buffer access into|"
+ "function call introduces unsafe buffer manipulation over"
+ "}0%select{"
+ "|" // Either not captured or unclear.
+ " captured"
+ "}1 %select{|raw pointer |raw array }2%select{"
+ "expression|"
+ "variable|"
+ "local variable|"
+ "parameter variable|"
+ "static local variable|"
+ "global variable|"
+ "member variable|"
+ "static member variable|"
+ "structured binding|"
+ "return value of function"
+ "}3%select{| %5}4">, InGroup<UnsafeBufferUsage>, DefaultIgnore;
def note_unsafe_buffer_operation : Note<
"used%select{| in pointer arithmetic| in buffer access}0 here">;
def note_unsafe_buffer_variable_fixit_group : Note<
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits