https://github.com/ziqingluo-90 updated https://github.com/llvm/llvm-project/pull/191931
>From 65abbbd4e682d67ee4fe642f8898cb5bb52ed6f6 Mon Sep 17 00:00:00 2001 From: Ziqing Luo <[email protected]> Date: Mon, 13 Apr 2026 17:26:04 -0700 Subject: [PATCH 1/2] [SSAF][UnsafeBufferUsage] Remove UnsafeBufferUsageExtractor.h - Removed UnsafeBufferUsageExtractor.h - Registered UnsafeBufferUsageExtractor - Changed unit tests to enable the extractor with `HandleTranslationUnit` - Fixed bugs in `UnsafeBufferUsageExtractor::HandleTranslationUnit` --- .../UnsafeBufferUsageExtractor.h | 35 -- .../SSAFBuiltinForceLinker.h | 5 + .../UnsafeBufferUsageExtractor.cpp | 142 ++++---- .../UnsafeBufferUsageTest.cpp | 313 ++++++++++-------- 4 files changed, 258 insertions(+), 237 deletions(-) delete mode 100644 clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h deleted file mode 100644 index 13d4e18b4e81f..0000000000000 --- a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h +++ /dev/null @@ -1,35 +0,0 @@ -//===- UnsafeBufferUsageExtractor.h -----------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGEBUILDER_H -#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGEBUILDER_H - -#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h" -#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h" -#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h" -#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h" -#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryExtractor.h" -#include "llvm/Support/Error.h" -#include <memory> - -namespace clang::ssaf { -class UnsafeBufferUsageTUSummaryExtractor : public TUSummaryExtractor { -public: - UnsafeBufferUsageTUSummaryExtractor(TUSummaryBuilder &Builder) - : TUSummaryExtractor(Builder) {} - - EntityId addEntity(EntityName EN) { return SummaryBuilder.addEntity(EN); } - - std::unique_ptr<UnsafeBufferUsageEntitySummary> - extractEntitySummary(const Decl *Contributor, ASTContext &Ctx, - llvm::Error &Error); - - void HandleTranslationUnit(ASTContext &Ctx) override; -}; -} // namespace clang::ssaf - -#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGEBUILDER_H diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h b/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h index 2030dc8a12030..916ef1ce783c4 100644 --- a/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h +++ b/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h @@ -36,6 +36,11 @@ extern volatile int UnsafeBufferUsageSSAFJSONFormatAnchorSource; [[maybe_unused]] static int UnsafeBufferUsageSSAFJSONFormatAnchorDestination = UnsafeBufferUsageSSAFJSONFormatAnchorSource; +extern volatile int UnsafeBufferUsageTUSummaryExtractorAnchorSource; +[[maybe_unused]] static int + UnsafeBufferUsageTUSummaryExtractorAnchorDestination = + UnsafeBufferUsageTUSummaryExtractorAnchorSource; + // This anchor is used to force the linker to link the CallGraphExtractor. extern volatile int CallGraphExtractorAnchorSource; [[maybe_unused]] static int CallGraphExtractorAnchorDestination = diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp index c412855028efb..72944bd0be323 100644 --- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp +++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp @@ -6,7 +6,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DynamicRecursiveASTVisitor.h" @@ -16,6 +15,9 @@ #include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h" #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h" #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h" +#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/ExtractorRegistry.h" +#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h" +#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryExtractor.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Error.h" #include <memory> @@ -24,8 +26,8 @@ namespace { using namespace clang; using namespace ssaf; -static llvm::Error makeCreateEntityNameError(const NamedDecl *FailedDecl, - ASTContext &Ctx) { +llvm::Error makeCreateEntityNameError(const NamedDecl *FailedDecl, + ASTContext &Ctx) { std::string LocStr = FailedDecl->getSourceRange().getBegin().printToString( Ctx.getSourceManager()); return llvm::createStringError( @@ -33,19 +35,8 @@ static llvm::Error makeCreateEntityNameError(const NamedDecl *FailedDecl, FailedDecl->getNameAsString().c_str(), LocStr.c_str()); } -static llvm::Error makeAddEntitySummaryError(const NamedDecl *FailedContributor, - ASTContext &Ctx) { - std::string LocStr = - FailedContributor->getSourceRange().getBegin().printToString( - Ctx.getSourceManager()); - return llvm::createStringError( - "failed to add entity summary for contributor %s declared at %s", - FailedContributor->getNameAsString().c_str(), LocStr.c_str()); -} - Expected<EntityPointerLevelSet> buildEntityPointerLevels(std::set<const Expr *> &&UnsafePointers, - UnsafeBufferUsageTUSummaryExtractor &Extractor, ASTContext &Ctx, std::function<EntityId(EntityName)> AddEntity) { EntityPointerLevelSet Result{}; @@ -71,7 +62,6 @@ buildEntityPointerLevels(std::set<const Expr *> &&UnsafePointers, return AllErrors; return Result; } -} // namespace static std::set<const Expr *> findUnsafePointersInContributor(const Decl *D) { if (isa<FunctionDecl>(D) || isa<VarDecl>(D)) @@ -86,78 +76,84 @@ static std::set<const Expr *> findUnsafePointersInContributor(const Decl *D) { } return {}; } +} // namespace -std::unique_ptr<UnsafeBufferUsageEntitySummary> -UnsafeBufferUsageTUSummaryExtractor::extractEntitySummary( - const Decl *Contributor, ASTContext &Ctx, llvm::Error &Error) { - auto AddEntity = [this](EntityName EN) { return addEntity(EN); }; - Expected<EntityPointerLevelSet> EPLs = buildEntityPointerLevels( - findUnsafePointersInContributor(Contributor), *this, Ctx, AddEntity); - - if (EPLs) - return std::make_unique<UnsafeBufferUsageEntitySummary>( - UnsafeBufferUsageEntitySummary(std::move(*EPLs))); - Error = EPLs.takeError(); - return nullptr; -} +class clang::ssaf::UnsafeBufferUsageTUSummaryExtractor + : public TUSummaryExtractor { +public: + UnsafeBufferUsageTUSummaryExtractor(TUSummaryBuilder &Builder) + : TUSummaryExtractor(Builder) {} -void UnsafeBufferUsageTUSummaryExtractor::HandleTranslationUnit( - ASTContext &Ctx) { + EntityId addEntity(EntityName EN) { return SummaryBuilder.addEntity(EN); } - // FIXME: I suppose finding contributor Decls is commonly needed by all/many - // extractors - class ContributorFinder : public DynamicRecursiveASTVisitor { - public: - std::vector<const NamedDecl *> Contributors; + Expected<std::unique_ptr<UnsafeBufferUsageEntitySummary>> + extractEntitySummary(const Decl *Contributor, ASTContext &Ctx) { + auto AddEntity = [this](EntityName EN) { return addEntity(EN); }; + Expected<EntityPointerLevelSet> EPLs = buildEntityPointerLevels( + findUnsafePointersInContributor(Contributor), Ctx, AddEntity); - bool VisitFunctionDecl(FunctionDecl *D) override { - Contributors.push_back(D); - return true; - } + if (EPLs) + return std::make_unique<UnsafeBufferUsageEntitySummary>( + UnsafeBufferUsageEntitySummary(std::move(*EPLs))); + return EPLs.takeError(); + } - bool VisitRecordDecl(RecordDecl *D) override { - Contributors.push_back(D); - return true; - } + void HandleTranslationUnit(ASTContext &Ctx) override { - bool VisitVarDecl(VarDecl *D) override { - DeclContext *DC = D->getDeclContext(); + // FIXME: I suppose finding contributor Decls is commonly needed by all/many + // extractors + class ContributorFinder : public DynamicRecursiveASTVisitor { + public: + std::vector<const NamedDecl *> Contributors; - if (DC->isFileContext() || DC->isNamespace()) + bool VisitFunctionDecl(FunctionDecl *D) override { Contributors.push_back(D); - return false; - } - } ContributorFinder; + return true; + } - ContributorFinder.VisitTranslationUnitDecl(Ctx.getTranslationUnitDecl()); + bool VisitRecordDecl(RecordDecl *D) override { + Contributors.push_back(D); + return true; + } - llvm::Error Errors = llvm::ErrorSuccess(); - auto addError = [&Errors](llvm::Error Err) { - Errors = llvm::joinErrors(std::move(Errors), std::move(Err)); - }; + bool VisitVarDecl(VarDecl *D) override { + DeclContext *DC = D->getDeclContext(); - for (auto *CD : ContributorFinder.Contributors) { - llvm::Error Error = llvm::ErrorSuccess(); - auto EntitySummary = extractEntitySummary(CD, Ctx, Error); + if (DC->isFileContext() || DC->isNamespace()) + Contributors.push_back(D); + return true; + } + } ContributorFinder; - if (Error) - addError(std::move(Error)); - if (EntitySummary->empty()) - continue; + ContributorFinder.VisitTranslationUnitDecl(Ctx.getTranslationUnitDecl()); - auto ContributorName = getEntityName(CD); + ContributorFinder.TraverseAST(Ctx); + for (auto *CD : ContributorFinder.Contributors) { + auto EntitySummary = extractEntitySummary(CD, Ctx); - if (!ContributorName) { - addError(makeCreateEntityNameError(CD, Ctx)); - continue; - } + if (!EntitySummary) + llvm::reportFatalInternalError(EntitySummary.takeError()); + assert(*EntitySummary); + if ((*EntitySummary)->empty()) + continue; + + auto ContributorName = getEntityName(CD); - auto [EntitySummaryPtr, Success] = SummaryBuilder.addSummary( - addEntity(*ContributorName), std::move(EntitySummary)); + if (!ContributorName) + llvm::reportFatalInternalError(makeCreateEntityNameError(CD, Ctx)); - if (!Success) - addError(makeAddEntitySummaryError(CD, Ctx)); + auto [Ignored, InsertionSucceeded] = SummaryBuilder.addSummary( + addEntity(*ContributorName), std::move(*EntitySummary)); + + assert(InsertionSucceeded && "duplicated contributor extraction"); + } } - // FIXME: handle errors! - llvm::consumeError(std::move(Errors)); -} +}; + +// NOLINTNEXTLINE(misc-use-internal-linkage) +volatile int UnsafeBufferUsageTUSummaryExtractorAnchorSource = 0; + +static clang::ssaf::TUSummaryExtractorRegistry::Add< + ssaf::UnsafeBufferUsageTUSummaryExtractor> + RegisterExtractor(UnsafeBufferUsageEntitySummary::Name, + "The TUSummaryExtractor for unsafe buffer pointers"); \ No newline at end of file diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp index d2c513b7c70a2..59c2cd38ffacf 100644 --- a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp +++ b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp @@ -11,20 +11,23 @@ #include "clang/AST/DynamicRecursiveASTVisitor.h" #include "clang/Frontend/ASTUnit.h" #include "clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h" -#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h" +#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h" #include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h" #include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h" #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h" #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityIdTable.h" #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h" +#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/ExtractorRegistry.h" #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummary.h" #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h" +#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryExtractor.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Error.h" #include "llvm/Testing/Support/Error.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include <initializer_list> #include <memory> #include <optional> @@ -33,7 +36,6 @@ using namespace ssaf; using testing::UnorderedElementsAre; namespace { - template <typename SomeDecl = NamedDecl> const SomeDecl *findDeclByName(StringRef Name, ASTContext &Ctx) { class NamedDeclFinder : public DynamicRecursiveASTVisitor { @@ -68,52 +70,82 @@ class UnsafeBufferUsageTest : public TestFixture { protected: TUSummary TUSum; TUSummaryBuilder Builder; - UnsafeBufferUsageTUSummaryExtractor Extractor; + std::unique_ptr<TUSummaryExtractor> Extractor; std::unique_ptr<ASTUnit> AST; UnsafeBufferUsageTest() : TUSum(BuildNamespace(BuildNamespaceKind::CompilationUnit, "Mock.cpp")), - Builder(TUSum), Extractor(Builder) {} + Builder(TUSum), Extractor(nullptr) {} - template <typename ContributorDecl = NamedDecl> - std::unique_ptr<UnsafeBufferUsageEntitySummary> - setUpTest(StringRef Code, StringRef ContributorName) { + bool setUpTest(StringRef Code) { AST = tooling::buildASTFromCodeWithArgs( Code, {"-Wno-unused-value", "-Wno-int-to-pointer-cast"}); - const auto *ContributorDefn = - findDeclByName<ContributorDecl>(ContributorName, AST->getASTContext()); + for (auto &E : clang::ssaf::TUSummaryExtractorRegistry::entries()) { + if (E.getName() == UnsafeBufferUsageEntitySummary::Name) { + Extractor = E.instantiate(Builder); + break; + } + } + + if (!Extractor) { + ADD_FAILURE() << "failed to find UnsafeBufferUsageTUSummaryExtractor"; + return false; + } + Extractor->HandleTranslationUnit(AST->getASTContext()); + return true; + } - if (!ContributorDefn) + template <typename ContributorDecl = NamedDecl> + const UnsafeBufferUsageEntitySummary * + getEntitySummary(StringRef ContributorEntityName) { + auto *ContributorDefn = findDeclByName<ContributorDecl>( + ContributorEntityName, AST->getASTContext()); + + if (!ContributorDefn) { + ADD_FAILURE() << "failed to find Decl of \"" << ContributorEntityName + << "\""; return nullptr; + } std::optional<EntityName> EN = getEntityName(ContributorDefn); - if (!EN) + if (!EN) { + ADD_FAILURE() << "failed to get EntityName for contributor \"" + << ContributorEntityName << "\""; return nullptr; + } - llvm::Error Error = llvm::ErrorSuccess(); - auto Sum = Extractor.extractEntitySummary(ContributorDefn, - AST->getASTContext(), Error); + EntityId ContributorEntityId = Builder.addEntity(*EN); + auto &TUSumData = getData(TUSum); + auto EntitiesSumIter = + TUSumData.find(UnsafeBufferUsageEntitySummary::summaryName()); - if (Error) { - llvm::consumeError(std::move(Error)); + // If none entity summary was collected, it may not be an entry in + // `TUSumData`: + if (EntitiesSumIter == TUSumData.end()) return nullptr; - } - return Sum; + + auto EntitySumIter = EntitiesSumIter->second.find(ContributorEntityId); + + // If entity summary is empty, it may not exist: + if (EntitySumIter == EntitiesSumIter->second.end()) + return nullptr; + return static_cast<const UnsafeBufferUsageEntitySummary *>( + EntitySumIter->second.get()); } std::optional<EntityId> getEntityId(StringRef Name) { if (const auto *D = findDeclByName(Name, AST->getASTContext())) if (auto EntityName = getEntityName(D)) - return Extractor.addEntity(*EntityName); + return Builder.addEntity(*EntityName); return std::nullopt; } std::optional<EntityId> getEntityIdForReturn(StringRef FunName) { if (const auto *D = findFnByName(FunName, AST->getASTContext())) if (auto EntityName = getEntityNameForReturn(D)) - return Extractor.addEntity(*EntityName); + return Builder.addEntity(*EntityName); return std::nullopt; } @@ -153,8 +185,8 @@ getSubsetOf(const EntityPointerLevelSet &Set, EntityId Entity) { } TEST_F(UnsafeBufferUsageTest, EntityPointerLevelComparison) { - EntityId E1 = Extractor.addEntity({"c:@F@foo", "", {}}); - EntityId E2 = Extractor.addEntity({"c:@F@bar", "", {}}); + EntityId E1 = Builder.addEntity({"c:@F@foo", "", {}}); + EntityId E2 = Builder.addEntity({"c:@F@bar", "", {}}); auto P1 = buildEntityPointerLevel(E1, 2); auto P2 = buildEntityPointerLevel(E1, 2); @@ -172,9 +204,9 @@ TEST_F(UnsafeBufferUsageTest, EntityPointerLevelComparison) { } TEST_F(UnsafeBufferUsageTest, UnsafeBufferUsageEntityPointerLevelSetTest) { - EntityId E1 = Extractor.addEntity({"c:@F@foo", "", {}}); - EntityId E2 = Extractor.addEntity({"c:@F@bar", "", {}}); - EntityId E3 = Extractor.addEntity({"c:@F@baz", "", {}}); + EntityId E1 = Builder.addEntity({"c:@F@foo", "", {}}); + EntityId E2 = Builder.addEntity({"c:@F@bar", "", {}}); + EntityId E3 = Builder.addEntity({"c:@F@baz", "", {}}); auto P1 = buildEntityPointerLevel(E1, 1); auto P2 = buildEntityPointerLevel(E1, 2); @@ -195,13 +227,14 @@ TEST_F(UnsafeBufferUsageTest, UnsafeBufferUsageEntityPointerLevelSetTest) { ////////////////////////////////////////////////////////////// TEST_F(UnsafeBufferUsageTest, UnsafeBufferUsageSerializeTest) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int ***p, int ****q, int x) { p[5][5][5]; q[5][5][5][5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); ASSERT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U}, {"p", 2U}, @@ -241,40 +274,43 @@ TEST_F(UnsafeBufferUsageTest, UnsafeBufferUsageSerializeTest) { ////////////////////////////////////////////////////////////// TEST_F(UnsafeBufferUsageTest, SimpleFunctionWithUnsafePointer) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int *p) { p[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U}})); } TEST_F(UnsafeBufferUsageTest, PointerArithmetic) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int *p, int *q) { *(p + 5); *(q - 3); } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U}, {"q", 1U}})); } TEST_F(UnsafeBufferUsageTest, PointerIncrementDecrement) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int *p, int *q, int *r, int *s) { (++p)[5]; (q++)[5]; (--r)[5]; (s--)[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, @@ -282,40 +318,43 @@ TEST_F(UnsafeBufferUsageTest, PointerIncrementDecrement) { } TEST_F(UnsafeBufferUsageTest, PointerAssignment) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int *p, int *q) { (p = q + 5)[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U}, {"q", 1U}})); } TEST_F(UnsafeBufferUsageTest, CompoundAssignment) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int *p, int *q) { (p += 5)[5]; (q -= 3)[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U}, {"q", 1U}})); } TEST_F(UnsafeBufferUsageTest, MultiLevelPointer) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int **p, int **q, int **r) { (*p)[5]; *(*q); *(q[5]); r[5][5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, @@ -323,13 +362,14 @@ TEST_F(UnsafeBufferUsageTest, MultiLevelPointer) { } TEST_F(UnsafeBufferUsageTest, ConditionalOperator) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int **p, int **q, int cond) { (cond ? *p : *q)[5]; cond ? p[5] : q[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, @@ -337,78 +377,84 @@ TEST_F(UnsafeBufferUsageTest, ConditionalOperator) { } TEST_F(UnsafeBufferUsageTest, CastExpression) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(void *p, int q) { ((int*)p)[5]; ((int*)q)[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U}})); } TEST_F(UnsafeBufferUsageTest, CommaOperator) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int *p, int x) { (x++, p)[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U}})); } TEST_F(UnsafeBufferUsageTest, CommaOperator2) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int **p, int **q, int x) { (p[x] = 0, q[x] = 0)[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U}, {"q", 1U}, {"q", 2U}})); } TEST_F(UnsafeBufferUsageTest, ParenthesizedExpression) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int *p) { (((p)))[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U}})); } TEST_F(UnsafeBufferUsageTest, ArrayParameter) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int arr[], int arr2[][10]) { int n = 5; arr[100]; arr2[5][n]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"arr", 1U}, {"arr2", 1U}, {"arr2", 2U}})); } TEST_F(UnsafeBufferUsageTest, FunctionCall) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( int ** (*fp)(); int ** foo() { fp = &foo; foo()[5]; (*fp())[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); // No (foo, 2) becasue indirect calls are ignored. @@ -416,7 +462,7 @@ TEST_F(UnsafeBufferUsageTest, FunctionCall) { } TEST_F(UnsafeBufferUsageTest, StructMemberAccess) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( struct S { int *ptr; int (*ptr_to_arr)[10]; @@ -426,206 +472,215 @@ TEST_F(UnsafeBufferUsageTest, StructMemberAccess) { obj.ptr[5]; (*obj.ptr_to_arr)[n]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"ptr", 1U}, {"ptr_to_arr", 2U}})); } TEST_F(UnsafeBufferUsageTest, StringLiteralSubscript) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo() { "hello"[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); - EXPECT_NE(Sum, nullptr); // String literals should not generate pointer kind variables - EXPECT_EQ(*Sum, makeSet(__LINE__, {})); + EXPECT_EQ(Sum, nullptr); } TEST_F(UnsafeBufferUsageTest, OpaqueValueExpr) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int *p, int *q) { (p ?: q)[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U}, {"q", 1U}})); } TEST_F(UnsafeBufferUsageTest, AddressOfOperator) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int x) { (&x)[5]; } - )cpp", - "foo"); - - EXPECT_NE(Sum, nullptr); - // Address-of should not generate pointer kind variables for 'x' - EXPECT_EQ(*Sum, makeSet(__LINE__, {})); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); + // Address-of should not generate pointer kind variables for 'x': + EXPECT_EQ(Sum, nullptr); } TEST_F(UnsafeBufferUsageTest, AddressOfThenDereference) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo(int *p, int *q) { (*(&p))[5]; (&(*q))[5]; } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1}, {"q", 1}})); } TEST_F(UnsafeBufferUsageTest, PointerToArrayOfPointers) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( void foo() { int * arr[10]; - int * (*p)[10] = arr; + int * (*p)[10] = &arr; - (*p)[5][5]; // '(*p)[5]' is unsafe + (*p)[5][5]; // '(*p)[5]' is unsafe // '(*p)' is fine because 5 < 10 } - )cpp", - "foo"); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 3}})); } TEST_F(UnsafeBufferUsageTest, UnsafePointerInGlobalVariableInitializer) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( int *gp; int x = gp[5]; - )cpp", - {"x"}); + )cpp"), + true); + const auto *Sum = getEntitySummary("x"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"gp", 1U}})); } TEST_F(UnsafeBufferUsageTest, UnsafePointerInFieldInitializer) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( int *gp; struct Foo { int field = gp[5]; }; - )cpp", - {"Foo"}); + )cpp"), + true); + const auto *Sum = getEntitySummary("Foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"gp", 1U}})); } TEST_F(UnsafeBufferUsageTest, UnsafePointerInFieldInitializer2) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( int *gp; union Foo { int field = gp[5]; int x; }; - )cpp", - {"Foo"}); + )cpp"), + true); + const auto *Sum = getEntitySummary("Foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"gp", 1U}})); } TEST_F(UnsafeBufferUsageTest, InitializerList) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( int *gp; struct Foo { int field; int x; }; Foo FooObj{gp[5], 0}; - )cpp", - {"FooObj"}); + )cpp"), + true); + const auto *Sum = getEntitySummary("FooObj"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"gp", 1U}})); } TEST_F(UnsafeBufferUsageTest, UnsafePointerInCXXCtorInitializer) { - auto Sum = setUpTest<CXXConstructorDecl>(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( struct Foo { int member; Foo(int *p) : member(p[5]) {} }; - )cpp", - {"Foo"}); + )cpp"), + true); + const auto *Sum = getEntitySummary<CXXConstructorDecl>("Foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U}})); } TEST_F(UnsafeBufferUsageTest, UnsafePointerInDefaultArg) { - auto Sum = setUpTest(R"cpp( + ASSERT_EQ(setUpTest(R"cpp( int * gp; void foo(int x = gp[5]); - )cpp", - {"foo"}); + )cpp"), + true); + const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); EXPECT_EQ(*Sum, makeSet(__LINE__, {{"gp", 1U}})); } TEST_F(UnsafeBufferUsageTest, NestedDefinitions) { - StringRef Code = R"cpp( + ASSERT_EQ(setUpTest(R"cpp( int * a = [](){ struct Foo { void bar(int * ptr) { ptr[3] = 0; } }; return nullptr; }(); - )cpp"; - auto Sum = setUpTest(Code, {"bar"}); + )cpp"), + true); + const auto *Sum = getEntitySummary("bar"); EXPECT_NE(Sum, nullptr); // The closest contributor owns the fact: EXPECT_EQ(*Sum, makeSet(__LINE__, {{"ptr", 1U}})); - Sum = setUpTest(Code, {"Foo"}); + Sum = getEntitySummary("Foo"); - EXPECT_NE(Sum, nullptr); - EXPECT_TRUE(Sum->empty()); + EXPECT_EQ(Sum, nullptr); - Sum = setUpTest(Code, {"a"}); + Sum = getEntitySummary("a"); - EXPECT_NE(Sum, nullptr); - EXPECT_TRUE(Sum->empty()); + EXPECT_EQ(Sum, nullptr); } TEST_F(UnsafeBufferUsageTest, NestedDefinitions2) { - StringRef Code = R"cpp( + bool SetupSuccess = setUpTest(R"cpp( int main(void) { struct Foo { void bar(int * ptr) { ptr[3] = 0; } }; } - )cpp"; - auto Sum = setUpTest(Code, {"bar"}); + )cpp"); + + ASSERT_EQ(SetupSuccess, true); + + const auto *Sum = getEntitySummary("bar"); EXPECT_NE(Sum, nullptr); // The closest contributor owns the fact: EXPECT_EQ(*Sum, makeSet(__LINE__, {{"ptr", 1U}})); - Sum = setUpTest(Code, {"Foo"}); + Sum = getEntitySummary("Foo"); - EXPECT_NE(Sum, nullptr); - EXPECT_TRUE(Sum->empty()); + EXPECT_EQ(Sum, nullptr); - Sum = setUpTest(Code, {"main"}); + Sum = getEntitySummary("main"); - EXPECT_NE(Sum, nullptr); - EXPECT_TRUE(Sum->empty()); + EXPECT_EQ(Sum, nullptr); } } // namespace >From f4ab5e00ea532531a9b3fc3bc3b71966bd6533e5 Mon Sep 17 00:00:00 2001 From: Ziqing Luo <[email protected]> Date: Wed, 15 Apr 2026 11:06:18 -0700 Subject: [PATCH 2/2] clean up code --- .../EntityPointerLevel/EntityPointerLevel.h | 2 +- .../SSAFBuiltinForceLinker.h | 4 + .../EntityPointerLevel/EntityPointerLevel.cpp | 2 +- .../UnsafeBufferUsageExtractor.cpp | 106 +++++++++--------- .../UnsafeBufferUsageTest.cpp | 3 +- 5 files changed, 63 insertions(+), 54 deletions(-) diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h index ed8400f65e310..506b81170f757 100644 --- a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h +++ b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h @@ -107,7 +107,7 @@ EntityPointerLevel buildEntityPointerLevel(EntityId, unsigned); /// \param IsFunRet true iff the created EPL is associated with the return type /// of a function entity. llvm::Expected<EntityPointerLevel> -creatEntityPointerLevel(const NamedDecl *ND, +createEntityPointerLevel(const NamedDecl *ND, llvm::function_ref<EntityId(EntityName EN)> AddEntity, bool IsFunRet = false); diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h b/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h index 916ef1ce783c4..5616976e10f77 100644 --- a/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h +++ b/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h @@ -32,10 +32,14 @@ extern volatile int SSAFAnalysisRegistryAnchorSource; [[maybe_unused]] static int SSAFAnalysisRegistryAnchorDestination = SSAFAnalysisRegistryAnchorSource; +// This anchor is used to force the linker to link the UnsafeBufferUsage +// JSON format. extern volatile int UnsafeBufferUsageSSAFJSONFormatAnchorSource; [[maybe_unused]] static int UnsafeBufferUsageSSAFJSONFormatAnchorDestination = UnsafeBufferUsageSSAFJSONFormatAnchorSource; +// This anchor is used to force the linker to link the +// UnsafeBufferUsageTUSummaryExtractor. extern volatile int UnsafeBufferUsageTUSummaryExtractorAnchorSource; [[maybe_unused]] static int UnsafeBufferUsageTUSummaryExtractorAnchorDestination = diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp index 7e4200467ce9e..dee8cf3465c1e 100644 --- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp +++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp @@ -256,7 +256,7 @@ Expected<EntityPointerLevelSet> clang::ssaf::translateEntityPointerLevel( } /// Create an EntityPointerLevel from a ValueDecl of a pointer type. -Expected<EntityPointerLevel> clang::ssaf::creatEntityPointerLevel( +Expected<EntityPointerLevel> clang::ssaf::createEntityPointerLevel( const NamedDecl *ND, llvm::function_ref<EntityId(EntityName EN)> AddEntity, bool IsFunRet) { EntityPointerLevelTranslator Translator(AddEntity, ND->getASTContext()); diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp index 72944bd0be323..712c2d39e3695 100644 --- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp +++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp @@ -78,8 +78,8 @@ static std::set<const Expr *> findUnsafePointersInContributor(const Decl *D) { } } // namespace -class clang::ssaf::UnsafeBufferUsageTUSummaryExtractor - : public TUSummaryExtractor { +namespace clang::ssaf { +class UnsafeBufferUsageTUSummaryExtractor : public TUSummaryExtractor { public: UnsafeBufferUsageTUSummaryExtractor(TUSummaryBuilder &Builder) : TUSummaryExtractor(Builder) {} @@ -87,68 +87,74 @@ class clang::ssaf::UnsafeBufferUsageTUSummaryExtractor EntityId addEntity(EntityName EN) { return SummaryBuilder.addEntity(EN); } Expected<std::unique_ptr<UnsafeBufferUsageEntitySummary>> - extractEntitySummary(const Decl *Contributor, ASTContext &Ctx) { - auto AddEntity = [this](EntityName EN) { return addEntity(EN); }; - Expected<EntityPointerLevelSet> EPLs = buildEntityPointerLevels( - findUnsafePointersInContributor(Contributor), Ctx, AddEntity); - - if (EPLs) - return std::make_unique<UnsafeBufferUsageEntitySummary>( - UnsafeBufferUsageEntitySummary(std::move(*EPLs))); - return EPLs.takeError(); - } + extractEntitySummary(const Decl *Contributor, ASTContext &Ctx); - void HandleTranslationUnit(ASTContext &Ctx) override { + void HandleTranslationUnit(ASTContext &Ctx) override; +}; +} // namespace clang::ssaf + +Expected<std::unique_ptr<UnsafeBufferUsageEntitySummary>> +clang::ssaf::UnsafeBufferUsageTUSummaryExtractor::extractEntitySummary( + const Decl *Contributor, ASTContext &Ctx) { + auto AddEntity = [this](EntityName EN) { return addEntity(EN); }; + Expected<EntityPointerLevelSet> EPLs = buildEntityPointerLevels( + findUnsafePointersInContributor(Contributor), Ctx, AddEntity); + + if (EPLs) + return std::make_unique<UnsafeBufferUsageEntitySummary>( + UnsafeBufferUsageEntitySummary(std::move(*EPLs))); + return EPLs.takeError(); +} - // FIXME: I suppose finding contributor Decls is commonly needed by all/many - // extractors - class ContributorFinder : public DynamicRecursiveASTVisitor { - public: - std::vector<const NamedDecl *> Contributors; +void clang::ssaf::UnsafeBufferUsageTUSummaryExtractor::HandleTranslationUnit( + ASTContext &Ctx) { - bool VisitFunctionDecl(FunctionDecl *D) override { - Contributors.push_back(D); - return true; - } + // FIXME: I suppose finding contributor Decls is commonly needed by all/many + // extractors + class ContributorFinder : public DynamicRecursiveASTVisitor { + public: + std::vector<const NamedDecl *> Contributors; - bool VisitRecordDecl(RecordDecl *D) override { - Contributors.push_back(D); - return true; - } + bool VisitFunctionDecl(FunctionDecl *D) override { + Contributors.push_back(D); + return true; + } - bool VisitVarDecl(VarDecl *D) override { - DeclContext *DC = D->getDeclContext(); + bool VisitRecordDecl(RecordDecl *D) override { + Contributors.push_back(D); + return true; + } - if (DC->isFileContext() || DC->isNamespace()) - Contributors.push_back(D); - return true; - } - } ContributorFinder; + bool VisitVarDecl(VarDecl *D) override { + DeclContext *DC = D->getDeclContext(); - ContributorFinder.VisitTranslationUnitDecl(Ctx.getTranslationUnitDecl()); + if (DC->isFileContext() || DC->isNamespace()) + Contributors.push_back(D); + return true; + } + } ContributorFinder; - ContributorFinder.TraverseAST(Ctx); - for (auto *CD : ContributorFinder.Contributors) { - auto EntitySummary = extractEntitySummary(CD, Ctx); + ContributorFinder.TraverseAST(Ctx); + for (auto *CD : ContributorFinder.Contributors) { + auto EntitySummary = extractEntitySummary(CD, Ctx); - if (!EntitySummary) - llvm::reportFatalInternalError(EntitySummary.takeError()); - assert(*EntitySummary); - if ((*EntitySummary)->empty()) - continue; + if (!EntitySummary) + llvm::reportFatalInternalError(EntitySummary.takeError()); + assert(*EntitySummary); + if ((*EntitySummary)->empty()) + continue; - auto ContributorName = getEntityName(CD); + auto ContributorName = getEntityName(CD); - if (!ContributorName) - llvm::reportFatalInternalError(makeCreateEntityNameError(CD, Ctx)); + if (!ContributorName) + llvm::reportFatalInternalError(makeCreateEntityNameError(CD, Ctx)); - auto [Ignored, InsertionSucceeded] = SummaryBuilder.addSummary( - addEntity(*ContributorName), std::move(*EntitySummary)); + auto [Ignored, InsertionSucceeded] = SummaryBuilder.addSummary( + addEntity(*ContributorName), std::move(*EntitySummary)); - assert(InsertionSucceeded && "duplicated contributor extraction"); - } + assert(InsertionSucceeded && "duplicated contributor extraction"); } -}; +} // NOLINTNEXTLINE(misc-use-internal-linkage) volatile int UnsafeBufferUsageTUSummaryExtractorAnchorSource = 0; diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp index 59c2cd38ffacf..11c3e4e01c5bc 100644 --- a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp +++ b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp @@ -11,7 +11,6 @@ #include "clang/AST/DynamicRecursiveASTVisitor.h" #include "clang/Frontend/ASTUnit.h" #include "clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h" -#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h" #include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h" #include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h" #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h" @@ -457,7 +456,7 @@ TEST_F(UnsafeBufferUsageTest, FunctionCall) { const auto *Sum = getEntitySummary("foo"); EXPECT_NE(Sum, nullptr); - // No (foo, 2) becasue indirect calls are ignored. + // No (foo, 2) because indirect calls are ignored. EXPECT_EQ(*Sum, makeSet(__LINE__, {{"foo", 1U, true}})); } _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
