From 59e031ff9057b103c73f22bebc32304ee79fa139 Mon Sep 17 00:00:00 2001 From: Stanislav Gatev Date: Mon, 17 Jan 2022 16:23:24 +0000 Subject: [PATCH] [clang][dataflow] Add transfer function for addrof This is part of the implementation of the dataflow analysis framework. See "[RFC] A dataflow analysis framework for Clang AST" on cfe-dev. Reviewed-by: xazax.hun Differential Revision: https://reviews.llvm.org/D117496 --- clang/lib/Analysis/FlowSensitive/Transfer.cpp | 36 +++++++++++-- .../Analysis/FlowSensitive/TransferTest.cpp | 59 ++++++++++++++++++++++ 2 files changed, 90 insertions(+), 5 deletions(-) diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 6ae4573..0979f55 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -174,19 +174,45 @@ public: } void VisitUnaryOperator(const UnaryOperator *S) { - if (S->getOpcode() == UO_Deref) { - assert(S->getSubExpr() != nullptr); + // The CFG does not contain `ParenExpr` as top-level statements in basic + // blocks, however sub-expressions can still be of that type. + assert(S->getSubExpr() != nullptr); + const Expr *SubExpr = S->getSubExpr()->IgnoreParens(); + assert(SubExpr != nullptr); + + switch (S->getOpcode()) { + case UO_Deref: { const auto *SubExprVal = cast_or_null( - Env.getValue(*S->getSubExpr(), SkipPast::Reference)); + Env.getValue(*SubExpr, SkipPast::Reference)); if (SubExprVal == nullptr) - return; + break; auto &Loc = Env.createStorageLocation(*S); Env.setStorageLocation(*S, Loc); Env.setValue(Loc, Env.takeOwnership(std::make_unique( SubExprVal->getPointeeLoc()))); + break; + } + case UO_AddrOf: { + // Do not form a pointer to a reference. If `SubExpr` is assigned a + // `ReferenceValue` then form a value that points to the location of its + // pointee. + StorageLocation *PointeeLoc = + Env.getStorageLocation(*SubExpr, SkipPast::Reference); + if (PointeeLoc == nullptr) + break; + + auto &PointerLoc = Env.createStorageLocation(*S); + auto &PointerVal = + Env.takeOwnership(std::make_unique(*PointeeLoc)); + Env.setStorageLocation(*S, PointerLoc); + Env.setValue(PointerLoc, PointerVal); + break; + } + default: + // FIXME: Add support for UO_LNot. + break; } - // FIXME: Add support for UO_AddrOf, UO_LNot. } void VisitCXXThisExpr(const CXXThisExpr *S) { diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 7dfb916..ea035ba 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -1699,4 +1699,63 @@ TEST_F(TransferTest, StaticCast) { }); } +TEST_F(TransferTest, AddrOfValue) { + std::string Code = R"( + void target() { + int Foo; + int *Bar = &Foo; + // [[p]] + } + )"; + runDataflow(Code, + [](llvm::ArrayRef< + std::pair>> + Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results, ElementsAre(Pair("p", _))); + const Environment &Env = Results[0].second.Env; + + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); + ASSERT_THAT(BarDecl, NotNull()); + + const auto *FooLoc = cast( + Env.getStorageLocation(*FooDecl, SkipPast::None)); + const auto *BarVal = + cast(Env.getValue(*BarDecl, SkipPast::None)); + EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); + }); +} + +TEST_F(TransferTest, AddrOfReference) { + std::string Code = R"( + void target(int *Foo) { + int *Bar = &(*Foo); + // [[p]] + } + )"; + runDataflow(Code, + [](llvm::ArrayRef< + std::pair>> + Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results, ElementsAre(Pair("p", _))); + const Environment &Env = Results[0].second.Env; + + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); + ASSERT_THAT(BarDecl, NotNull()); + + const auto *FooVal = + cast(Env.getValue(*FooDecl, SkipPast::None)); + const auto *BarVal = + cast(Env.getValue(*BarDecl, SkipPast::None)); + EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc()); + }); +} + } // namespace -- 2.7.4