A helper takes a std::string by value and returns a std::string_view into it. Callers store the returned view. Unit tests pass and production prints garbage symbols under load. Explain the lifetime violation, why the tests passed anyway, and give two signatures that make the bug impossible.
A helper takes a std::string by value and returns a std::string_view into it. Callers store the returned view. Unit tests pass and production prints garbage symbols under load. Explain the lifetime violation, why the tests passed anyway, and give two signatures that make the bug impossible.
Approach: Track the lifetime of the parameter object against the lifetime of the view, then ask what an allocator does with a freed block in a quiet process compared with a busy one.
The by value parameter is destroyed when the helper returns, so the returned string_view points at freed storage and every later read is undefined behaviour, and the two fixes are to return a std::string by value or to take the input as a string_view whose owner outlives the call. A view is a pointer and a length with no ownership, so nothing about it extends the object lifetime of the buffer it names. The tests passed because a freed small block is usually still intact, and a short string may live in the small buffer inside the parameter object on the stack, so the bytes survive until something overwrites them; under load the allocator hands that block to another thread and the contents change within microseconds. Building the tests with the address sanitiser reports the use after free on the first call, which is how this class of bug is caught rather than reasoned about.
Follow-up: What changes in the analysis if the view points into a member buffer of an object the caller owns for the whole session?
Key concepts: string_view, object lifetime, use after free, address sanitiser.