diff options
author | Anna Zaks <ganna@apple.com> | 2011-12-20 22:35:30 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2011-12-20 22:35:30 +0000 |
commit | 2cbe791d3e9b26f30196c4852da75d9ad67b4ad9 (patch) | |
tree | 0fae159435699e0f6287b60932699a97549cd868 /lib/StaticAnalyzer/Core | |
parent | b5ea9db3cf47e8d4bc60d922331773dbfd265c6f (diff) |
[analyzer] Do not invalidate arguments when the parameter's
type is a pointer to const. (radar://10595327)
The regions corresponding to the pointer and reference arguments to
a function get invalidated by the calls since a function call can
possibly modify the pointed to data. With this change, we are not going
to invalidate the data if the argument is a pointer to const. This
change makes the analyzer more optimistic in reporting errors.
(Support for C, C++ and Obj C)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147002 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 54 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ObjCMessage.cpp | 19 |
2 files changed, 70 insertions, 3 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index dc49c85a97..46ebd84b65 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -63,6 +63,46 @@ void ExprEngine::processCallExit(CallExitNodeBuilder &B) { B.generateNode(state); } +static bool isPointerToConst(const ParmVarDecl *ParamDecl) { + QualType PointeeTy = ParamDecl->getOriginalType()->getPointeeType(); + if (PointeeTy != QualType() && PointeeTy.isConstQualified() && + !PointeeTy->isAnyPointerType() && !PointeeTy->isReferenceType()) { + return true; + } + return false; +} + +// Try to retrieve the function declaration and find the function parameter +// types which are pointers/references to a non-pointer const. +// We do not invalidate the corresponding argument regions. +static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, + const CallOrObjCMessage &Call) { + const Decl *CallDecl = Call.getDecl(); + if (!CallDecl) + return; + + if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) { + for (unsigned Idx = 0, E = Call.getNumArgs(); Idx != E; ++Idx) { + if (FDecl && Idx < FDecl->getNumParams()) { + if (isPointerToConst(FDecl->getParamDecl(Idx))) + PreserveArgs.insert(Idx); + } + } + return; + } + + if (const ObjCMethodDecl *MDecl = dyn_cast<ObjCMethodDecl>(CallDecl)) { + assert(MDecl->param_size() <= Call.getNumArgs()); + unsigned Idx = 0; + for (clang::ObjCMethodDecl::param_const_iterator + I = MDecl->param_begin(), E = MDecl->param_end(); I != E; ++I, ++Idx) { + if (isPointerToConst(*I)) + PreserveArgs.insert(Idx); + } + return; + } +} + const ProgramState * ExprEngine::invalidateArguments(const ProgramState *State, const CallOrObjCMessage &Call, @@ -84,13 +124,21 @@ ExprEngine::invalidateArguments(const ProgramState *State, } else if (Call.isFunctionCall()) { // Block calls invalidate all captured-by-reference values. - if (const MemRegion *Callee = Call.getFunctionCallee().getAsRegion()) { + SVal CalleeVal = Call.getFunctionCallee(); + if (const MemRegion *Callee = CalleeVal.getAsRegion()) { if (isa<BlockDataRegion>(Callee)) RegionsToInvalidate.push_back(Callee); } } + // Indexes of arguments whose values will be preserved by the call. + llvm::SmallSet<unsigned, 1> PreserveArgs; + findPtrToConstParams(PreserveArgs, Call); + for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) { + if (PreserveArgs.count(idx)) + continue; + SVal V = Call.getArgSVal(idx); // If we are passing a location wrapped as an integer, unwrap it and @@ -104,7 +152,7 @@ ExprEngine::invalidateArguments(const ProgramState *State, // Invalidate the value of the variable passed by reference. // Are we dealing with an ElementRegion? If the element type is - // a basic integer type (e.g., char, int) and the underying region + // a basic integer type (e.g., char, int) and the underlying region // is a variable region then strip off the ElementRegion. // FIXME: We really need to think about this for the general case // as sometimes we are reasoning about arrays and other times @@ -115,7 +163,7 @@ ExprEngine::invalidateArguments(const ProgramState *State, // we'll leave it in for now until we have a systematic way of // handling all of these cases. Eventually we need to come up // with an interface to StoreManager so that this logic can be - // approriately delegated to the respective StoreManagers while + // appropriately delegated to the respective StoreManagers while // still allowing us to do checker-specific logic (e.g., // invalidating reference counts), probably via callbacks. if (ER->getElementType()->isIntegralOrEnumerationType()) { diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp index 0974fe877a..1edc3769e7 100644 --- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp +++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" +#include "clang/AST/DeclCXX.h" using namespace clang; using namespace ento; @@ -162,3 +163,21 @@ CallOrObjCMessage::getInstanceMessageReceiver(const LocationContext *LC) const { assert(isObjCMessage()); return Msg.getInstanceReceiverSVal(State, LC); } + +const Decl *CallOrObjCMessage::getDecl() const { + if (isCXXCall()) { + const CXXMemberCallExpr *CE = + cast<CXXMemberCallExpr>(CallE.dyn_cast<const CallExpr *>()); + assert(CE); + return CE->getMethodDecl(); + } else if (isObjCMessage()) { + return Msg.getMethodDecl(); + } else if (isFunctionCall()) { + // In case of a C style call, use the path sensitive information to find + // the function declaration. + SVal CalleeVal = getFunctionCallee(); + return CalleeVal.getAsFunctionDecl(); + } + return 0; +} + |