26 July 2024 · 3 min
For better performance in software, we avoid unnecessary copies. To do so, we introduce references (or pointers). An example of this ideas in C++ is the std::string_view class. As the name suggests, a std::string_view instance is merely a ‘view’: it points at some string, but it does not own or otherwise manage the underlying memory.
The downside is that we must track ownership: when the owner of the memory is gone, we should not be left holding the std::string_view instance. With modern tools, it is trivial to detect such bugs (e.g., using a sanitizer). However, it would be nicer if the compiler could tell us right away.
A few C++ compilers (Visual Studio and LLVM) support lifetime-bound annotation to help us. Let us consider an example. Suppose you would like to parse a URL (e.g., ‘https://www.google.com/path’), but you are only interested in the host (e.g. ‘www.google.com’). You might write code like so using the ada-url/ada parsing library:
std::string_view my_get_host(std::string_view url_string) { auto url = ada::parse(url_string).value(); return url.get_host(); }
This code is not generally safe. The parser will store the result of the parse inside a temporary object but you are returning an std::string_view which points at it. You have a dangling reference.
To get a recent version of LLVM/clang (18+) to warn us, we just need to annotate the function get_host like so:
#ifndef __has_cpp_attribute #define ada_lifetime_bound #elif __has_cpp_attribute(msvc::lifetimebound) #define ada_lifetime_bound [[msvc::lifetimebound]] #elif __has_cpp_attribute(clang::lifetimebound) #define ada_lifetime_bound [[clang::lifetimebound]] #elif __has_cpp_attribute(lifetimebound) #define ada_lifetime_bound [[lifetimebound]] #else #define ada_lifetime_bound #endif ... std::string_view get_host() const noexcept ada_lifetime_bound;
You can review the complete code update on GitHub.
And then we get a warning at compile time:
fun.cpp:8:10: warning: address of stack memory associated with local variable 'url' returned [-Wreturn-stack-address]
8 | return url.get_host();
It is hardly perfect at this point in time. It does not always warn you, but progress is being made. This feature and others will help us catch errors sooner.
Credit: Thanks to Denis Yaroshevskiy for making me aware of this new compiler feature.
Further reading: LLVM documentation.
Daniel Lemire, "Safer code in C++ with lifetime bounds," in Daniel Lemire's blog, July 26, 2024, https://lemire.me/blog/2024/07/26/safer-code-in-c-with-lifetime-bounds/.
[BibTeX]
You’ve changed the example function from one code snippet to the next, which confuses your point.
– In the first example, it’s a standalone function taking a string_view parameter.
– When you add the attribute to the declaration, it’s now declared as a method (of some unknown class), with no parameters, and const and noexcept attributes. We never get to see the implementation of this method.
Moreover, in the first example it’s the _implementation_ of the function that in error due to UB, but later on the compiler warning you show is at a _call site_.
I’ve read the docs of the lifetimebound attribute in the Clang documentation, and it’s more complex than your example implies; using it correctly involves reasoning about the lifetime of the result in relation to function arguments including the implicit “this”. IMHO a fuller explanation is needed in this post.
You are correct although part of the confusion comes from initial typographical errors that I have since corrected. I appreciate your critical feedback.
I think the example is not very suitable. Any good implementation shall return a sub-string_view of the parameter to my_get_host(), so the lifetime will be independent of the implementation.
I think, this would be something, that can’t be expressed in the moment, but could become useful? At least a lifetime checker would indirectly detect implementations not returning a sub-string_view
A URL parser produce a parsed string which differs, in general, from the string you provided.
E.g., given https://www.7‑Eleven.com/Home/Privacy/Montréal, the host would be http://www.xn--7eleven-506c.com as per the WHATWG URL standard.