Index: lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -970,8 +970,10 @@ return Pred; ProgramStateRef state = C.getState(); - SymbolRef Sym = - state->getSValAsScalarOrLoc(RetE, C.getLocationContext()).getAsLocSymbol(); + // We need to dig down to the symbolic base here because various + // custom allocators do sometimes return the symbol with an offset. + SymbolRef Sym = state->getSValAsScalarOrLoc(RetE, C.getLocationContext()) + .getAsLocSymbol(/*IncludeBaseRegions=*/true); if (!Sym) return Pred; Index: test/Analysis/retain-release.mm =================================================================== --- test/Analysis/retain-release.mm +++ test/Analysis/retain-release.mm @@ -515,3 +515,35 @@ } } + +namespace reinterpret_casts { + +void *foo() { + void *p = const_cast( + reinterpret_cast(CFArrayCreate(0, 0, 0, 0))); + void *q = reinterpret_cast( + reinterpret_cast(p) + 1); + // FIXME: Should warn about a leak here. The function should return at +0, + // but it returns at +1 instead. + return q; +} + +void *fooCreate() { + void *p = const_cast( + reinterpret_cast(CFArrayCreate(0, 0, 0, 0))); + void *q = reinterpret_cast( + reinterpret_cast(p) + 1); + // The function follows the Create Rule. + return q; // no-warning +} + +void *fooBar() CF_RETURNS_RETAINED { + void *p = const_cast( + reinterpret_cast(CFArrayCreate(0, 0, 0, 0))); + void *q = reinterpret_cast( + reinterpret_cast(p) + 1); + // The function follows the Create Rule. + return q; // no-warning +} + +}