diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-08-10 22:26:46 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-08-10 22:26:46 +0000 |
commit | b6d2bea04801cb66263de2f3fe99ef8e1dcd9f53 (patch) | |
tree | e56cb46315bfa93624640958c1de3c7944a0e6e7 | |
parent | 9584f67b6da17283a31dedf0a1cab2d83a3d121c (diff) |
[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>
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161710 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/StaticAnalyzer/Core/CallEvent.cpp | 26 | ||||
-rw-r--r-- | test/Analysis/inline.cpp | 38 |
2 files changed, 63 insertions, 1 deletions
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 0f24bce70b..619f9b200b 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -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)); } } diff --git a/test/Analysis/inline.cpp b/test/Analysis/inline.cpp index 4298e1aac8..9a867849e5 100644 --- a/test/Analysis/inline.cpp +++ b/test/Analysis/inline.cpp @@ -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(); + } +} + + |