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
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits