Index: include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -53,6 +53,8 @@ iterator begin() const { return L.begin(); } iterator end() const { return L.end(); } + QualType getType() const { return T; } + static void Profile(llvm::FoldingSetNodeID& ID, QualType T, llvm::ImmutableList L); Index: include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -205,6 +205,8 @@ SymExpr::symbol_iterator symbol_end() const { return SymExpr::symbol_end(); } + + QualType detectType(ASTContext &ACtx) const; }; inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) { Index: lib/StaticAnalyzer/Core/SVals.cpp =================================================================== --- lib/StaticAnalyzer/Core/SVals.cpp +++ lib/StaticAnalyzer/Core/SVals.cpp @@ -21,6 +21,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "llvm/ADT/Optional.h" @@ -185,6 +186,59 @@ return DD; } +namespace { +class TypeDetector : public SValVisitor { + ASTContext &ACtx; + +public: + TypeDetector(ASTContext &ACtx): ACtx(ACtx) {} + + QualType VisitSVal(SVal V) { return QualType(); } + + QualType VisitNonLocSymbolVal(nonloc::SymbolVal V) { + return V.getSymbol()->getType(); + } + + QualType VisitLocMemRegionVal(loc::MemRegionVal V) { + if (const auto *TR = dyn_cast(V.getRegion())) + return TR->getLocationType(); + else + return ACtx.VoidPtrTy; + } + + QualType VisitNonLocConcreteInt(nonloc::ConcreteInt V) { + const llvm::APSInt &I = V.getValue(); + return ACtx.getIntTypeForBitwidth(I.getBitWidth(), I.isSigned()); + } + + QualType VisitLocConcreteInt(loc::ConcreteInt V) { + return ACtx.VoidPtrTy; + } + + QualType VisitNonLocLocAsInteger(nonloc::LocAsInteger V) { + // FIXME: This returns an unsigned type because LocAsInteger + // does not remember what is the correct type. + return ACtx.getIntTypeForBitwidth(V.getNumBits(), false); + } + + QualType VisitNonLocCompoundVal(nonloc::CompoundVal V) { + return V.getValue()->getType(); + } + + QualType VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) { + if (const auto *TVR = dyn_cast(V.getRegion())) + return TVR->getValueType(); + return QualType(); + } + + // TODO: VisitNonLocPointerToMember! +}; +} + +QualType SVal::detectType(ASTContext &ACtx) const { + return TypeDetector(ACtx).Visit(*this); +} + //===----------------------------------------------------------------------===// // Other Iterators. //===----------------------------------------------------------------------===// Index: lib/StaticAnalyzer/Core/Store.cpp =================================================================== --- lib/StaticAnalyzer/Core/Store.cpp +++ lib/StaticAnalyzer/Core/Store.cpp @@ -394,14 +394,29 @@ return UnknownVal(); } +static bool isScalarEnoughToAttemptACast(QualType T) { + return T->isIntegralOrEnumerationType() || Loc::isLocType(T); +} + /// CastRetrievedVal - Used by subclasses of StoreManager to implement /// implicit casts that arise from loads from regions that are reinterpreted /// as another region. SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R, - QualType castTy) { - if (castTy.isNull() || V.isUnknownOrUndef()) + QualType CastTy) { + if (CastTy.isNull() || V.isUnknownOrUndef()) + return V; + + QualType OrigTy = V.detectType(StateMgr.getContext()); + if (OrigTy.isNull()) return V; + if (!isScalarEnoughToAttemptACast(OrigTy) || + !isScalarEnoughToAttemptACast(CastTy)) { + if (OrigTy.getUnqualifiedType() == CastTy.getUnqualifiedType()) + return V; + 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 @@ -410,13 +425,13 @@ // We might need to do that for non-void pointers as well. // FIXME: We really need a single good function to perform casts for us // correctly every time we need it. - if (castTy->isPointerType() && !castTy->isVoidPointerType()) + if (CastTy->isPointerType() && !CastTy->isVoidPointerType()) if (const auto *SR = dyn_cast_or_null(V.getAsRegion())) if (SR->getSymbol()->getType().getCanonicalType() != - castTy.getCanonicalType()) - return loc::MemRegionVal(castRegion(SR, castTy)); + CastTy.getCanonicalType()) + return loc::MemRegionVal(castRegion(SR, CastTy)); - return svalBuilder.dispatchCast(V, castTy); + return svalBuilder.dispatchCast(V, CastTy); } SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) { Index: test/Analysis/casts.c =================================================================== --- test/Analysis/casts.c +++ 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; +} +