Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions clang/lib/StaticAnalyzer/Core/CallEvent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,14 @@ static void findPtrToConstParams(llvm::SmallSet<unsigned, 4> &PreserveArgs,
}
}

static const MemRegion *getThisRegionBaseOrNull(const CallEvent &Call) {
if (const auto *CtorCall = dyn_cast<CXXConstructorCall>(&Call)) {
if (const MemRegion *R = CtorCall->getCXXThisVal().getAsRegion())
return R->getBaseRegion();
}
return nullptr;
}

ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
ProgramStateRef State) const {
// Don't invalidate anything if the callee is marked pure/const.
Expand All @@ -246,14 +254,26 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
if (!argumentsMayEscape())
findPtrToConstParams(PreserveArgs, *this);

// We should not preserve the contents of the region pointed by "this" when
// constructing the object, even if an argument refers to it.
const auto *ThisRegionBaseOrNull = getThisRegionBaseOrNull(*this);

for (unsigned Idx = 0, Count = getNumArgs(); Idx != Count; ++Idx) {
// Mark this region for invalidation. We batch invalidate regions
// below for efficiency.
if (PreserveArgs.count(Idx))
if (const MemRegion *MR = getArgSVal(Idx).getAsRegion())
ETraits.setTrait(MR->getBaseRegion(),
RegionAndSymbolInvalidationTraits::TK_PreserveContents);
// TODO: Factor this out + handle the lower level const pointers.
if (PreserveArgs.count(Idx)) {
if (const MemRegion *ArgBaseR = getArgSVal(Idx).getAsRegion()) {
ArgBaseR = ArgBaseR->getBaseRegion();

// Preserve the contents of the pointee of the argument - except if it
// refers to the object under construction (ctor call).
if (ArgBaseR != ThisRegionBaseOrNull) {
ETraits.setTrait(
ArgBaseR, RegionAndSymbolInvalidationTraits::TK_PreserveContents);
// TODO: Factor this out + handle the lower level const pointers.
}
}
}

ValuesToInvalidate.push_back(getArgSVal(Idx));

Expand Down
18 changes: 18 additions & 0 deletions clang/test/Analysis/call-invalidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,21 @@ int testNestedStdNamespacesAndRecords() {
int y = obj.uninit; // expected-warning {{Assigned value is uninitialized}}
return x + y;
}

struct SpecialVector {
SpecialVector(const void *); // Takes a const pointer!
int size() const {
return Size; // no-warning: We should not warn "uninitialized Size" because the ctor might have initialized it.
}
int Size;
};

void selfPtrPassedAsConstPointerToOpaqueCtorCall() {
// We construct a "SpecialVector" that takes the address of itself
// (or to a subobject somewhere itself) by a const-pointer.
// Despite the var region "buf" is mentioned via a const argument, the opaque
// ctor cal should still take presecedent and invalidate the underlying object.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// ctor cal should still take presecedent and invalidate the underlying object.
// ctor call should still take precedent and invalidate the underlying object.

SpecialVector buf(&buf);
buf.size();
}

Loading