[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