]> granicus.if.org Git - clang/commitdiff
[analyzer] When failing to evaluate a __builtin_constant_p, presume it's false.
authorArtem Dergachev <artem.dergachev@gmail.com>
Wed, 3 Apr 2019 01:53:40 +0000 (01:53 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Wed, 3 Apr 2019 01:53:40 +0000 (01:53 +0000)
__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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@357557 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
test/Analysis/builtin-functions.cpp

index 290a03517920e260e7d2c9ef1c0f1a085542a5f8..8544f98b948dff103ece103f71e19acd4fb615a0 100644 (file)
@@ -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;
   }
index da2fcf915d31eb6935f6057595c17b030fb4791e..37e522049b17489732e2851d0a11171069456bec 100644 (file)
@@ -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}}
 }