// 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;
// 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.
}
+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}}
+}
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.
// 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