<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/132739>132739</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[CaptureTracking] False Negatives in `PointerMayBeCaptured` Due to Missing Underlying Object Backtracking
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
Camsyn
</td>
</tr>
</table>
<pre>
## Description
`PointerMaybeCaptured`, as its name suggests, is supposed to take an arbitrary pointer and analyze whether it might be captured.
However, the current capture checking in `PointerMayBeCaptured` may produce false negatives by directly tracking the def-use chain of the given pointer without first backtracking to its underlying object. This leads to missed captures when analyzing derived pointers (e.g., GEP results) with their base objects captured.
## Reproducer
Analyze whether `&arr[1]` is captured or not.
```cpp
void foo(char *);
int main() {
int arr[2] = {0, 0};
pthread_t t;
// `arr` is captured through the pointer argument
foo(arr);
// Current implementation considers `arr + 1` as non-captured
arr[1] = 2;
...
}
```
## Analysis of Current Usage
Currently, there are TWO different patterns of the pointer argument passed to `PointerMayBeCaptured`.
### Safe Patterns (Majority of Existing Uses)
- **Direct patterns with guaranteed base objects**:
- `Alloca` instructions
- Function arguments
- Return values with `noalias` attributes
- Pointers processed through `getUnderlyingObject()`
- **These account for uses in**:
- `InstructionSimplify.cpp`
- `InstCombineCompares.cpp`
- `FunctionAttrs.cpp` (with manual object backtracking)
- `DeadStoreElimination.cpp`
- `SimplifyCFG.cpp`
### Potentially Problematic Cases
- `ThreadSanitizer.cpp`: Uses pointer operand of Store/Load directly
- `SanitizerBinaryMetadata.cpp`: Processes pointer operand of Store/Load for GWP-San metadata
The FNs of capture relation of load/store addresses might lead to FN in TSan's race detection, observed in this [Godbolt example](https://godbolt.org/z/n67GrxdcE):
## TWO Potential Fixes
1. **Fix of Restriction**: Explicitly or implicitly restrict the pattern of pointer argument of `PointerMayBeCaptured`
- Explicitly state in API comments that a pointer not from a base object might be mis-analyzed as non-captured.
- Or add an inner assertion to limit the passed pointer must be a base object.
> If so, the use cases in `ThreadSanitizer.cpp` and `SanitizerBinaryMetadata.cpp` need to be fixed
2. **Fix of Implementation** (Recommended):
- Add extra underlying object resolution in the beginning of `PointerMayBeCaptured`:
```cpp
const Value *Obj = getUnderlyingObject(Ptr);
return analyzeCaptures(Obj);
```
- As most of the usages of `PointerMayBeCaptured` just pass the underlying object pointer to it, this fix would not introduce obvious overhead, but eliminate the FN when the argument pointer is not of underlying object.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJyEV01v4soS_TXNphRkGgjJgoUTQt5IbyZoknl3-VS2y7gzdrfVXSZhfv1VtW3Ix70zElKC3V1f59SpAkMwe0u0VssbtdxMsOPK-fUtNuFoJ5krjmul50rPYUMh96Zl46xKUnWZ7JyxTP4rHjO6xZY7T4W6TJS-BQxgOIDFhiB0-z0FDvLcBAhd27pABbADxp8EaAF9ZtijP0Lb2wS0BaDF-viL4KUirsiDYWjMvmLICPLB31Ql6X_cCx3Ii32uCPLOe7I8HoG8ovynsXswFt5FffM2amjwCK13RZcTlFgHAkt7ZHOgANkRCuMp5_oI7LE3J74KKi-6ID7QWHBlfLg3B7KnTF4MV65jKI0PDBnmP88WXKxSZwvy9VGeuOyZcp7CU2UC1IRFkEONCVKwIaEgBbFDdeRSQd4cqBg9BlD6iqb7qRTk_m4HnkJXS_2vYzASo_GQYaDBX3hXTvn0iH-noSBeJWn6AY2I9CV6r5Y3M7XcSA3N2RI4D9bxtKdK_8nbViXpwZkCSueUvsor9KB0qvS1mt-oJDWWoUFjlb6ScNVKHgLI496TVssNqPlGXkWmJWq16e8CtFx5wuL_DDw-Unqr9FaClfsfQuTKu24fC3Imnt93DVmOt_so5eYY4Mni7cAy07Q1yQWUxoDc2WCKCEJ0CUrfwEwcYwDr7MXoPNo6Vy_mpAcf02ks22rztnjvkIlgBBOEcmMkPwLuSSXp8L0-Dg3hCdATPP31AIUpS4qHW2Qmb8PI2Y_pQ4thaNJ_75npKSCJ6RFLgt1oV-mrr_jsvOGj-Lh7NYGFrD8CCRNVkl70yKeb2FnniCJH9x16tExUvCNqf0PN01i-C4ktrWuXY4TWBvZdLjiE4f22s_H7Ka_xxXfizls4YN3R4FJdJtZhbTBEuJi9yTqm8cZu7K7Wu5z64gz8UZfJnvjHqY0fYrA9h0_Ijek-VRQIMM9dZxlK56ELFEA4_ym3L-eMHoVopjxOpYmizTdnbl2TGUu3rmnRU_h0ZixDyuzHt4JQzLtB22E9VPidQPU4DTY2hMUjO093tWmMjXT_5GiM8nZ7f373jiU7x2TZYF0fYeddVlODbHK4xRBLHc08xT5-RGvY_CI_mpqnkT4nsrqWvAwKV0KMTOntfx0WJ60ezZ0M3RiL_viVGAtkfGN2N2D6Z9sC2P1fu4tHtNAMhvocnyqC7bfYUePo8VT3suBKqB0WSm-DGAMsCt_76yeaSL302vabTKmnR7RKrwJ4zGXGMEX0pJ9dFsiL2BsLLENCLW_uXZG5moFeUcRItFhfVcxtEDJFudr3R6bO75Xe_lJ6ay9X9_61yO-itKXv1EWk4oQTbM1rREYl6Ww6kHhrXiWn7xTYmyG4gb1w99rWJjcyK52P-jh888PpXnD6dhcrn7THlb8RnUg2uHjrJjAySUXS3RfIXRMbHbhCBjxZt46h9K4BfKso542iMeFi2DiKj2I9HZ0-eIFOVhZjrYQcAvmIMDuQvhiTi_owum66EF288zzYVPM7-FJCcOP6EtcJ7CXh33shLkh_pDZY6jU8IyjNa5w6Kkn1Bxi_vJth_SuRh-_UF7Og4sSSWIa0KIBe2ePn3UVQdnUXaxI5SpDR3lgbj_wW2NE-wIeNIT6TycrwPxFsif4he44z85-Fd8dvRzYA-F7vB4AHr0Hpq4fs-Xzy7bDtEw3QuMDjlOxkxIbfpwHPgrYwoL_yqUAjK-L216NugsADL66ri0hUY3lYRV12MK4L4A7kKxIJuYWsY6BBhSl62X7rl0L5_zzCB0cmRJuu_IdNc-j7-JkU63lxPb_GCa1nq4W-0svr1XJSrRe6XK5Wi2yVZbPF9eVitdC0uEp0UlxeUpbNJmatE71M5noxW8yu9XxazK-yEq9nOsMyowzVIqEGTT2t60MjKjQxIXS0ns31an49qTGjOsSfIFpbeoH4VmnZ9iZ-LZcusm4f1CKpTeBwNsOG6_jbZUDgaRxdyw1s4xb_7bTF_37_33QkkHw1IcQ95VyqnlVw82YyTjpfrz9IrOGqy6a5a5TeSnzDn4vWu56V25hVUHo7pH1Y678DAAD__0SOdBQ">