a.sidorin created this revision.
a.sidorin added reviewers: NoQ, dcoughlin, xazax.hun.
Herald added subscribers: cfe-commits, rnkovacs, szepet.
Herald added a reviewer: george.karpenkov.

Despite the fact that cast expressions return rvalues, GCC still handles  such 
outputs as lvalues when compiling inline assembler. Such code causes assertion 
failure in ExprEngine::VisitGCCAsmStmt. In this commit, we treat such rvalue 
outputs in the way similar to how CGStmt does it.


Repository:
  rC Clang

https://reviews.llvm.org/D45416

Files:
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/Analysis/asm.c


Index: test/Analysis/asm.c
===================================================================
--- /dev/null
+++ test/Analysis/asm.c
@@ -0,0 +1,10 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker debug.ExprInspection 
-fheinous-gnu-extensions -w %s -verify
+
+int clang_analyzer_eval(int);
+
+int global;
+void testRValueOutput() {
+  global = 1;
+  __asm__("" : "=r"((int)global));  // don't crash on rvalue output operand
+  clang_analyzer_eval(global == 1); // expected-warning{{UNKNOWN}}
+}
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3071,9 +3071,25 @@
   // outputs.
 
   ProgramStateRef state = Pred->getState();
+  const auto *LCtx = Pred->getLocationContext();
 
   for (const Expr *O : A->outputs()) {
-    SVal X = state->getSVal(O, Pred->getLocationContext());
+    // NOTE: GCC inline asm supports rvalue no-op-like casts as output
+    // arguments (-fheinous-gnu-extensions).
+    const Expr *LValueOutputE = O->IgnoreParenNoopCasts(getContext());
+    SVal X = state->getSVal(LValueOutputE, LCtx);
+    if (X.isUnknown()) {
+      // The value being casted to rvalue can be garbage-collected after
+      // the cast is modeled. Try to recover the memory region being casted
+      // if possible.
+      if (const auto *DRE = dyn_cast<DeclRefExpr>(LValueOutputE)) {
+        if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+          const VarRegion *VR =
+              getSValBuilder().getRegionManager().getVarRegion(VD, LCtx);
+          X = loc::MemRegionVal(VR);
+        }
+      }
+    }
     assert(!X.getAs<NonLoc>());  // Should be an Lval, or unknown, undef.
 
     if (Optional<Loc> LV = X.getAs<Loc>())


Index: test/Analysis/asm.c
===================================================================
--- /dev/null
+++ test/Analysis/asm.c
@@ -0,0 +1,10 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker debug.ExprInspection -fheinous-gnu-extensions -w %s -verify
+
+int clang_analyzer_eval(int);
+
+int global;
+void testRValueOutput() {
+  global = 1;
+  __asm__("" : "=r"((int)global));  // don't crash on rvalue output operand
+  clang_analyzer_eval(global == 1); // expected-warning{{UNKNOWN}}
+}
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3071,9 +3071,25 @@
   // outputs.
 
   ProgramStateRef state = Pred->getState();
+  const auto *LCtx = Pred->getLocationContext();
 
   for (const Expr *O : A->outputs()) {
-    SVal X = state->getSVal(O, Pred->getLocationContext());
+    // NOTE: GCC inline asm supports rvalue no-op-like casts as output
+    // arguments (-fheinous-gnu-extensions).
+    const Expr *LValueOutputE = O->IgnoreParenNoopCasts(getContext());
+    SVal X = state->getSVal(LValueOutputE, LCtx);
+    if (X.isUnknown()) {
+      // The value being casted to rvalue can be garbage-collected after
+      // the cast is modeled. Try to recover the memory region being casted
+      // if possible.
+      if (const auto *DRE = dyn_cast<DeclRefExpr>(LValueOutputE)) {
+        if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+          const VarRegion *VR =
+              getSValBuilder().getRegionManager().getVarRegion(VD, LCtx);
+          X = loc::MemRegionVal(VR);
+        }
+      }
+    }
     assert(!X.getAs<NonLoc>());  // Should be an Lval, or unknown, undef.
 
     if (Optional<Loc> LV = X.getAs<Loc>())
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to