diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:04 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:11 +0000 |
commit | e3b557809604d036af6e00c60f012c2025b59a5e (patch) | |
tree | 8a11ba2269a3b669601e2fd41145b174008f4da8 /clang/lib/StaticAnalyzer/Core/CallEvent.cpp | |
parent | 08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff) |
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/CallEvent.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 83 |
1 files changed, 60 insertions, 23 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 3a8d69df7a64..8516e3643425 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -49,8 +49,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/ImmutableList.h" -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" @@ -62,6 +60,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include <cassert> +#include <optional> #include <utility> #define DEBUG_TYPE "static-analyzer-call-event" @@ -424,6 +423,38 @@ static SVal processArgument(SVal Value, const Expr *ArgumentExpr, return Value; } +/// Cast the argument value to the type of the parameter at the function +/// declaration. +/// Returns the argument value if it didn't need a cast. +/// Or returns the cast argument if it needed a cast. +/// Or returns 'Unknown' if it would need a cast but the callsite and the +/// runtime definition don't match in terms of argument and parameter count. +static SVal castArgToParamTypeIfNeeded(const CallEvent &Call, unsigned ArgIdx, + SVal ArgVal, SValBuilder &SVB) { + const FunctionDecl *RTDecl = + Call.getRuntimeDefinition().getDecl()->getAsFunction(); + const auto *CallExprDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); + + if (!RTDecl || !CallExprDecl) + return ArgVal; + + // The function decl of the Call (in the AST) will not have any parameter + // declarations, if it was 'only' declared without a prototype. However, the + // engine will find the appropriate runtime definition - basically a + // redeclaration, which has a function body (and a function prototype). + if (CallExprDecl->hasPrototype() || !RTDecl->hasPrototype()) + return ArgVal; + + // Only do this cast if the number arguments at the callsite matches with + // the parameters at the runtime definition. + if (Call.getNumArgs() != RTDecl->getNumParams()) + return UnknownVal(); + + const Expr *ArgExpr = Call.getArgExpr(ArgIdx); + const ParmVarDecl *Param = RTDecl->getParamDecl(ArgIdx); + return SVB.evalCast(ArgVal, Param->getType(), ArgExpr->getType()); +} + static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx, CallEvent::BindingsTy &Bindings, SValBuilder &SVB, @@ -449,12 +480,18 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx, // which makes getArgSVal() fail and return UnknownVal. SVal ArgVal = Call.getArgSVal(Idx); const Expr *ArgExpr = Call.getArgExpr(Idx); - if (!ArgVal.isUnknown()) { - Loc ParamLoc = SVB.makeLoc( - MRMgr.getParamVarRegion(Call.getOriginExpr(), Idx, CalleeCtx)); - Bindings.push_back( - std::make_pair(ParamLoc, processArgument(ArgVal, ArgExpr, *I, SVB))); - } + + if (ArgVal.isUnknown()) + continue; + + // Cast the argument value to match the type of the parameter in some + // edge-cases. + ArgVal = castArgToParamTypeIfNeeded(Call, Idx, ArgVal, SVB); + + Loc ParamLoc = SVB.makeLoc( + MRMgr.getParamVarRegion(Call.getOriginExpr(), Idx, CalleeCtx)); + Bindings.push_back( + std::make_pair(ParamLoc, processArgument(ArgVal, ArgExpr, *I, SVB))); } // FIXME: Variadic arguments are not handled at all right now. @@ -477,24 +514,23 @@ const ConstructionContext *CallEvent::getConstructionContext() const { return nullptr; } -Optional<SVal> -CallEvent::getReturnValueUnderConstruction() const { +std::optional<SVal> CallEvent::getReturnValueUnderConstruction() const { const auto *CC = getConstructionContext(); if (!CC) - return None; + return std::nullopt; EvalCallOptions CallOpts; ExprEngine &Engine = getState()->getStateManager().getOwningEngine(); - SVal RetVal = - Engine.computeObjectUnderConstruction(getOriginExpr(), getState(), - getLocationContext(), CC, CallOpts); + SVal RetVal = Engine.computeObjectUnderConstruction( + getOriginExpr(), getState(), &Engine.getBuilderContext(), + getLocationContext(), CC, CallOpts); return RetVal; } ArrayRef<ParmVarDecl*> AnyFunctionCall::parameters() const { const FunctionDecl *D = getDecl(); if (!D) - return None; + return std::nullopt; return D->parameters(); } @@ -770,7 +806,7 @@ void CXXInstanceCall::getInitialStackFrameContents( QualType Ty = Ctx.getPointerType(Ctx.getRecordType(Class)); // FIXME: CallEvent maybe shouldn't be directly accessing StoreManager. - Optional<SVal> V = + std::optional<SVal> V = StateMgr.getStoreManager().evalBaseToDerived(ThisVal, Ty); if (!V) { // We might have suffered some sort of placement new earlier, so @@ -819,7 +855,7 @@ const BlockDataRegion *BlockCall::getBlockRegion() const { ArrayRef<ParmVarDecl*> BlockCall::parameters() const { const BlockDecl *D = getDecl(); if (!D) - return None; + return std::nullopt; return D->parameters(); } @@ -908,7 +944,7 @@ RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const { ArrayRef<ParmVarDecl*> ObjCMethodCall::parameters() const { const ObjCMethodDecl *D = getDecl(); if (!D) - return None; + return std::nullopt; return D->parameters(); } @@ -1124,7 +1160,7 @@ static const ObjCMethodDecl *findDefiningRedecl(const ObjCMethodDecl *MD) { // Find the redeclaration that defines the method. if (!MD->hasBody()) { - for (auto I : MD->redecls()) + for (auto *I : MD->redecls()) if (I->hasBody()) MD = cast<ObjCMethodDecl>(I); } @@ -1185,10 +1221,10 @@ lookupRuntimeDefinition(const ObjCInterfaceDecl *Interface, // stays around until clang quits, which also may be bad if we // need to release memory. using PrivateMethodCache = - llvm::DenseMap<PrivateMethodKey, Optional<const ObjCMethodDecl *>>; + llvm::DenseMap<PrivateMethodKey, std::optional<const ObjCMethodDecl *>>; static PrivateMethodCache PMC; - Optional<const ObjCMethodDecl *> &Val = + std::optional<const ObjCMethodDecl *> &Val = PMC[{Interface, LookupSelector, InstanceMethod}]; // Query lookupPrivateMethod() if the cache does not hit. @@ -1398,9 +1434,10 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx, SVal ThisVal = State->getSVal(ThisPtr); const Stmt *Trigger; - if (Optional<CFGAutomaticObjDtor> AutoDtor = E.getAs<CFGAutomaticObjDtor>()) + if (std::optional<CFGAutomaticObjDtor> AutoDtor = + E.getAs<CFGAutomaticObjDtor>()) Trigger = AutoDtor->getTriggerStmt(); - else if (Optional<CFGDeleteDtor> DeleteDtor = E.getAs<CFGDeleteDtor>()) + else if (std::optional<CFGDeleteDtor> DeleteDtor = E.getAs<CFGDeleteDtor>()) Trigger = DeleteDtor->getDeleteExpr(); else Trigger = Dtor->getBody(); |