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