Index: cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -321,11 +321,6 @@ return; } - if (!isa(Sym)) { - reportBug("Not an atomic symbol", C); - return; - } - const auto *E = dyn_cast(CE->getArg(1)->IgnoreParenCasts()); if (!E) { reportBug("Not a string literal", C); @@ -345,7 +340,7 @@ public: SymbolExpressor(ProgramStateRef State) : State(State) {} - Optional VisitSymExpr(const SymExpr *S) { + Optional lookup(const SymExpr *S) { if (const StringLiteral *const *SLPtr = State->get(S)) { const StringLiteral *SL = *SLPtr; return std::string(SL->getBytes()); @@ -353,8 +348,14 @@ return None; } + Optional VisitSymExpr(const SymExpr *S) { + return lookup(S); + } + Optional VisitSymIntExpr(const SymIntExpr *S) { - if (auto Str = Visit(S->getLHS())) + if (Optional Str = lookup(S)) + return Str; + if (Optional Str = Visit(S->getLHS())) return (*Str + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) + " " + std::to_string(S->getRHS().getLimitedValue()) + (S->getRHS().isUnsigned() ? "U" : "")) @@ -363,12 +364,22 @@ } Optional VisitSymSymExpr(const SymSymExpr *S) { - if (auto Str1 = Visit(S->getLHS())) - if (auto Str2 = Visit(S->getRHS())) + if (Optional Str = lookup(S)) + return Str; + if (Optional Str1 = Visit(S->getLHS())) + if (Optional Str2 = Visit(S->getRHS())) return (*Str1 + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) + " " + *Str2).str(); return None; } + + Optional VisitSymbolCast(const SymbolCast *S) { + if (Optional Str = lookup(S)) + return Str; + if (Optional Str = Visit(S->getOperand())) + return (Twine("(") + S->getType().getAsString() + ")" + *Str).str(); + return None; + } }; } // namespace Index: cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp @@ -402,6 +402,17 @@ if (castTy.isNull() || V.isUnknownOrUndef()) return V; + // The dispatchCast() call below would convert the int into a float. + // What we want, however, is a bit-by-bit reinterpretation of the int + // as a float, which usually yields nothing garbage. For now skip casts + // from ints to floats. + // TODO: What other combinations of types are affected? + if (castTy->isFloatingType()) { + SymbolRef Sym = V.getAsSymbol(); + if (Sym && !Sym->getType()->isFloatingType()) + return UnknownVal(); + } + // When retrieving symbolic pointer and expecting a non-void pointer, // wrap them into element regions of the expected type if necessary. // SValBuilder::dispatchCast() doesn't do that, but it is necessary to Index: cfe/trunk/test/Analysis/casts.c =================================================================== --- cfe/trunk/test/Analysis/casts.c +++ cfe/trunk/test/Analysis/casts.c @@ -213,3 +213,35 @@ } #endif + +char no_crash_SymbolCast_of_float_type_aux(int *p) { + *p += 1; + return *p; +} + +void no_crash_SymbolCast_of_float_type() { + extern float x; + char (*f)() = no_crash_SymbolCast_of_float_type_aux; + f(&x); +} + +double no_crash_reinterpret_double_as_int(double a) { + *(int *)&a = 1; + return a * a; +} + +double no_crash_reinterpret_double_as_ptr(double a) { + *(void **)&a = 0; + return a * a; +} + +double no_crash_reinterpret_double_as_sym_int(double a, int b) { + *(int *)&a = b; + return a * a; +} + +double no_crash_reinterpret_double_as_sym_ptr(double a, void * b) { + *(void **)&a = b; + return a * a; +} + Index: cfe/trunk/test/Analysis/casts.cpp =================================================================== --- cfe/trunk/test/Analysis/casts.cpp +++ cfe/trunk/test/Analysis/casts.cpp @@ -102,3 +102,15 @@ castToDerived(reinterpret_cast(ORef))->getNotInt(); } } // namespace base_to_derived_opaque_class + +namespace bool_to_nullptr { +struct S { + int *a[1]; + bool b; +}; +void foo(S s) { + s.b = true; + for (int i = 0; i < 2; ++i) + (void)(s.a[i] != nullptr); // no-crash +} +} // namespace bool_to_nullptr Index: cfe/trunk/test/Analysis/expr-inspection.cpp =================================================================== --- cfe/trunk/test/Analysis/expr-inspection.cpp +++ cfe/trunk/test/Analysis/expr-inspection.cpp @@ -24,7 +24,7 @@ clang_analyzer_denote(1, "$z"); // expected-warning{{Not a symbol}} clang_analyzer_express(1); // expected-warning{{Not a symbol}} - clang_analyzer_denote(x + 1, "$w"); // expected-warning{{Not an atomic symbol}} - clang_analyzer_express(x + 1); // expected-warning{{$x + 1}} + clang_analyzer_denote(x + 1, "$w"); + clang_analyzer_express(x + 1); // expected-warning{{$w}} clang_analyzer_express(y + 1); // expected-warning{{$y + 1U}} } Index: cfe/trunk/test/Analysis/svalbuilder-float-cast.c =================================================================== --- cfe/trunk/test/Analysis/svalbuilder-float-cast.c +++ cfe/trunk/test/Analysis/svalbuilder-float-cast.c @@ -0,0 +1,20 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker debug.ExprInspection -verify %s +void clang_analyzer_denote(int, const char *); +void clang_analyzer_express(int); + +void SymbolCast_of_float_type_aux(int *p) { + *p += 0; + // FIXME: Ideally, all unknown values should be symbolicated. + clang_analyzer_denote(*p, "$x"); // expected-warning{{Not a symbol}} + + *p += 1; + // This should NOT be (float)$x + 1. Symbol $x was never casted to float. + // FIXME: Ideally, this should be $x + 1. + clang_analyzer_express(*p); // expected-warning{{Not a symbol}} +} + +void SymbolCast_of_float_type() { + extern float x; + void (*f)() = SymbolCast_of_float_type_aux; + f(&x); +}