ymandel created this revision. ymandel added reviewers: xazax.hun, gribozavr2. Herald added subscribers: martong, rnkovacs. Herald added a reviewer: NoQ. Herald added a project: All. ymandel requested review of this revision. Herald added a project: clang.
The handling of return statements, added in support of context-sensitive analysis, has a bug relating to functions that return reference types. Specifically, interpretation of such functions can result in a crash from a bad cast. This patch fixes the bug and guards all of that code with the context-sensitive option, since there's no reason to execute at all when context-sensitive analysis is off. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D140430 Files: clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp Index: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp =================================================================== --- clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -4018,6 +4018,35 @@ {TransferOptions{/*.ContextSensitiveOpts=*/std::nullopt}}); } +// This test is a regression test, based on a real crash. +TEST(TransferTest, ContextSensitiveReturnReferenceFromNonReferenceLvalue) { + // This code exercises an unusual code path. If we return an lvalue directly, + // the code will catch that it's an l-value based on the `Value`'s kind. If we + // pass through a dummy function, the framework won't populate a value at + // all. In contrast, this code results in a (fresh) value, but it is not + // `ReferenceValue`. This test verifies that we catch this case as well. + std::string Code = R"( + class S {}; + S& target(bool b, S &s) { + return b ? s : s; + // [[p]] + } + )"; + runDataflow( + Code, + [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + + auto *Loc = Env.getReturnStorageLocation(); + ASSERT_THAT(Loc, NotNull()); + + EXPECT_THAT(Env.getValue(*Loc), IsNull()); + }, + {TransferOptions{ContextSensitiveOptions{}}}); +} + TEST(TransferTest, ContextSensitiveDepthZero) { std::string Code = R"( bool GiveBool(); Index: clang/lib/Analysis/FlowSensitive/Transfer.cpp =================================================================== --- clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -429,6 +429,9 @@ } void VisitReturnStmt(const ReturnStmt *S) { + if (!Options.ContextSensitiveOpts) + return; + auto *Ret = S->getRetValue(); if (Ret == nullptr) return; @@ -443,6 +446,10 @@ auto *Loc = Env.getReturnStorageLocation(); assert(Loc != nullptr); + // FIXME: Support reference-type returns. + if (Loc->getType()->isReferenceType()) + return; + // FIXME: Model NRVO. Env.setValue(*Loc, *Val); }
Index: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp =================================================================== --- clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -4018,6 +4018,35 @@ {TransferOptions{/*.ContextSensitiveOpts=*/std::nullopt}}); } +// This test is a regression test, based on a real crash. +TEST(TransferTest, ContextSensitiveReturnReferenceFromNonReferenceLvalue) { + // This code exercises an unusual code path. If we return an lvalue directly, + // the code will catch that it's an l-value based on the `Value`'s kind. If we + // pass through a dummy function, the framework won't populate a value at + // all. In contrast, this code results in a (fresh) value, but it is not + // `ReferenceValue`. This test verifies that we catch this case as well. + std::string Code = R"( + class S {}; + S& target(bool b, S &s) { + return b ? s : s; + // [[p]] + } + )"; + runDataflow( + Code, + [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + + auto *Loc = Env.getReturnStorageLocation(); + ASSERT_THAT(Loc, NotNull()); + + EXPECT_THAT(Env.getValue(*Loc), IsNull()); + }, + {TransferOptions{ContextSensitiveOptions{}}}); +} + TEST(TransferTest, ContextSensitiveDepthZero) { std::string Code = R"( bool GiveBool(); Index: clang/lib/Analysis/FlowSensitive/Transfer.cpp =================================================================== --- clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -429,6 +429,9 @@ } void VisitReturnStmt(const ReturnStmt *S) { + if (!Options.ContextSensitiveOpts) + return; + auto *Ret = S->getRetValue(); if (Ret == nullptr) return; @@ -443,6 +446,10 @@ auto *Loc = Env.getReturnStorageLocation(); assert(Loc != nullptr); + // FIXME: Support reference-type returns. + if (Loc->getType()->isReferenceType()) + return; + // FIXME: Model NRVO. Env.setValue(*Loc, *Val); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits