[llvm-branch-commits] [clang] 9f59e81 - Revert "[NFC][SSAF] Move EntityPointerLevel to a separate folder (#191331)"
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Apr 10 11:15:03 PDT 2026
Author: Ziqing Luo
Date: 2026-04-10T11:14:59-07:00
New Revision: 9f59e81ae9e2aa9dfde3da95c6fe5de7053f1352
URL: https://github.com/llvm/llvm-project/commit/9f59e81ae9e2aa9dfde3da95c6fe5de7053f1352
DIFF: https://github.com/llvm/llvm-project/commit/9f59e81ae9e2aa9dfde3da95c6fe5de7053f1352.diff
LOG: Revert "[NFC][SSAF] Move EntityPointerLevel to a separate folder (#191331)"
This reverts commit 1a3cf72213adba014c0a8ee7a6377212c635c135.
Added:
Modified:
clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h
clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
Removed:
clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h
clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
################################################################################
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h
deleted file mode 100644
index 52caa52e1120d..0000000000000
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h
+++ /dev/null
@@ -1,99 +0,0 @@
-//===- EntityPointerLevel.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_ENTITYPOINTERLEVEL_ENTITYPOINTERLEVEL_H
-#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_ENTITYPOINTERLEVEL_ENTITYPOINTERLEVEL_H
-
-#include "clang/AST/Expr.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
-#include <set>
-
-namespace clang::ssaf {
-
-/// An EntityPointerLevel represents a level of the declared pointer/array
-/// type of an entity. In the fully-expanded spelling of the declared type, a
-/// EntityPointerLevel is associated with a '*' (or a '[]`) in that declaration.
-///
-/// For example, for 'int *p[10];', there are two EntityPointerLevels. One
-/// is associated with 'int *[10]' of 'p' and the other is associated with 'int
-/// *' of 'p'.
-///
-/// An EntityPointerLevel can be identified by an EntityId and an unsigned
-/// integer indicating the pointer level: '(EntityId, PointerLevel)'.
-/// An EntityPointerLevel 'P' is valid iff 'P.EntityId' has a pointer type with
-/// at least 'P.PointerLevel' levels (This implies 'P.PointerLevel > 0').
-///
-/// For the same example 'int *p[10];', the EntityPointerLevels below are valid:
-/// - '(p, 2)' is associated with the 'int *' part of the declared type of 'p';
-/// - '(p, 1)' is associated with the 'int *[10]' part of the declared type of
-/// 'p'.
-class EntityPointerLevel {
- EntityId Entity;
- unsigned PointerLevel;
-
- friend class EntityPointerLevelTranslator;
- friend EntityPointerLevel buildEntityPointerLevel(EntityId, unsigned);
-
- EntityPointerLevel(EntityId Entity, unsigned PointerLevel)
- : Entity(Entity), PointerLevel(PointerLevel) {}
-
-public:
- EntityId getEntity() const { return Entity; }
- unsigned getPointerLevel() const { return PointerLevel; }
-
- bool operator==(const EntityPointerLevel &Other) const {
- return std::tie(Entity, PointerLevel) ==
- std::tie(Other.Entity, Other.PointerLevel);
- }
-
- bool operator!=(const EntityPointerLevel &Other) const {
- return !(*this == Other);
- }
-
- bool operator<(const EntityPointerLevel &Other) const {
- return std::tie(Entity, PointerLevel) <
- std::tie(Other.Entity, Other.PointerLevel);
- }
-
- /// Compares `EntityPointerLevel`s; additionally, partially compares
- /// `EntityPointerLevel` with `EntityId`.
- struct Comparator {
- using is_transparent = void;
- bool operator()(const EntityPointerLevel &L,
- const EntityPointerLevel &R) const {
- return L < R;
- }
- bool operator()(const EntityId &L, const EntityPointerLevel &R) const {
- return L < R.getEntity();
- }
- bool operator()(const EntityPointerLevel &L, const EntityId &R) const {
- return L.getEntity() < R;
- }
- };
-};
-
-using EntityPointerLevelSet =
- std::set<EntityPointerLevel, EntityPointerLevel::Comparator>;
-
-/// Translate a pointer/array type expression 'E' to a (set of)
-/// EntityPointerLevel(s) associated with the declared type of the base address
-/// of `E`. If the base address of `E` is not associated with an entity, the
-/// translation result is an empty set.
-///
-/// \param E the pointer expression to be translated
-/// \param Ctx the AST context of `E`
-/// \param AddEntity the callback provided by the caller to convert EntityNames
-/// to EntityIds.
-llvm::Expected<EntityPointerLevelSet>
-translateEntityPointerLevel(const Expr *E, ASTContext &Ctx,
- std::function<EntityId(EntityName EN)> AddEntity);
-
-EntityPointerLevel buildEntityPointerLevel(EntityId, unsigned);
-} // namespace clang::ssaf
-#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_ENTITYPOINTERLEVEL_ENTITYPOINTERLEVEL_H
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
index 250bad5b72f75..4e217c2eb87ef 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
@@ -9,7 +9,7 @@
#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGE_H
#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGE_H
-#include "clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/SummaryName.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/EntitySummary.h"
#include "llvm/ADT/StringRef.h"
@@ -18,6 +18,72 @@
namespace clang::ssaf {
+/// An EntityPointerLevel represents a level of the declared pointer/array
+/// type of an entity. In the fully-expanded spelling of the declared type, a
+/// EntityPointerLevel is associated with a '*' (or a '[]`) in that declaration.
+///
+/// For example, for 'int *p[10];', there are two EntityPointerLevels. One
+/// is associated with 'int *[10]' of 'p' and the other is associated with 'int
+/// *' of 'p'.
+///
+/// An EntityPointerLevel can be identified by an EntityId and an unsigned
+/// integer indicating the pointer level: '(EntityId, PointerLevel)'.
+/// An EntityPointerLevel 'P' is valid iff 'P.EntityId' has a pointer type with
+/// at least 'P.PointerLevel' levels (This implies 'P.PointerLevel > 0').
+///
+/// For the same example 'int *p[10];', the EntityPointerLevels below are valid:
+/// - '(p, 2)' is associated with the 'int *' part of the declared type of 'p';
+/// - '(p, 1)' is associated with the 'int *[10]' part of the declared type of
+/// 'p'.
+class EntityPointerLevel {
+ EntityId Entity;
+ unsigned PointerLevel;
+
+ friend class UnsafeBufferUsageEntitySummary;
+ friend class UnsafeBufferUsageTUSummaryExtractor;
+ friend EntityPointerLevel buildEntityPointerLevel(EntityId, unsigned);
+
+ EntityPointerLevel(EntityId Entity, unsigned PointerLevel)
+ : Entity(Entity), PointerLevel(PointerLevel) {}
+
+public:
+ EntityId getEntity() const { return Entity; }
+ unsigned getPointerLevel() const { return PointerLevel; }
+
+ bool operator==(const EntityPointerLevel &Other) const {
+ return std::tie(Entity, PointerLevel) ==
+ std::tie(Other.Entity, Other.PointerLevel);
+ }
+
+ bool operator!=(const EntityPointerLevel &Other) const {
+ return !(*this == Other);
+ }
+
+ bool operator<(const EntityPointerLevel &Other) const {
+ return std::tie(Entity, PointerLevel) <
+ std::tie(Other.Entity, Other.PointerLevel);
+ }
+
+ /// Compares `EntityPointerLevel`s; additionally, partially compares
+ /// `EntityPointerLevel` with `EntityId`.
+ struct Comparator {
+ using is_transparent = void;
+ bool operator()(const EntityPointerLevel &L,
+ const EntityPointerLevel &R) const {
+ return L < R;
+ }
+ bool operator()(const EntityId &L, const EntityPointerLevel &R) const {
+ return L < R.getEntity();
+ }
+ bool operator()(const EntityPointerLevel &L, const EntityId &R) const {
+ return L.getEntity() < R;
+ }
+ };
+};
+
+using EntityPointerLevelSet =
+ std::set<EntityPointerLevel, EntityPointerLevel::Comparator>;
+
/// An UnsafeBufferUsageEntitySummary is an immutable set of unsafe buffers, in
/// the form of EntityPointerLevel.
class UnsafeBufferUsageEntitySummary final : public EntitySummary {
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h
index 13d4e18b4e81f..765b2c37562ce 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h
@@ -22,6 +22,11 @@ class UnsafeBufferUsageTUSummaryExtractor : public TUSummaryExtractor {
UnsafeBufferUsageTUSummaryExtractor(TUSummaryBuilder &Builder)
: TUSummaryExtractor(Builder) {}
+ static EntityPointerLevel buildEntityPointerLevel(EntityId Entity,
+ unsigned PointerLevel) {
+ return {Entity, PointerLevel};
+ }
+
EntityId addEntity(EntityName EN) { return SummaryBuilder.addEntity(EN); }
std::unique_ptr<UnsafeBufferUsageEntitySummary>
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
index c15ff3b3c42e7..926b610aa8dee 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
@@ -5,7 +5,6 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangScalableStaticAnalysisFrameworkAnalyses
CallGraph/CallGraphExtractor.cpp
CallGraph/CallGraphJSONFormat.cpp
- EntityPointerLevel/EntityPointerLevel.cpp
UnsafeBufferUsage/UnsafeBufferUsage.cpp
UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
deleted file mode 100644
index 49a135b13877a..0000000000000
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
+++ /dev/null
@@ -1,244 +0,0 @@
-//===- EntityPointerLevel.cpp ----------------------------------*- 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
-
-using namespace clang;
-using namespace ssaf;
-
-static bool hasPointerType(const Expr *E) {
- auto Ty = E->getType();
- return !Ty.isNull() && !Ty->isFunctionPointerType() &&
- (Ty->isPointerType() || Ty->isArrayType());
-}
-
-static llvm::Error makeUnsupportedStmtKindError(const Stmt *Unsupported) {
- return llvm::createStringError(
- "unsupported expression kind for translation to "
- "EntityPointerLevel: %s",
- Unsupported->getStmtClassName());
-}
-
-static llvm::Error makeCreateEntityNameError(const NamedDecl *FailedDecl,
- ASTContext &Ctx) {
- std::string LocStr = FailedDecl->getSourceRange().getBegin().printToString(
- Ctx.getSourceManager());
- return llvm::createStringError(
- "failed to create entity name for %s declared at %s",
- FailedDecl->getNameAsString().c_str(), LocStr.c_str());
-}
-
-// Translate a pointer type expression 'E' to a (set of) EntityPointerLevel(s)
-// associated with the declared type of the base address of `E`. If the base
-// address of `E` is not associated with an entity, the translation result is an
-// empty set.
-//
-// The translation is a process of traversing into the pointer 'E' until its
-// base address can be represented by an entity, with the number of dereferences
-// tracked by incrementing the pointer level. Naturally, taking address of, as
-// the inverse operation of dereference, is tracked by decrementing the pointer
-// level.
-//
-// For example, suppose there are pointers and arrays declared as
-// int *ptr, **p1, **p2;
-// int arr[10][10];
-// , the translation of expressions involving these base addresses will be:
-// Translate(ptr + 5) -> {(ptr, 1)}
-// Translate(arr[5]) -> {(arr, 2)}
-// Translate(cond ? p1[5] : p2) -> {(p1, 2), (p2, 1)}
-// Translate(&arr[5]) -> {(arr, 1)}
-class ssaf::EntityPointerLevelTranslator
- : ConstStmtVisitor<EntityPointerLevelTranslator,
- Expected<EntityPointerLevelSet>> {
- friend class StmtVisitorBase;
-
- // Fallback method for all unsupported expression kind:
- llvm::Error fallback(const Stmt *E) {
- return makeUnsupportedStmtKindError(E);
- }
-
- static EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E) {
- return EntityPointerLevel(E.getEntity(), E.getPointerLevel() + 1);
- }
-
- static EntityPointerLevel decrementPointerLevel(const EntityPointerLevel &E) {
- assert(E.getPointerLevel() > 0);
- return EntityPointerLevel(E.getEntity(), E.getPointerLevel() - 1);
- }
-
- EntityPointerLevel createEntityPointerLevelFor(const EntityName &Name) {
- return EntityPointerLevel(AddEntity(Name), 1);
- }
-
- // The common helper function for Translate(*base):
- // Translate(*base) -> Translate(base) with .pointerLevel + 1
- Expected<EntityPointerLevelSet> translateDereferencePointer(const Expr *Ptr) {
- assert(hasPointerType(Ptr));
-
- Expected<EntityPointerLevelSet> SubResult = Visit(Ptr);
- if (!SubResult)
- return SubResult.takeError();
-
- auto Incremented = llvm::map_range(*SubResult, incrementPointerLevel);
- return EntityPointerLevelSet{Incremented.begin(), Incremented.end()};
- }
-
- std::function<EntityId(EntityName EN)> AddEntity;
- ASTContext &Ctx;
-
-public:
- EntityPointerLevelTranslator(std::function<EntityId(EntityName EN)> AddEntity,
- ASTContext &Ctx)
- : AddEntity(AddEntity), Ctx(Ctx) {}
-
- Expected<EntityPointerLevelSet> translate(const Expr *E) { return Visit(E); }
-
-private:
- Expected<EntityPointerLevelSet> VisitStmt(const Stmt *E) {
- return fallback(E);
- }
-
- // Translate(base + x) -> Translate(base)
- // Translate(x + base) -> Translate(base)
- // Translate(base - x) -> Translate(base)
- // Translate(base {+=, -=, =} x) -> Translate(base)
- // Translate(x, base) -> Translate(base)
- Expected<EntityPointerLevelSet> VisitBinaryOperator(const BinaryOperator *E) {
- switch (E->getOpcode()) {
- case clang::BO_Add:
- if (hasPointerType(E->getLHS()))
- return Visit(E->getLHS());
- return Visit(E->getRHS());
- case clang::BO_Sub:
- case clang::BO_AddAssign:
- case clang::BO_SubAssign:
- case clang::BO_Assign:
- return Visit(E->getLHS());
- case clang::BO_Comma:
- return Visit(E->getRHS());
- default:
- return fallback(E);
- }
- }
-
- // Translate({++, --}base) -> Translate(base)
- // Translate(base{++, --}) -> Translate(base)
- // Translate(*base) -> Translate(base) with .pointerLevel += 1
- // Translate(&base) -> {}, if Translate(base) is {}
- // -> Translate(base) with .pointerLevel -= 1
- Expected<EntityPointerLevelSet> VisitUnaryOperator(const UnaryOperator *E) {
- switch (E->getOpcode()) {
- case clang::UO_PostInc:
- case clang::UO_PostDec:
- case clang::UO_PreInc:
- case clang::UO_PreDec:
- return Visit(E->getSubExpr());
- case clang::UO_AddrOf: {
- Expected<EntityPointerLevelSet> SubResult = Visit(E->getSubExpr());
- if (!SubResult)
- return SubResult.takeError();
-
- auto Decremented = llvm::map_range(*SubResult, decrementPointerLevel);
- return EntityPointerLevelSet{Decremented.begin(), Decremented.end()};
- }
- case clang::UO_Deref:
- return translateDereferencePointer(E->getSubExpr());
- default:
- return fallback(E);
- }
- }
-
- // Translate((T*)base) -> Translate(p) if p has pointer type
- // -> {} otherwise
- Expected<EntityPointerLevelSet> VisitCastExpr(const CastExpr *E) {
- if (hasPointerType(E->getSubExpr()))
- return Visit(E->getSubExpr());
- return EntityPointerLevelSet{};
- }
-
- // Translate(f(...)) -> {} if it is an indirect call
- // -> {(f_return, 1)}, otherwise
- Expected<EntityPointerLevelSet> VisitCallExpr(const CallExpr *E) {
- if (auto *FD = E->getDirectCallee())
- if (auto FDEntityName = getEntityNameForReturn(FD))
- return EntityPointerLevelSet{
- createEntityPointerLevelFor(*FDEntityName)};
- return EntityPointerLevelSet{};
- }
-
- // Translate(base[x]) -> Translate(*base)
- Expected<EntityPointerLevelSet>
- VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
- return translateDereferencePointer(E->getBase());
- }
-
- // Translate(cond ? base1 : base2) := Translate(base1) U Translate(base2)
- Expected<EntityPointerLevelSet>
- VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
- Expected<EntityPointerLevelSet> ReT = Visit(E->getTrueExpr());
- Expected<EntityPointerLevelSet> ReF = Visit(E->getFalseExpr());
-
- if (ReT && ReF) {
- ReT->insert(ReF->begin(), ReF->end());
- return ReT;
- }
- if (!ReF && !ReT)
- return llvm::joinErrors(ReT.takeError(), ReF.takeError());
- if (!ReF)
- return ReF.takeError();
- return ReT.takeError();
- }
-
- Expected<EntityPointerLevelSet> VisitParenExpr(const ParenExpr *E) {
- return Visit(E->getSubExpr());
- }
-
- // Translate("string-literal") -> {}
- // Buffer accesses on string literals are unsafe, but string literals are not
- // entities so there is no EntityPointerLevel associated with it.
- Expected<EntityPointerLevelSet> VisitStringLiteral(const StringLiteral *E) {
- return EntityPointerLevelSet{};
- }
-
- // Translate(DRE) -> {(Decl, 1)}
- Expected<EntityPointerLevelSet> VisitDeclRefExpr(const DeclRefExpr *E) {
- if (auto EntityName = getEntityName(E->getDecl()))
- return EntityPointerLevelSet{createEntityPointerLevelFor(*EntityName)};
- return makeCreateEntityNameError(E->getDecl(), Ctx);
- }
-
- // Translate({., ->}f) -> {(MemberDecl, 1)}
- Expected<EntityPointerLevelSet> VisitMemberExpr(const MemberExpr *E) {
- if (auto EntityName = getEntityName(E->getMemberDecl()))
- return EntityPointerLevelSet{createEntityPointerLevelFor(*EntityName)};
- return makeCreateEntityNameError(E->getMemberDecl(), Ctx);
- }
-
- Expected<EntityPointerLevelSet>
- VisitOpaqueValueExpr(const OpaqueValueExpr *S) {
- return Visit(S->getSourceExpr());
- }
-};
-
-Expected<EntityPointerLevelSet> clang::ssaf::translateEntityPointerLevel(
- const Expr *E, ASTContext &Ctx,
- std::function<EntityId(EntityName EN)> AddEntity) {
- EntityPointerLevelTranslator Translator(AddEntity, Ctx);
-
- return Translator.translate(E);
-}
-
-EntityPointerLevel clang::ssaf::buildEntityPointerLevel(EntityId Id,
- unsigned PtrLv) {
- return EntityPointerLevel({Id, PtrLv});
-}
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
index 84f3f9cbb3852..d325e8df79c20 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
@@ -21,6 +21,10 @@ using Object = llvm::json::Object;
static constexpr llvm::StringLiteral SummarySerializationKey = "UnsafeBuffers";
+EntityPointerLevel ssaf::buildEntityPointerLevel(EntityId Id, unsigned PtrLv) {
+ return EntityPointerLevel(Id, PtrLv);
+}
+
UnsafeBufferUsageEntitySummary
ssaf::buildUnsafeBufferUsageEntitySummary(EntityPointerLevelSet UnsafeBuffers) {
return UnsafeBufferUsageEntitySummary(std::move(UnsafeBuffers));
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
index b29eaa6b903d0..c609168e4dc7d 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
@@ -11,8 +11,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DynamicRecursiveASTVisitor.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/UnsafeBufferUsage.h"
-#include "clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h"
#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h"
#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
#include "llvm/ADT/STLExtras.h"
@@ -24,6 +24,22 @@ namespace {
using namespace clang;
using namespace ssaf;
+static bool hasPointerType(const Expr *E) {
+ auto Ty = E->getType();
+ return !Ty.isNull() && !Ty->isFunctionPointerType() &&
+ (Ty->isPointerType() || Ty->isArrayType());
+}
+
+constexpr inline auto buildEntityPointerLevel =
+ UnsafeBufferUsageTUSummaryExtractor::buildEntityPointerLevel;
+
+static llvm::Error makeUnsupportedStmtKindError(const Stmt *Unsupported) {
+ return llvm::createStringError(
+ "unsupported expression kind for translation to "
+ "EntityPointerLevel: %s",
+ Unsupported->getStmtClassName());
+}
+
static llvm::Error makeCreateEntityNameError(const NamedDecl *FailedDecl,
ASTContext &Ctx) {
std::string LocStr = FailedDecl->getSourceRange().getBegin().printToString(
@@ -43,17 +59,208 @@ static llvm::Error makeAddEntitySummaryError(const NamedDecl *FailedContributor,
FailedContributor->getNameAsString().c_str(), LocStr.c_str());
}
+// Translate a pointer type expression 'E' to a (set of) EntityPointerLevel(s)
+// associated with the declared type of the base address of `E`. If the base
+// address of `E` is not associated with an entity, the translation result is an
+// empty set.
+//
+// The translation is a process of traversing into the pointer 'E' until its
+// base address can be represented by an entity, with the number of dereferences
+// tracked by incrementing the pointer level. Naturally, taking address of, as
+// the inverse operation of dereference, is tracked by decrementing the pointer
+// level.
+//
+// For example, suppose there are pointers and arrays declared as
+// int *ptr, **p1, **p2;
+// int arr[10][10];
+// , the translation of expressions involving these base addresses will be:
+// Translate(ptr + 5) -> {(ptr, 1)}
+// Translate(arr[5]) -> {(arr, 2)}
+// Translate(cond ? p1[5] : p2) -> {(p1, 2), (p2, 1)}
+// Translate(&arr[5]) -> {(arr, 1)}
+class EntityPointerLevelTranslator
+ : ConstStmtVisitor<EntityPointerLevelTranslator,
+ Expected<EntityPointerLevelSet>> {
+ friend class StmtVisitorBase;
+
+ // Fallback method for all unsupported expression kind:
+ llvm::Error fallback(const Stmt *E) {
+ return makeUnsupportedStmtKindError(E);
+ }
+
+ static EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E) {
+ return buildEntityPointerLevel(E.getEntity(), E.getPointerLevel() + 1);
+ }
+
+ static EntityPointerLevel decrementPointerLevel(const EntityPointerLevel &E) {
+ assert(E.getPointerLevel() > 0);
+ return buildEntityPointerLevel(E.getEntity(), E.getPointerLevel() - 1);
+ }
+
+ EntityPointerLevel createEntityPointerLevelFor(const EntityName &Name) {
+ return buildEntityPointerLevel(Extractor.addEntity(Name), 1);
+ }
+
+ // The common helper function for Translate(*base):
+ // Translate(*base) -> Translate(base) with .pointerLevel + 1
+ Expected<EntityPointerLevelSet> translateDereferencePointer(const Expr *Ptr) {
+ assert(hasPointerType(Ptr));
+
+ Expected<EntityPointerLevelSet> SubResult = Visit(Ptr);
+ if (!SubResult)
+ return SubResult.takeError();
+
+ auto Incremented = llvm::map_range(*SubResult, incrementPointerLevel);
+ return EntityPointerLevelSet{Incremented.begin(), Incremented.end()};
+ }
+
+ UnsafeBufferUsageTUSummaryExtractor &Extractor;
+ ASTContext &Ctx;
+
+public:
+ EntityPointerLevelTranslator(UnsafeBufferUsageTUSummaryExtractor &Extractor,
+ ASTContext &Ctx)
+ : Extractor(Extractor), Ctx(Ctx) {}
+
+ Expected<EntityPointerLevelSet> translate(const Expr *E) { return Visit(E); }
+
+private:
+ Expected<EntityPointerLevelSet> VisitStmt(const Stmt *E) {
+ return fallback(E);
+ }
+
+ // Translate(base + x) -> Translate(base)
+ // Translate(x + base) -> Translate(base)
+ // Translate(base - x) -> Translate(base)
+ // Translate(base {+=, -=, =} x) -> Translate(base)
+ // Translate(x, base) -> Translate(base)
+ Expected<EntityPointerLevelSet> VisitBinaryOperator(const BinaryOperator *E) {
+ switch (E->getOpcode()) {
+ case clang::BO_Add:
+ if (hasPointerType(E->getLHS()))
+ return Visit(E->getLHS());
+ return Visit(E->getRHS());
+ case clang::BO_Sub:
+ case clang::BO_AddAssign:
+ case clang::BO_SubAssign:
+ case clang::BO_Assign:
+ return Visit(E->getLHS());
+ case clang::BO_Comma:
+ return Visit(E->getRHS());
+ default:
+ return fallback(E);
+ }
+ }
+
+ // Translate({++, --}base) -> Translate(base)
+ // Translate(base{++, --}) -> Translate(base)
+ // Translate(*base) -> Translate(base) with .pointerLevel += 1
+ // Translate(&base) -> {}, if Translate(base) is {}
+ // -> Translate(base) with .pointerLevel -= 1
+ Expected<EntityPointerLevelSet> VisitUnaryOperator(const UnaryOperator *E) {
+ switch (E->getOpcode()) {
+ case clang::UO_PostInc:
+ case clang::UO_PostDec:
+ case clang::UO_PreInc:
+ case clang::UO_PreDec:
+ return Visit(E->getSubExpr());
+ case clang::UO_AddrOf: {
+ Expected<EntityPointerLevelSet> SubResult = Visit(E->getSubExpr());
+ if (!SubResult)
+ return SubResult.takeError();
+
+ auto Decremented = llvm::map_range(*SubResult, decrementPointerLevel);
+ return EntityPointerLevelSet{Decremented.begin(), Decremented.end()};
+ }
+ case clang::UO_Deref:
+ return translateDereferencePointer(E->getSubExpr());
+ default:
+ return fallback(E);
+ }
+ }
+
+ // Translate((T*)base) -> Translate(p) if p has pointer type
+ // -> {} otherwise
+ Expected<EntityPointerLevelSet> VisitCastExpr(const CastExpr *E) {
+ if (hasPointerType(E->getSubExpr()))
+ return Visit(E->getSubExpr());
+ return EntityPointerLevelSet{};
+ }
+
+ // Translate(f(...)) -> {} if it is an indirect call
+ // -> {(f_return, 1)}, otherwise
+ Expected<EntityPointerLevelSet> VisitCallExpr(const CallExpr *E) {
+ if (auto *FD = E->getDirectCallee())
+ if (auto FDEntityName = getEntityNameForReturn(FD))
+ return EntityPointerLevelSet{
+ createEntityPointerLevelFor(*FDEntityName)};
+ return EntityPointerLevelSet{};
+ }
+
+ // Translate(base[x]) -> Translate(*base)
+ Expected<EntityPointerLevelSet>
+ VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+ return translateDereferencePointer(E->getBase());
+ }
+
+ // Translate(cond ? base1 : base2) := Translate(base1) U Translate(base2)
+ Expected<EntityPointerLevelSet>
+ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
+ Expected<EntityPointerLevelSet> ReT = Visit(E->getTrueExpr());
+ Expected<EntityPointerLevelSet> ReF = Visit(E->getFalseExpr());
+
+ if (ReT && ReF) {
+ ReT->insert(ReF->begin(), ReF->end());
+ return ReT;
+ }
+ if (!ReF && !ReT)
+ return llvm::joinErrors(ReT.takeError(), ReF.takeError());
+ if (!ReF)
+ return ReF.takeError();
+ return ReT.takeError();
+ }
+
+ Expected<EntityPointerLevelSet> VisitParenExpr(const ParenExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+
+ // Translate("string-literal") -> {}
+ // Buffer accesses on string literals are unsafe, but string literals are not
+ // entities so there is no EntityPointerLevel associated with it.
+ Expected<EntityPointerLevelSet> VisitStringLiteral(const StringLiteral *E) {
+ return EntityPointerLevelSet{};
+ }
+
+ // Translate(DRE) -> {(Decl, 1)}
+ Expected<EntityPointerLevelSet> VisitDeclRefExpr(const DeclRefExpr *E) {
+ if (auto EntityName = getEntityName(E->getDecl()))
+ return EntityPointerLevelSet{createEntityPointerLevelFor(*EntityName)};
+ return makeCreateEntityNameError(E->getDecl(), Ctx);
+ }
+
+ // Translate({., ->}f) -> {(MemberDecl, 1)}
+ Expected<EntityPointerLevelSet> VisitMemberExpr(const MemberExpr *E) {
+ if (auto EntityName = getEntityName(E->getMemberDecl()))
+ return EntityPointerLevelSet{createEntityPointerLevelFor(*EntityName)};
+ return makeCreateEntityNameError(E->getMemberDecl(), Ctx);
+ }
+
+ Expected<EntityPointerLevelSet>
+ VisitOpaqueValueExpr(const OpaqueValueExpr *S) {
+ return Visit(S->getSourceExpr());
+ }
+};
+
Expected<EntityPointerLevelSet>
buildEntityPointerLevels(std::set<const Expr *> &&UnsafePointers,
UnsafeBufferUsageTUSummaryExtractor &Extractor,
- ASTContext &Ctx,
- std::function<EntityId(EntityName)> AddEntity) {
+ ASTContext &Ctx) {
EntityPointerLevelSet Result{};
+ EntityPointerLevelTranslator Translator{Extractor, Ctx};
llvm::Error AllErrors = llvm::ErrorSuccess();
for (const Expr *Ptr : UnsafePointers) {
- Expected<EntityPointerLevelSet> Translation =
- translateEntityPointerLevel(Ptr, Ctx, AddEntity);
+ Expected<EntityPointerLevelSet> Translation = Translator.translate(Ptr);
if (Translation) {
// Filter out those temporary invalid EntityPointerLevels associated with
@@ -90,9 +297,8 @@ static std::set<const Expr *> findUnsafePointersInContributor(const Decl *D) {
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);
+ findUnsafePointersInContributor(Contributor), *this, Ctx);
if (EPLs)
return std::make_unique<UnsafeBufferUsageEntitySummary>(
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
index d2c513b7c70a2..51d422c1921af 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
@@ -10,7 +10,6 @@
#include "TestFixture.h"
#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/UnsafeBufferUsageTest.h"
#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
@@ -64,6 +63,9 @@ const FunctionDecl *findFnByName(StringRef Name, ASTContext &Ctx) {
return findDeclByName<FunctionDecl>(Name, Ctx);
}
+constexpr inline auto buildEntityPointerLevel =
+ UnsafeBufferUsageTUSummaryExtractor::buildEntityPointerLevel;
+
class UnsafeBufferUsageTest : public TestFixture {
protected:
TUSummary TUSum;
More information about the llvm-branch-commits
mailing list