/// \param IS the set of invalidated symbols.
/// \param Call if non-null, the invalidated regions represent parameters to
/// the call and should be considered directly invalidated.
- /// \param HTraits information about special handling for a particular
+ /// \param ITraits information about special handling for a particular
/// region/symbol.
ProgramStateRef
invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E,
unsigned BlockCount, const LocationContext *LCtx,
bool CausesPointerEscape, InvalidatedSymbols *IS = 0,
const CallEvent *Call = 0,
- RegionAndSymbolInvalidationTraits *HTraits = 0) const;
+ RegionAndSymbolInvalidationTraits *ITraits = 0) const;
ProgramStateRef
invalidateRegions(ArrayRef<SVal> Regions, const Expr *E,
unsigned BlockCount, const LocationContext *LCtx,
bool CausesPointerEscape, InvalidatedSymbols *IS = 0,
const CallEvent *Call = 0,
- RegionAndSymbolInvalidationTraits *HTraits = 0) const;
+ RegionAndSymbolInvalidationTraits *ITraits = 0) const;
/// enterStackFrame - Returns the state for entry to the given stack frame,
/// preserving the current state.
SVal val) const;
static ProgramStateRef InvalidateBuffer(CheckerContext &C,
- ProgramStateRef state,
- const Expr *Ex, SVal V);
+ ProgramStateRef state,
+ const Expr *Ex, SVal V,
+ bool IsSourceBuffer);
static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
const MemRegion *MR);
}
ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
- ProgramStateRef state,
- const Expr *E, SVal V) {
+ ProgramStateRef state,
+ const Expr *E, SVal V,
+ bool IsSourceBuffer) {
Optional<Loc> L = V.getAs<Loc>();
if (!L)
return state;
// Invalidate this region.
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- return state->invalidateRegions(R, E, C.blockCount(), LCtx,
- /*CausesPointerEscape*/ false);
+
+ bool CausesPointerEscape = false;
+ RegionAndSymbolInvalidationTraits ITraits;
+ // Invalidate and escape only indirect regions accessible through the source
+ // buffer.
+ if (IsSourceBuffer) {
+ ITraits.setTrait(R,
+ RegionAndSymbolInvalidationTraits::TK_PreserveContents);
+ ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape);
+ CausesPointerEscape = true;
+ }
+
+ return state->invalidateRegions(R, E, C.blockCount(), LCtx,
+ CausesPointerEscape, 0, 0, &ITraits);
}
// If we have a non-region value by chance, just remove the binding.
state = state->BindExpr(CE, LCtx, destVal);
}
- // Invalidate the destination.
+ // Invalidate the destination (regular invalidation without pointer-escaping
+ // the address of the top-level region).
// FIXME: Even if we can't perfectly model the copy, we should see if we
// can use LazyCompoundVals to copy the source values into the destination.
// This would probably remove any existing bindings past the end of the
// copied region, but that's still an improvement over blank invalidation.
- state = InvalidateBuffer(C, state, Dest,
- state->getSVal(Dest, C.getLocationContext()));
+ state = InvalidateBuffer(C, state, Dest, C.getSVal(Dest),
+ /*IsSourceBuffer*/false);
+
+ // Invalidate the source (const-invalidation without const-pointer-escaping
+ // the address of the top-level region).
+ state = InvalidateBuffer(C, state, Source, C.getSVal(Source),
+ /*IsSourceBuffer*/true);
+
C.addTransition(state);
}
}
Result = lastElement;
}
- // Invalidate the destination. This must happen before we set the C string
- // length because invalidation will clear the length.
+ // Invalidate the destination (regular invalidation without pointer-escaping
+ // the address of the top-level region). This must happen before we set the
+ // C string length because invalidation will clear the length.
// FIXME: Even if we can't perfectly model the copy, we should see if we
// can use LazyCompoundVals to copy the source values into the destination.
// This would probably remove any existing bindings past the end of the
// string, but that's still an improvement over blank invalidation.
- state = InvalidateBuffer(C, state, Dst, *dstRegVal);
+ state = InvalidateBuffer(C, state, Dst, *dstRegVal,
+ /*IsSourceBuffer*/false);
+
+ // Invalidate the source (const-invalidation without const-pointer-escaping
+ // the address of the top-level region).
+ state = InvalidateBuffer(C, state, srcExpr, srcVal, /*IsSourceBuffer*/true);
// Set the C string length of the destination, if we know it.
if (isBounded && !isAppending) {
// Invalidate the search string, representing the change of one delimiter
// character to NUL.
- State = InvalidateBuffer(C, State, SearchStrPtr, Result);
+ State = InvalidateBuffer(C, State, SearchStrPtr, Result,
+ /*IsSourceBuffer*/false);
// Overwrite the search string pointer. The new value is either an address
// further along in the same string, or NULL if there are no more tokens.
char *p = malloc(12);
strlen(p);
strcpy(p, s);
+ strcpy(s, p);
+ strcpy(p, p);
+ memcpy(p, s, 1);
+ memcpy(s, p, 1);
+ memcpy(p, p, 1);
} // expected-warning {{leak}}
+// Treat source buffer contents as escaped.
+void escapeSourceContents(char *s) {
+ char *p = malloc(12);
+ memcpy(s, &p, 12); // no warning
+
+ void *p1 = malloc(7);
+ char *a;
+ memcpy(&a, &p1, sizeof a);
+ // FIXME: No warning due to limitations imposed by current modelling of
+ // 'memcpy' (regions metadata is not copied).
+
+ int *ptrs[2];
+ int *allocated = (int *)malloc(4);
+ memcpy(&ptrs[0], &allocated, sizeof(int *));
+ // FIXME: No warning due to limitations imposed by current modelling of
+ // 'memcpy' (regions metadata is not copied).
+}
+
+void invalidateDestinationContents() {
+ int *null = 0;
+ int *p = (int *)malloc(4);
+ memcpy(&p, &null, sizeof(int *));
+
+ int *ptrs1[2]; // expected-warning {{Potential leak of memory pointed to by}}
+ ptrs1[0] = (int *)malloc(4);
+ memcpy(ptrs1, &null, sizeof(int *));
+
+ int *ptrs2[2]; // expected-warning {{Potential memory leak}}
+ ptrs2[0] = (int *)malloc(4);
+ memcpy(&ptrs2[1], &null, sizeof(int *));
+
+ int *ptrs3[2]; // expected-warning {{Potential memory leak}}
+ ptrs3[0] = (int *)malloc(4);
+ memcpy(&ptrs3[0], &null, sizeof(int *));
+} // expected-warning {{Potential memory leak}}
+
// Rely on the CString checker evaluation of the strcpy API to convey that the result of strcpy is equal to p.
void symbolLostWithStrcpy(char *s) {
char *p = malloc(12);