Index: lib/StaticAnalyzer/Core/Store.cpp =================================================================== --- lib/StaticAnalyzer/Core/Store.cpp +++ lib/StaticAnalyzer/Core/Store.cpp @@ -15,6 +15,7 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" @@ -401,12 +402,23 @@ // These are anormal cases. Flag an undefined value. return UndefinedVal(); - case loc::ConcreteIntKind: - // While these seem funny, this can happen through casts. - // FIXME: What we should return is the field offset. For example, - // add the field offset to the integer value. That way funny things - // like this work properly: &(((struct foo *) 0xa)->f) + case loc::ConcreteIntKind: { + // Don't allow field offset calculations, if base is null. + if (!Base.isZeroConstant()) { + if (const auto *FD = dyn_cast(D)) { + if (FD->getKind() != Decl::ObjCIvar) { + ASTContext &Ctx = D->getASTContext(); + CharUnits CU = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FD)); + loc::ConcreteInt BasePtr = BaseL.castAs(); + llvm::APSInt Offset(Ctx.getTypeSize(Ctx.VoidPtrTy)); + Offset = CU.getQuantity(); + Offset += BasePtr.getValue(); + return svalBuilder.makeIntLocVal(Offset); + } + } + } return Base; + } default: llvm_unreachable("Unhandled Base."); Index: test/Analysis/array-struct-region.cpp =================================================================== --- test/Analysis/array-struct-region.cpp +++ test/Analysis/array-struct-region.cpp @@ -106,6 +106,28 @@ #endif } +struct FieldOffset { + int firstField; + char secondField[63]; + void *thirdField; +}; + +void testFieldOffsets() { + struct FieldOffset FO; + struct FieldOffset *PFONull = 0; + struct FieldOffset *PFOConstant = (struct FieldOffset *) 0x22; +#if __cplusplus + struct FieldOffset *PFONew = new struct FieldOffset; +#endif + clang_analyzer_eval((void *)&FO.secondField != (void*)&FO); // expected-warning{{TRUE}} + clang_analyzer_eval((void *)&FO.secondField != (void*)&FO.thirdField); // expected-warning{{TRUE}} + clang_analyzer_eval((void *)&PFONull->secondField != (void *)&PFONull->thirdField); // expected-warning{{FALSE}} + clang_analyzer_eval((void *)&PFONull->secondField == (void *)0); // expected-warning{{TRUE}} + clang_analyzer_eval((void *)&PFOConstant->secondField != (void*)PFOConstant); // expected-warning{{TRUE}} +#if __cplusplus + clang_analyzer_eval((void *)&PFONew->secondField != (void *)&PFONew); // expected-warning{{TRUE}} +#endif +} //-------------------- // C++-only tests Index: test/Analysis/ivars.m =================================================================== --- test/Analysis/ivars.m +++ test/Analysis/ivars.m @@ -138,3 +138,8 @@ int *x = &obj->uniqueID; return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} } + +void testFieldOffset() { + int *v = &((Root *)0x10)->uniqueID; + (void)v; +}