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, DefaultIgnore; def warn_unsafe_buffer_operation : Warning< - "%select{unsafe pointer operation|unsafe pointer arithmetic|" - "unsafe buffer access|function introduces unsafe buffer manipulation}0">, - InGroup, 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, 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< 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(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(Operand)) { + const ValueDecl *ObjD = DRE->getDecl(); + IsCapturedTy IsCaptured = DRE->refersToEnclosingVariableOrCapture() + ? IsCapturedTy::Yes + : IsCapturedTy::NoOrUnclear /*no*/; + + if (const auto *VD = dyn_cast(ObjD)) + return {IsCaptured, describeVariableStorageKind(VD), VD}; + + if (const auto *BD = dyn_cast(ObjD)) + return {IsCaptured, StorageKindTy::StructuredBinding, BD}; + + // FIXME: Are there other storage kinds that we don't support? + } + + if (const auto *ME = dyn_cast(Operand)) { + const ValueDecl *MemberD = ME->getMemberDecl(); + + if (const auto *VD = dyn_cast(MemberD)) { + assert(VD->isStaticDataMember() && + "Non-static member VarDecl!"); + return {IsCapturedTy::NoOrUnclear /*unclear (FIXME!)*/, + StorageKindTy::StaticMemberVariable, VD}; + } + + if (const auto *FD = dyn_cast(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(Operand)) { + const auto *ND = dyn_cast_or_null(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(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(Operation)) { - Loc = ASE->getBase()->getExprLoc(); - Range = ASE->getBase()->getSourceRange(); - MsgParam = 2; - } else if (const auto *BO = dyn_cast(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(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(Operation)) { + } + + if (const auto *UO = dyn_cast(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(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(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/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/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/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-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-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-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 *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-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-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.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' requested here}} + foo(f(p, &p, a, a)[1]); // expected-warning{{unsafe buffer access through raw pointer return value of function 'f'}} const int **q = const_cast(&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}}