Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -1970,6 +1970,12 @@ extern const internal::VariadicDynCastAllOfMatcher cxxNoexceptExpr; +extern const internal::VariadicDynCastAllOfMatcher + arrayInitIndexExpr; + +extern const internal::VariadicDynCastAllOfMatcher + arrayInitLoopExpr; + /// Matches array subscript expressions. /// /// Given Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -882,6 +882,10 @@ cxxNoexceptExpr; const internal::VariadicDynCastAllOfMatcher arraySubscriptExpr; +const internal::VariadicDynCastAllOfMatcher + arrayInitIndexExpr; +const internal::VariadicDynCastAllOfMatcher + arrayInitLoopExpr; const internal::VariadicDynCastAllOfMatcher cxxDefaultArgExpr; const internal::VariadicDynCastAllOfMatcher Index: clang/lib/Analysis/UnsafeBufferUsage.cpp =================================================================== --- clang/lib/Analysis/UnsafeBufferUsage.cpp +++ clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -118,12 +118,9 @@ return true; if (!match(*Node)) return false; - // To skip callables: - if (isa(Node)) - return true; return VisitorBase::TraverseStmt(Node); } - + bool shouldVisitTemplateInstantiations() const { return true; } bool shouldVisitImplicitCode() const { // TODO: let's ignore implicit code for now @@ -433,7 +430,9 @@ return stmt(arraySubscriptExpr( hasBase(ignoringParenImpCasts( anyOf(hasPointerType(), hasArrayType()))), - unless(hasIndex(integerLiteral(equals(0))))) + unless(hasIndex( + anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) + ))) .bind(ArraySubscrTag)); // clang-format on } @@ -685,6 +684,7 @@ // An auxiliary tracking facility for the fixit analysis. It helps connect // declarations to its and make sure we've covered all uses with our analysis // before we try to fix the declaration. + class DeclUseTracker { using UseSetTy = SmallSet; using DefMapTy = DenseMap; @@ -1516,7 +1516,7 @@ UnsafeBufferUsageHandler &Handler) { switch (K) { case Strategy::Kind::Span: { - if (VD->getType()->isPointerType() && VD->isLocalVarDecl()) + if (VD->getType()->isPointerType()) return fixVariableWithSpan(VD, Tracker, Ctx, Handler); return {}; } @@ -1602,6 +1602,13 @@ bool EmitFixits) { assert(D && D->getBody()); + // We do not want to visit a Lambda expression defined inside a method independently. + // Instead, it should be visited along with the outer method. + if(const auto *fd = dyn_cast(D)) { + if(fd->getParent()->isLambda() && fd->getParent()->isLocalClass()) + return; + } + WarningGadgetSets UnsafeOps; FixableGadgetSets FixablesForUnsafeVars; DeclUseTracker Tracker; @@ -1620,7 +1627,7 @@ for (auto it = FixablesForUnsafeVars.byVar.cbegin(); it != FixablesForUnsafeVars.byVar.cend();) { // FIXME: Support ParmVarDecl as well. - if (!it->first->isLocalVarDecl() || Tracker.hasUnclaimedUses(it->first)) { + if (!it->first->isLocalVarDecl() || Tracker.hasUnclaimedUses(it->first) || it->first->isInitCapture()) { it = FixablesForUnsafeVars.byVar.erase(it); } else { ++it; Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp @@ -108,3 +108,62 @@ m1(q, q, 8); } + +void unsafe_access_in_lamda() { + auto p = new int[10]; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span p" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}" + + auto my_lambda = [&](){ + p[5] = 10; + }; + + foo(p); + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:8-[[@LINE-1]]:8}:".data()" +} + +void fixits_in_lamda() { + auto p = new int[10]; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span p" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}" + + auto my_lambda = [&](){ + foo(p); + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:10}:".data()" + }; + + p[5] = 10; +} + +// FIXME: Emit fixits for lambda captured variables +void fixits_in_lambda_capture() { + auto p = new int[10]; + + auto my_lambda = [p](){ // No fixits emitted here. + foo(p); + }; + + p[5] = 10; +} + +void fixits_in_lambda_capture_reference() { + auto p = new int[10]; + + auto my_lambda = [&p](){ // No fixits emitted here. + foo(p); + }; + + p[5] = 10; +} + +void fixits_in_lambda_capture_rename() { + auto p = new int[10]; + + auto my_lambda = [x = p](){ // No fixits emitted here. + foo(x); + }; + + p[5] = 10; +} 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 @@ -163,13 +163,39 @@ // 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-note{{used in buffer access here}} + auto Lam = [p, a]() { + 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}} + }; } +auto file_scope_lambda = [](int *ptr) { + // expected-warning@-1{{'ptr' is an unsafe pointer used for buffer access}} + + ptr[5] = 10; // expected-note{{used in buffer access here}} +}; + +void testLambdaCapture() { + int a[10]; // expected-warning{{'a' is an unsafe buffer that does not perform bounds checks}} + int b[10]; // expected-warning{{'b' is an unsafe buffer that does not perform bounds checks}} + int c[10]; + + auto Lam1 = [a]() { + return a[1]; // expected-note{{used in buffer access here}} + }; + + auto Lam2 = [x = b[3]]() { // expected-note{{used in buffer access here}} + return x; + }; + + auto Lam = [x = c]() { // expected-warning{{'x' is an unsafe pointer used for buffer access}} + return x[3]; // expected-note{{used in buffer access here}} + }; +} + + typedef T_t * T_ptr_t; void testTypedefs(T_ptr_t p) {