Index: lib/StaticAnalyzer/Core/Store.cpp =================================================================== --- lib/StaticAnalyzer/Core/Store.cpp +++ lib/StaticAnalyzer/Core/Store.cpp @@ -378,6 +378,20 @@ if (castTy.isNull() || V.isUnknownOrUndef()) return V; + // 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 + // make sure that the retrieved value makes sense, because there's no other + // cast in the AST that would tell us to cast it to the correct pointer type. + // 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 (const auto *SR = dyn_cast_or_null(V.getAsRegion())) + if (SR->getSymbol()->getType().getCanonicalType() != + castTy.getCanonicalType()) + return loc::MemRegionVal(castRegion(SR, castTy)); + return svalBuilder.dispatchCast(V, castTy); } Index: test/Analysis/casts.c =================================================================== --- test/Analysis/casts.c +++ test/Analysis/casts.c @@ -149,3 +149,25 @@ clang_analyzer_eval(*((char *)y1) == *((char *) y3)); // expected-warning{{TRUE}} } + +void *getVoidPtr(); + +void testCastVoidPtrToIntPtrThroughIntTypedAssignment() { + int *x; + (*((int *)(&x))) = (int)getVoidPtr(); + *x = 1; // no-crash +} + +void testCastUIntPtrToIntPtrThroughIntTypedAssignment() { + unsigned u; + int *x; + (*((int *)(&x))) = (int)&u; + *x = 1; + clang_analyzer_eval(u == 1); // expected-warning{{TRUE}} +} + +void testCastVoidPtrToIntPtrThroughUIntTypedAssignment() { + int *x; + (*((int *)(&x))) = (int)(unsigned *)getVoidPtr(); + *x = 1; // no-crash +}