Index: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -920,7 +920,7 @@ // Invalidate and escape only indirect regions accessible through the source // buffer. if (IsSourceBuffer) { - ITraits.setTrait(R, + ITraits.setTrait(R->getBaseRegion(), RegionAndSymbolInvalidationTraits::TK_PreserveContents); ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape); CausesPointerEscape = true; Index: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -177,7 +177,7 @@ // below for efficiency. if (PreserveArgs.count(Idx)) if (const MemRegion *MR = getArgSVal(Idx).getAsRegion()) - ETraits.setTrait(MR->StripCasts(), + ETraits.setTrait(MR->getBaseRegion(), RegionAndSymbolInvalidationTraits::TK_PreserveContents); // TODO: Factor this out + handle the lower level const pointers. Index: cfe/trunk/test/Analysis/call-invalidation.cpp =================================================================== --- cfe/trunk/test/Analysis/call-invalidation.cpp +++ cfe/trunk/test/Analysis/call-invalidation.cpp @@ -118,3 +118,50 @@ } +struct PlainStruct { + int x, y; + mutable int z; +}; + +PlainStruct glob; + +void useAnything(void *); +void useAnythingConst(const void *); + +void testInvalidationThroughBaseRegionPointer() { + PlainStruct s1; + s1.x = 1; + s1.z = 1; + clang_analyzer_eval(s1.x == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(s1.z == 1); // expected-warning{{TRUE}} + // Not only passing a structure pointer through const pointer parameter, + // but also passing a field pointer through const pointer parameter + // should preserve the contents of the structure. + useAnythingConst(&(s1.y)); + clang_analyzer_eval(s1.x == 1); // expected-warning{{TRUE}} + // FIXME: Should say "UNKNOWN", because it is not uncommon to + // modify a mutable member variable through const pointer. + clang_analyzer_eval(s1.z == 1); // expected-warning{{TRUE}} + useAnything(&(s1.y)); + clang_analyzer_eval(s1.x == 1); // expected-warning{{UNKNOWN}} +} + + +void useFirstConstSecondNonConst(const void *x, void *y); +void useFirstNonConstSecondConst(void *x, const void *y); + +void testMixedConstNonConstCalls() { + PlainStruct s2; + s2.x = 1; + useFirstConstSecondNonConst(&(s2.x), &(s2.y)); + clang_analyzer_eval(s2.x == 1); // expected-warning{{UNKNOWN}} + s2.x = 1; + useFirstNonConstSecondConst(&(s2.x), &(s2.y)); + clang_analyzer_eval(s2.x == 1); // expected-warning{{UNKNOWN}} + s2.y = 1; + useFirstConstSecondNonConst(&(s2.x), &(s2.y)); + clang_analyzer_eval(s2.y == 1); // expected-warning{{UNKNOWN}} + s2.y = 1; + useFirstNonConstSecondConst(&(s2.x), &(s2.y)); + clang_analyzer_eval(s2.y == 1); // expected-warning{{UNKNOWN}} +} Index: cfe/trunk/test/Analysis/malloc.c =================================================================== --- cfe/trunk/test/Analysis/malloc.c +++ cfe/trunk/test/Analysis/malloc.c @@ -1750,6 +1750,19 @@ fake_rb_tree_insert_node(rbt, data); // no warning } +struct IntAndPtr { + int x; + int *p; +}; + +void constEscape(const void *ptr); + +void testConstEscapeThroughAnotherField() { + struct IntAndPtr s; + s.p = malloc(sizeof(int)); + constEscape(&(s.x)); // could free s->p! +} // no-warning + // ---------------------------------------------------------------------------- // False negatives. @@ -1769,3 +1782,9 @@ // FIXME: This is a leak: if we think a system function won't free p, it // won't free (p-1) either. } + +void testMallocIntoMalloc() { + StructWithPtr *s = malloc(sizeof(StructWithPtr)); + s->memP = malloc(sizeof(int)); + free(s); +} // FIXME: should warn here