From f7887d41cbd73cad2e92eea60c710e4f263cdf18 Mon Sep 17 00:00:00 2001 From: Artem Dergachev Date: Wed, 3 Apr 2019 01:53:40 +0000 Subject: [PATCH] [analyzer] When failing to evaluate a __builtin_constant_p, presume it's false. __builtin_constant_p(x) is a compiler builtin that evaluates to 1 when its argument x is a compile-time constant and to 0 otherwise. In CodeGen it is simply lowered to the respective LLVM intrinsic. In the Analyzer we've been trying to delegate modeling to Expr::EvaluateAsInt, which is allowed to sometimes fail for no apparent reason. When it fails, let's conservatively return false. Modeling it as false is pretty much never wrong, and it is only required to return true on a best-effort basis, which every user should expect. Fixes VLAChecker false positives on code that tries to emulate static asserts in C by constructing a VLA of dynamic size -1 under the assumption that this dynamic size is actually a constant in the sense of __builtin_constant_p. Differential Revision: https://reviews.llvm.org/D60110 llvm-svn: 357557 --- clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp | 10 +++++++++- clang/test/Analysis/builtin-functions.cpp | 9 +++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp index 290a035..8544f98 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -100,17 +100,25 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE, case Builtin::BI__builtin_constant_p: { // This must be resolvable at compile time, so we defer to the constant // evaluator for a value. + SValBuilder &SVB = C.getSValBuilder(); SVal V = UnknownVal(); Expr::EvalResult EVResult; if (CE->EvaluateAsInt(EVResult, C.getASTContext(), Expr::SE_NoSideEffects)) { // Make sure the result has the correct type. llvm::APSInt Result = EVResult.Val.getInt(); - SValBuilder &SVB = C.getSValBuilder(); BasicValueFactory &BVF = SVB.getBasicValueFactory(); BVF.getAPSIntType(CE->getType()).apply(Result); V = SVB.makeIntVal(Result); } + if (FD->getBuiltinID() == Builtin::BI__builtin_constant_p) { + // If we didn't manage to figure out if the value is constant or not, + // it is safe to assume that it's not constant and unsafe to assume + // that it's constant. + if (V.isUnknown()) + V = SVB.makeIntVal(0, CE->getType()); + } + C.addTransition(state->BindExpr(CE, LCtx, V)); return true; } diff --git a/clang/test/Analysis/builtin-functions.cpp b/clang/test/Analysis/builtin-functions.cpp index da2fcf9..37e5220 100644 --- a/clang/test/Analysis/builtin-functions.cpp +++ b/clang/test/Analysis/builtin-functions.cpp @@ -65,19 +65,20 @@ void g(int i) { } } -void test_constant_p() { +void test_constant_p(void *ptr) { int i = 1; const int j = 2; constexpr int k = 3; clang_analyzer_eval(__builtin_constant_p(42) == 1); // expected-warning {{TRUE}} - clang_analyzer_eval(__builtin_constant_p(i) == 0); // expected-warning {{UNKNOWN}} + clang_analyzer_eval(__builtin_constant_p(i) == 0); // expected-warning {{TRUE}} clang_analyzer_eval(__builtin_constant_p(j) == 1); // expected-warning {{TRUE}} clang_analyzer_eval(__builtin_constant_p(k) == 1); // expected-warning {{TRUE}} - clang_analyzer_eval(__builtin_constant_p(i + 42) == 0); // expected-warning {{UNKNOWN}} + clang_analyzer_eval(__builtin_constant_p(i + 42) == 0); // expected-warning {{TRUE}} clang_analyzer_eval(__builtin_constant_p(j + 42) == 1); // expected-warning {{TRUE}} clang_analyzer_eval(__builtin_constant_p(k + 42) == 1); // expected-warning {{TRUE}} clang_analyzer_eval(__builtin_constant_p(" ") == 1); // expected-warning {{TRUE}} - clang_analyzer_eval(__builtin_constant_p(test_constant_p) == 0); // expected-warning {{UNKNOWN}} + clang_analyzer_eval(__builtin_constant_p(test_constant_p) == 0); // expected-warning {{TRUE}} clang_analyzer_eval(__builtin_constant_p(k - 3) == 0); // expected-warning {{FALSE}} clang_analyzer_eval(__builtin_constant_p(k - 3) == 1); // expected-warning {{TRUE}} + clang_analyzer_eval(__builtin_constant_p(ptr == 0)); // expected-warning {{FALSE}} } -- 2.7.4