[clang] [analyzer] Fix crash on dereference invalid return value of getAdjustedParameterIndex() (PR #83585)

via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 6 00:36:49 PST 2024


tomasz-kaminski-sonarsource wrote:

Looking at the examples for the static operator at ([live example](https://godbolt.org/z/GhhT5ohh7)):
```c++
struct S {
  int pad;  
  static void operator()(int x, int y) {
    // clang_analyzer_dump(x);
    // clang_analyzer_dump(y); 
  }
};

void calls() {
    S s{10};
    void (*fptr)(int, int) = &S::operator();

    s(1, 2);  // A
    S::operator()(1, 2);  // B
    fptr(1, 2); // C
}
```
You can experiment with the results of the dumps to check current behavior - you need to add `debug.ExprInspection` matcher to see the output.

The calls `B` and `C` are represented as the `CallExpr` with 2 arguments, and in static analysis, they are mapped to `SimpleFunctionCall` event. This is no different from handling of any other static member function, that we have currently. 

However, in the case of `A` the AST is different, as we have `CXXOperatorCallExpr` with 3 arguments being included (the first node is called function). The additional argument is the object argument, which is not later passed to function because it is  `static`.
````
CXXOperatorCallExpr <line:13:5, col:11> 'void' '()'
|-ImplicitCastExpr <col:6, col:11> 'void (*)(int, int)' <FunctionToPointerDecay>
| `-DeclRefExpr <col:6, col:11> 'void (int, int)' lvalue CXXMethod 0xc7ecd78 'operator()' 'void (int, int)'
|-DeclRefExpr <col:5> 'S' lvalue Var 0xc7ed028 's' 'S'
|-IntegerLiteral <col:7> 'int' 1
`-IntegerLiteral <col:10> 'int' 2
````

So in this case we also need an adjustment when mapping from arguments to parameters. However, we cannot use `CXXMemberOperatorCall` as we are not calling an implicit object function, and we do not have `this` argument.
I think the best way to handle it would be to introduce a new kind of event `CXXStaticOperatorCall`.
This event should be based on `SimpleFunctionCall` (I would start it as a copy of it), with some modification derived from `CXXMemberOperatorCall`:
* constructor from `CXXOperatorCallExpr`
* `getOriginExpr` and `getOverloadedOperator` as we will always use it for `CXXOperatorCallExpr`
* `getNumArgs`, `getArgExpr`, `getAdjustedParameterIndex`, and `getASTArgumentIndex` to skip object parameters.

[ Note: We do not copy any function related to `this` object, as there is not any. ]

Then we need to add a new `CE_CXXStaticOperator` kind, it should be after `CE_Function` and before `CE_CXXMember` as this is not an instance call.
```c++
enum CallEventKind {
  CE_Function,
  CE_CXXStaticOperator,
  CE_CXXMember,
  CE_CXXMemberOperator,
  CE_CXXDestructor,
  CE_BEG_CXX_INSTANCE_CALLS = CE_CXXMember,
  CE_END_CXX_INSTANCE_CALLS = CE_CXXDestructor,
  ....
};
```

Finally, we can change `getSimpleCall` to check for static operators:
```
 if (const auto *OpCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
    const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
    if (const auto *MD = dyn_cast<CXXMethodDecl>(DirectCallee)) {
      if (MD->isInstance()
        return create<CXXMemberOperatorCall>(OpCE, State, LCtx, ElemRef);
      if (MD->isStatic())
         return create<CXXStaticOperatorCall>(OpCE, State, LCtx, ElemRef);
     }    
  }
```

Hope this helps. However, please open such changes in a separate PR.

https://github.com/llvm/llvm-project/pull/83585


More information about the cfe-commits mailing list