]> granicus.if.org Git - clang/commitdiff
Re-apply "[analyzer] Model casts to bool differently from other numbers."
authorJordan Rose <jordan_rose@apple.com>
Wed, 1 May 2013 18:19:59 +0000 (18:19 +0000)
committerJordan Rose <jordan_rose@apple.com>
Wed, 1 May 2013 18:19:59 +0000 (18:19 +0000)
This doesn't appear to be the cause of the slowdown. I'll have to try a
manual bisect to see if there's really anything there, or if it's just
the bot itself taking on additional load. Meanwhile, this change helps
with correctness.

This changes an assertion and adds a test case, then re-applies r180638,
which was reverted in r180714.

<rdar://problem/13296133> and PR15863

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

lib/StaticAnalyzer/Core/SValBuilder.cpp
lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
test/Analysis/bool-assignment.c
test/Analysis/casts.c
test/Analysis/stack-addr-ps.cpp
test/Analysis/stackaddrleak.c
test/Analysis/svalbuilder-logic.c

index 309230ebed0eb072cef1a81f456d8225c38f8dae..5bab986ed05a79422579454fd051ef0124f8546c 100644 (file)
@@ -327,6 +327,22 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
   if (val.isUnknownOrUndef() || castTy == originalTy)
     return val;
 
+  if (castTy->isBooleanType()) {
+    if (val.isUnknownOrUndef())
+      return val;
+    if (val.isConstant())
+      return makeTruthVal(!val.isZeroConstant(), castTy);
+    if (SymbolRef Sym = val.getAsSymbol()) {
+      BasicValueFactory &BVF = getBasicValueFactory();
+      // FIXME: If we had a state here, we could see if the symbol is known to
+      // be zero, but we don't.
+      return makeNonLoc(Sym, BO_NE, BVF.getValue(0, Sym->getType()), castTy);
+    }
+
+    assert(val.getAs<Loc>());
+    return makeTruthVal(true, castTy);
+  }
+
   // For const casts, casts to void, just propagate the value.
   if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
     if (shouldBeModeledWithNoOp(Context, Context.getPointerType(castTy),
index 61f9275ce886c419cf417c2d589b201643ae4e32..ee627f2baa352e9c74255426c3baf47f0e785c4e 100644 (file)
@@ -438,9 +438,13 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
           case BO_GE:
           case BO_EQ:
           case BO_NE:
+            assert(resultTy->isBooleanType() ||
+                   resultTy == getConditionType());
+            assert(symIntExpr->getType()->isBooleanType() ||
+                   getContext().hasSameUnqualifiedType(symIntExpr->getType(),
+                                                       getConditionType()));
             // Negate the comparison and make a value.
             opc = BinaryOperator::negateComparisonOp(opc);
-            assert(symIntExpr->getType() == resultTy);
             return makeNonLoc(symIntExpr->getLHS(), opc,
                 symIntExpr->getRHS(), resultTy);
           }
index 86a581def64e5afd2b50a5dcfe8cd16230a558f5..0f782fbfd9a9666ab0a1de066241d4a38b2fd276 100644 (file)
@@ -1,15 +1,19 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.BoolAssignment -analyzer-store=region -verify -std=c99 -Dbool=_Bool %s
 // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.BoolAssignment -analyzer-store=region -verify -x c++ %s
 
-// Test C++'s bool and C's _Bool
+// Test C++'s bool and C's _Bool.
+// FIXME: We stopped warning on these when SValBuilder got smarter about
+// casts to bool. Arguably, however, these conversions are okay; the result
+// is always 'true' or 'false'.
 
 void test_stdbool_initialization(int y) {
+  bool constant = 2; // no-warning
   if (y < 0) {
-    bool x = y; // expected-warning {{Assignment of a non-Boolean value}}
+    bool x = y; // no-warning
     return;
   }
   if (y > 1) {
-    bool x = y; // expected-warning {{Assignment of a non-Boolean value}}
+    bool x = y; // no-warning
     return;
   }
   bool x = y; // no-warning
@@ -18,11 +22,11 @@ void test_stdbool_initialization(int y) {
 void test_stdbool_assignment(int y) {
   bool x = 0; // no-warning
   if (y < 0) {
-    x = y; // expected-warning {{Assignment of a non-Boolean value}}
+    x = y; // no-warning
     return;
   }
   if (y > 1) {
-    x = y; // expected-warning {{Assignment of a non-Boolean value}}
+    x = y; // no-warning
     return;
   }
   x = y; // no-warning
@@ -33,6 +37,7 @@ void test_stdbool_assignment(int y) {
 typedef signed char BOOL;
 
 void test_BOOL_initialization(int y) {
+  BOOL constant = 2; // expected-warning {{Assignment of a non-Boolean value}}
   if (y < 0) {
     BOOL x = y; // expected-warning {{Assignment of a non-Boolean value}}
     return;
@@ -63,6 +68,7 @@ void test_BOOL_assignment(int y) {
 typedef unsigned char Boolean;
 
 void test_Boolean_initialization(int y) {
+  Boolean constant = 2; // expected-warning {{Assignment of a non-Boolean value}}
   if (y < 0) {
     Boolean x = y; // expected-warning {{Assignment of a non-Boolean value}}
     return;
index 087bd978e11388bc53932f5208fa7f8c2a9d2cab..3e2f8077ede04c86c70a79ff139b3a03d8726ae8 100644 (file)
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify %s
+
+extern void clang_analyzer_eval(_Bool);
 
 // Test if the 'storage' region gets properly initialized after it is cast to
 // 'struct sockaddr *'. 
@@ -85,3 +86,34 @@ int foo (int* p) {
   }
   return 0;
 }
+
+void castsToBool() {
+  clang_analyzer_eval(0); // expected-warning{{FALSE}}
+  clang_analyzer_eval(0U); // expected-warning{{FALSE}}
+  clang_analyzer_eval((void *)0); // expected-warning{{FALSE}}
+
+  clang_analyzer_eval(1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(1U); // expected-warning{{TRUE}}
+  clang_analyzer_eval(-1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(0x100); // expected-warning{{TRUE}}
+  clang_analyzer_eval(0x100U); // expected-warning{{TRUE}}
+  clang_analyzer_eval((void *)0x100); // expected-warning{{TRUE}}
+
+  extern int symbolicInt;
+  clang_analyzer_eval(symbolicInt); // expected-warning{{UNKNOWN}}
+  if (symbolicInt)
+    clang_analyzer_eval(symbolicInt); // expected-warning{{TRUE}}
+
+  extern void *symbolicPointer;
+  clang_analyzer_eval(symbolicPointer); // expected-warning{{UNKNOWN}}
+  if (symbolicPointer)
+    clang_analyzer_eval(symbolicPointer); // expected-warning{{TRUE}}
+
+  int localInt;
+  clang_analyzer_eval(&localInt); // expected-warning{{TRUE}}
+  clang_analyzer_eval(&castsToBool); // expected-warning{{TRUE}}
+  clang_analyzer_eval("abc"); // expected-warning{{TRUE}}
+
+  extern float globalFloat;
+  clang_analyzer_eval(globalFloat); // expected-warning{{UNKNOWN}}
+}
index 7aefea5095c78640ac5d3966e2d5bf443dc832f4..65d757154c87d6bc32b5dac51a80ef85155b260b 100644 (file)
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
 
-// FIXME: Only the stack-address checking in Sema catches this right now, and
-// the stack analyzer doesn't handle the ImplicitCastExpr (lvalue).
+typedef __INTPTR_TYPE__ intptr_t;
+
 const int& g() {
   int s;
   return s; // expected-warning{{Address of stack memory associated with local variable 's' returned}} expected-warning{{reference to stack memory associated with local variable 's' returned}}
@@ -96,3 +96,40 @@ void *radar13226577() {
     return p; // expected-warning {{stack memory associated with local variable 'p' returned to caller}}
 }
 
+namespace rdar13296133 {
+  class ConvertsToBool {
+  public:
+    operator bool() const { return this; }
+  };
+
+  class ConvertsToIntptr {
+  public:
+    operator intptr_t() const { return reinterpret_cast<intptr_t>(this); }
+  };
+
+  class ConvertsToPointer {
+  public:
+    operator const void *() const { return this; }
+  };
+
+  intptr_t returnAsNonLoc() {
+    ConvertsToIntptr obj;
+    return obj; // expected-warning{{Address of stack memory associated with local variable 'obj' returned to caller}}
+  }
+
+  bool returnAsBool() {
+    ConvertsToBool obj;
+    return obj; // no-warning
+  }
+
+  intptr_t returnAsNonLocViaPointer() {
+    ConvertsToPointer obj;
+    return reinterpret_cast<intptr_t>(static_cast<const void *>(obj)); // expected-warning{{Address of stack memory associated with local variable 'obj' returned to caller}}
+  }
+
+  bool returnAsBoolViaPointer() {
+    ConvertsToPointer obj;
+    return obj; // no-warning
+  }
+}
+
index 10564faff38ac3d32306eb3ce93ed2889591545c..4f81f6623e5188307c475603532264964249b4a1 100644 (file)
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -std=c99 -Dbool=_Bool %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -x c++ %s
 
+typedef __INTPTR_TYPE__ intptr_t;
 char const *p;
 
 void f0() {
@@ -15,7 +17,7 @@ void f1() {
 
 void f2() {
   p = (const char *) __builtin_alloca(12);
-} // expected-warning{{Address of stack memory allocated by call to alloca() on line 17 is still referred to by the global variable 'p' upon returning to the caller.  This will be a dangling reference}}
+} // expected-warning{{Address of stack memory allocated by call to alloca() on line 19 is still referred to by the global variable 'p' upon returning to the caller.  This will be a dangling reference}}
 
 // PR 7383 - previosly the stack address checker would crash on this example
 //  because it would attempt to do a direct load from 'pr7383_list'. 
@@ -32,3 +34,25 @@ void test_multi_return() {
   a = &x;
   b = &x;
 } // expected-warning{{Address of stack memory associated with local variable 'x' is still referred to by the global variable 'a' upon returning}} expected-warning{{Address of stack memory associated with local variable 'x' is still referred to by the global variable 'b' upon returning}}
+
+intptr_t returnAsNonLoc() {
+  int x;
+  return (intptr_t)&x; // expected-warning{{Address of stack memory associated with local variable 'x' returned to caller}}
+}
+
+bool returnAsBool() {
+  int x;
+  return &x; // no-warning
+}
+
+void assignAsNonLoc() {
+  extern intptr_t ip;
+  int x;
+  ip = (intptr_t)&x;
+} // expected-warning{{Address of stack memory associated with local variable 'x' is still referred to by the global variable 'ip' upon returning}}
+
+void assignAsBool() {
+  extern bool b;
+  int x;
+  b = &x;
+} // no-warning
index 41d4fe21c2f0018a0eeb153ed780a37d777c8826..9cf3f964bc0a7ce0be026bd81381993b9d6505f8 100644 (file)
@@ -6,3 +6,11 @@
 int SValBuilderLogicNoCrash(int *x) {
   return 3 - (int)(x +3);
 }
+
+// http://llvm.org/bugs/show_bug.cgi?id=15863
+// Don't crash when mixing 'bool' and 'int' in implicit comparisons to 0.
+void pr15863() {
+  extern int getBool();
+  _Bool a = getBool();
+  (void)!a; // no-warning
+}