llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Benedek Kaibas (benedekaibas)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/221252.diff


4 Files Affected:

- (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h 
(+27-2) 
- (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h 
(+6-1) 
- (modified) clang/lib/StaticAnalyzer/Core/CallEvent.cpp (+64-34) 
- (modified) clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (+7-2) 


``````````diff
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 2010e4b0da84b..5e70928b582e3 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -420,6 +420,9 @@ class CallEvent {
   /// Returns memory location for a parameter variable within the callee stack
   /// frame. The behavior is undefined if the block count is different from the
   /// one that is there when call happens. May fail; returns null on failure.
+  ///
+  /// \param Index refers to the index of the declared parameter of the callee.
+  /// See getDeclaredParameterIndex().
   const ParamVarRegion *getParameterLocation(unsigned Index,
                                              unsigned BlockCount) const;
 
@@ -429,6 +432,9 @@ class CallEvent {
   /// if we are supposed to construct an argument directly, we may still
   /// not do that because we don't know how (i.e., construction context is
   /// unavailable in the CFG or not supported by the analyzer).
+  ///
+  /// \param Index index of the argument as understood by the AST.
+  /// See getASTArgumentIndex().
   bool isArgumentConstructedDirectly(unsigned Index) const {
     // This assumes that the object was not yet removed from the state.
     return ExprEngine::getObjectUnderConstruction(
@@ -437,9 +443,13 @@ class CallEvent {
   }
 
   /// Some calls have parameter numbering mismatched from argument numbering.
-  /// This function converts an argument index to the corresponding
-  /// parameter index. Returns std::nullopt is the argument doesn't correspond
+  /// This function converts an argument index as understood by the AST to the
+  /// index of the *declared* parameter of the callee that this argument
+  /// initializes. Returns std::nullopt if the argument doesn't correspond
   /// to any parameter variable.
+  ///
+  /// Note that \c clang::AnyCall::arguments() uses the opposite convention:
+  /// there the object argument is part of the argument list.
   virtual std::optional<unsigned>
   getAdjustedParameterIndex(unsigned ASTArgumentIndex) const {
     return ASTArgumentIndex;
@@ -452,6 +462,21 @@ class CallEvent {
     return CallArgumentIndex;
   }
 
+  /// Returns the declared parameter index that CallEvent argument
+  /// \p CallArgumentIndex (as understood by CallEvent) initializes or
+  /// std::nullopt if that argument does not initialize any declared parameter.
+  ///
+  /// This is the index to use with parameters() and getParameterLocation().
+  /// Note that this is not necessarily equal to \p CallArgumentIndex. For an
+  /// overloaded operator call, the object is passed as argument 0, but it is
+  /// not a declared parameter of an implicit ombject member function. For an
+  /// explicit object member function, the object is likewise passed as
+  /// argument 0, but there it is a declared parameter #0.
+  std::optional<unsigned>
+  getDeclaredParameterIndex(unsigned CallArgumentIndex) const {
+    return getAdjustedParameterIndex(getASTArgumentIndex(CallArgumentIndex));
+  }
+
   /// Returns the construction context of the call, if it is a C++ constructor
   /// call or a call of a function returning a C++ class instance. Otherwise
   /// return nullptr.
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index c3d6d552d5e56..e5f8457555ec6 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -1073,6 +1073,10 @@ class ParamVarRegion : public VarRegion {
   friend class MemRegionManager;
 
   const Expr *OriginExpr;
+
+  /// Index of teh declared parameter of the callee that this region stands
+  /// for. This is not necessarily the index of the corresponding argument
+  /// in `OriginExpr`. See `CallEvent::getDeclaredParameterIndex()`.
   unsigned Index;
 
   ParamVarRegion(const Expr *OE, unsigned Idx, const MemRegion *SReg)
@@ -1095,7 +1099,8 @@ class ParamVarRegion : public VarRegion {
 
   QualType getValueType() const override;
 
-  /// TODO: What does this return?
+  /// \returns the declared parameter of the callee that this region
+  /// stands for (`getStackFrame()->getDecl()->parameters()[getIndex()]`).
   const ParmVarDecl *getDecl() const override;
 
   bool canPrintPrettyAsExpr() const override;
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp 
b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 2338c06d5f992..8eab3f19dc0a8 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -449,8 +449,13 @@ static SVal processArgument(SVal Value, const Expr 
*ArgumentExpr,
 /// 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) {
+///
+/// \param DeclParamIdx index of the declared parameter that \p ArgExpr
+/// initializes. See CallEvent::getDeclaredParameterIndex().
+static SVal castArgToParamTypeIfNeeded(const CallEvent &Call,
+                                       unsigned DeclParamIdx,
+                                       const Expr *ArgExpr, SVal ArgVal,
+                                       SValBuilder &SVB) {
   const auto *CallExprDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
   if (!CallExprDecl)
     return ArgVal;
@@ -466,52 +471,77 @@ static SVal castArgToParamTypeIfNeeded(const CallEvent 
&Call, unsigned ArgIdx,
     return ArgVal;
 
   // Only do this cast if the number arguments at the callsite matches with
-  // the parameters at the runtime definition.
+  // the parameters at the runtime definition. Note that this point is only
+  // reached for C functions without a prototype, so the argument indices
+  // and the declared parameter indices coincide.
   if (Call.getNumArgs() != Definition->getNumParams())
     return UnknownVal();
 
-  const Expr *ArgExpr = Call.getArgExpr(ArgIdx);
-  const ParmVarDecl *Param = Definition->getParamDecl(ArgIdx);
+  const ParmVarDecl *Param = Definition->getParamDecl(DeclParamIdx);
   return SVB.evalCast(ArgVal, Param->getType(), ArgExpr->getType());
 }
 
+/// Binds the value of a single argument to the region of the parameter it
+/// initializes in the callee's stack frame.
+///
+/// \param ParamDecl the declared parameter initialized by this argument.
+/// \param DeclParamIdx index of \p ParamDecl among the callee's declared
+/// parameters. See CallEvent::getDeclaredParameterIndex().
+/// \param ASTArgIdx index of \p ArgExpr in the origin expression's argument
+/// list. See CallEvent::getASTArgumentIndex(). Note that this is not
+/// necessarily equal to \p DeclParamIdx.
+static void addParameterValueToBindings(const StackFrame *CalleeSF,
+                                        CallEvent::BindingsTy &Bindings,
+                                        SValBuilder &SVB, const CallEvent 
&Call,
+                                        const ParmVarDecl *ParamDecl,
+                                        unsigned DeclParamIdx,
+                                        unsigned ASTArgIdx, const Expr 
*ArgExpr,
+                                        SVal ArgVal) {
+  assert(ParamDecl && "Formal parameter has no decl?");
+
+  // TODO: Support allocator calls.
+  if (Call.getKind() != CE_CXXAllocator)
+    if (Call.isArgumentConstructedDirectly(ASTArgIdx))
+      return;
+
+  // TODO: Allocators should receive the correct size and possibly alignment,
+  // determined in compile-time but not represented as arg-expressions,
+  // which makes getArgSVal() fail and return UnknownVal.
+  if (ArgVal.isUnknown())
+    return;
+
+  // Cast the argument value to match the type of the parameter in some
+  // edge-cases.
+  ArgVal = castArgToParamTypeIfNeeded(Call, DeclParamIdx, ArgExpr, ArgVal, 
SVB);
+
+  Loc ParamLoc = SVB.makeLoc(SVB.getRegionManager().getParamVarRegion(
+      Call.getOriginExpr(), DeclParamIdx, CalleeSF));
+  Bindings.emplace_back(ParamLoc,
+                        processArgument(ArgVal, ArgExpr, ParamDecl, SVB));
+}
+
 static void addParameterValuesToBindings(const StackFrame *CalleeSF,
                                          CallEvent::BindingsTy &Bindings,
                                          SValBuilder &SVB,
                                          const CallEvent &Call,
                                          ArrayRef<ParmVarDecl *> parameters) {
-  MemRegionManager &MRMgr = SVB.getRegionManager();
-
-  // If the function has fewer parameters than the call has arguments, we 
simply
-  // do not bind any values to them.
-  unsigned NumArgs = Call.getNumArgs();
-  unsigned Idx = 0;
-  ArrayRef<ParmVarDecl*>::iterator I = parameters.begin(), E = 
parameters.end();
-  for (; I != E && Idx < NumArgs; ++I, ++Idx) {
-    assert(*I && "Formal parameter has no decl?");
-
-    // TODO: Support allocator calls.
-    if (Call.getKind() != CE_CXXAllocator)
-      if (Call.isArgumentConstructedDirectly(Call.getASTArgumentIndex(Idx)))
-        continue;
-
-    // TODO: Allocators should receive the correct size and possibly alignment,
-    // determined in compile-time but not represented as arg-expressions,
-    // which makes getArgSVal() fail and return UnknownVal.
-    SVal ArgVal = Call.getArgSVal(Idx);
-    const Expr *ArgExpr = Call.getArgExpr(Idx);
-
-    if (ArgVal.isUnknown())
+  for (unsigned Idx = 0, NumArgs = Call.getNumArgs(); Idx != NumArgs; ++Idx) {
+    // An argument that doesn't initialize a declared parameter, such as the
+    // object argument of an overloaded operator call.
+    std::optional<unsigned> DeclParamIdx = Call.getDeclaredParameterIndex(Idx);
+    if (!DeclParamIdx)
       continue;
 
-    // Cast the argument value to match the type of the parameter in some
-    // edge-cases.
-    ArgVal = castArgToParamTypeIfNeeded(Call, Idx, ArgVal, SVB);
+    // If the call has more arguments than the function has parameters, the
+    // extra ones are left unbound. Since the indices are monotonic, no later
+    // argument has a parameter either, so we can stop here.
+    if (*DeclParamIdx >= parameters.size())
+      break;
 
-    Loc ParamLoc = SVB.makeLoc(
-        MRMgr.getParamVarRegion(Call.getOriginExpr(), Idx, CalleeSF));
-    Bindings.push_back(
-        std::make_pair(ParamLoc, processArgument(ArgVal, ArgExpr, *I, SVB)));
+    addParameterValueToBindings(CalleeSF, Bindings, SVB, Call,
+                                parameters[*DeclParamIdx], *DeclParamIdx,
+                                Call.getASTArgumentIndex(Idx),
+                                Call.getArgExpr(Idx), Call.getArgSVal(Idx));
   }
 
   // FIXME: Variadic arguments are not handled at all right now.
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 9fb167ee2ea4a..52cb267304b67 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -350,8 +350,13 @@ SVal ExprEngine::computeObjectUnderConstruction(
         // Operator arguments do not correspond to operator parameters
         // because this-argument is implemented as a normal argument in
         // operator call expressions but not in operator declarations.
-        const TypedValueRegion *TVR = Caller->getParameterLocation(
-            *Caller->getAdjustedParameterIndex(Idx), NumVisitedCaller);
+        std::optional<unsigned> DeclParamIdx =
+            Caller->getAdjustedParameterIndex(Idx);
+        if (!DeclParamIdx)
+          return std::nullopt;
+
+        const TypedValueRegion *TVR =
+            Caller->getParameterLocation(*DeclParamIdx, NumVisitedCaller);
         if (!TVR)
           return std::nullopt;
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/221252
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to