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
  • [PATCH] D140430: [clang... Yitzhak Mandelbaum via Phabricator via cfe-commits

Reply via email to