forked from OSchip/llvm-project
[analyzer] Strip CXXBaseObjectRegions when devirtualizing method calls.
This was causing a crash when we tried to re-apply a base object region to itself. It probably also caused incorrect offset calculations in RegionStore. PR13569 / <rdar://problem/12076683> llvm-svn: 161710
This commit is contained in:
parent
51bcb226a2
commit
02e5309b35
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "clang/AST/CXXInheritance.h"
|
||||
#include "clang/AST/ParentMap.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
|
@ -408,11 +409,34 @@ void CXXInstanceCall::getInitialStackFrameContents(
|
|||
BindingsTy &Bindings) const {
|
||||
AnyFunctionCall::getInitialStackFrameContents(CalleeCtx, Bindings);
|
||||
|
||||
// Handle the binding of 'this' in the new stack frame.
|
||||
// We need to make sure we have the proper layering of CXXBaseObjectRegions.
|
||||
SVal ThisVal = getCXXThisVal();
|
||||
if (!ThisVal.isUnknown()) {
|
||||
SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
|
||||
ProgramStateManager &StateMgr = getState()->getStateManager();
|
||||
SValBuilder &SVB = StateMgr.getSValBuilder();
|
||||
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CalleeCtx->getDecl());
|
||||
Loc ThisLoc = SVB.getCXXThis(MD, CalleeCtx);
|
||||
|
||||
if (const MemRegion *ThisReg = ThisVal.getAsRegion()) {
|
||||
const CXXRecordDecl *Class = MD->getParent();
|
||||
|
||||
// We may be downcasting to call a devirtualized virtual method.
|
||||
// Search through the base casts we already have to see if we can just
|
||||
// strip them off.
|
||||
const CXXBaseObjectRegion *BaseReg;
|
||||
while ((BaseReg = dyn_cast<CXXBaseObjectRegion>(ThisReg))) {
|
||||
if (BaseReg->getDecl() == Class)
|
||||
break;
|
||||
ThisReg = BaseReg->getSuperRegion();
|
||||
}
|
||||
|
||||
// Either we found the right base class, or we stripped all the casts to
|
||||
// the most derived type. Either one is good.
|
||||
ThisVal = loc::MemRegionVal(ThisReg);
|
||||
}
|
||||
|
||||
Bindings.push_back(std::make_pair(ThisLoc, ThisVal));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,3 +71,41 @@ namespace PureVirtualParent {
|
|||
}
|
||||
|
||||
|
||||
namespace PR13569 {
|
||||
class Parent {
|
||||
protected:
|
||||
int m_parent;
|
||||
virtual int impl() const = 0;
|
||||
|
||||
Parent() : m_parent(0) {}
|
||||
|
||||
public:
|
||||
int interface() const {
|
||||
clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
|
||||
return impl();
|
||||
}
|
||||
};
|
||||
|
||||
class Child : public Parent {
|
||||
protected:
|
||||
virtual int impl() const {
|
||||
clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
|
||||
return m_parent + m_child;
|
||||
}
|
||||
|
||||
public:
|
||||
Child() : m_child(0) {}
|
||||
|
||||
int m_child;
|
||||
};
|
||||
|
||||
void testVirtual() {
|
||||
Child x;
|
||||
x.m_child = 42;
|
||||
|
||||
// Don't crash when inlining and devirtualizing.
|
||||
x.interface();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue