[clang] [WIP][clang]: Implement a conditional lifetimebound_if builtin. (PR #125520)
Haojian Wu via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 21 07:28:02 PST 2025
hokein wrote:
Another thought for supporting the `emplace_back(Args...)` case (for STL only).
The underlying implementation of the `emplace_back` relies on `std::allocator_traits::construct(Alloc& a, T* p, Args&&... args)`, so we could use the `lifetime_capture_by` annotation in the instantiated function (this annotation can be relatively easy to infer in clang).
For example, consider an instantiated template (note that the function parameter should be an non-const rvalue reference):
```cpp
construct(std::string_view* p, std::string&& arg [[clang::lifetime_capture_by(p)]]);
```
Here, we annotate `arg` with `lifetime_capture_by(p)`, which should allow us to detect cases like:
```cpp
construct(&view, std::string()); // Detects dangling pointer
```
However, this approach doesn’t work for `emplace_back`, because in that case, we only see perfect forwarding in the function arguments (`construct(std::__to_address(__tx.__pos_), std::forward<_Args>(__args)...);`)
### Potential Extension:
We could consider extending the analysis scope for non-const rvalue references. Specifically if a non-const rvalue reference parameter is annotated, we could always emit a warning when this function is being called.
Example:
```cpp
void add(std::vector<std::string_view>& container, std::string&& s [[clang::lifetime_capture_by]]);
void test() {
std::vector<std::string_view> abc;
add(abc, std::string()); // Case 1: Warning, point to a dead object
std::string b;
add(abc, std::move(b)); // Case 2: point to a moved-from object
add(abc, b); // invalid c++ code, cannot bind a lvalue to rvalue reference
}
```
For non-const rvalue reference function parameters, there are only two legal options to pass the argument:
1. A temporary object.
2. A non-const object explicitly marked with `std::move()`.
- **Case 1)** is a clear use-after-free issue, which is already detected by the current implementation.
- **Case 2)** is a bit subtle. The moved-from object is still alive but in a valid-but-unspecified state. While it’s technically possible to use the object after a `std::move()`, the general programming guideline is to avoid doing so, as it could lead to potential use-after-move issues (we have a use-after-move clang-tidy check).
If we extend the analysis to warn on Case (2), we should be able to detect the `emplace_back` case. However, I’m not sure whether making the compiler stricter on this is a feasible idea.
https://github.com/llvm/llvm-project/pull/125520
More information about the cfe-commits
mailing list