Lifetime profile v1.0 posted

I love C++. I also love safe code and not having to worry about dangling pointers and iterators and views. So I’ve been doing some work to make my life less conflicted: As long promised, the Lifetime profile 1.0 paper is now posted in the C++ Core Guidelines repo. It aims to detect common local cases of dangling pointers/iterators/string_views/spans/etc. in C++ code, at compile time, efficiently enough to run during normal compilation and in IDE tooltips. And, best of all (IMO), leveraging the rich information that’s already in typical modern C++ code, especially code that uses RAII and STL, with little or no annotation (e.g., see section 2.6).

For a quick summary, section 1.1 is a readable 3-page overview. Or, if you prefer watching a talk video, you can also see my CppCon 2015 talk starting at 29:06, where I first talked about this work; the approach is still the same. I’ll also be giving an update on this work next week at CppCon as one of the three major sections of my talk this year.

Many thanks to all of the people who contributed and gave feedback to help me flesh out this design over the past three years. I would like to especially thank Neil MacIntosh and Kyle Reed who did the bulk of the MSVC static analysis extension implementation work, and Matthias Gehre and Gábor Horváth who did the Clang-based implementation. Thank you! Those of you who’ll be at CppCon will see some of these folks on-stage showing their work in my talk, and be able to ask them questions at the conference.

… Did I say Clang? Yes, there’s now also a Clang-based implementation in addition to MSVC. Although I stress this work is still somewhat experimental and that both are partial implementations, both of them do already compile most of the examples in the paper and both already run efficiently enough to run during normal compilation (Clang) and in the IDE for live-squiggle diagnostics (MSVC) even though they have not been optimized yet. And, as you’d expect in 2018, the Clang-based implementation is available on Godbolt — in the paper, just search for “godbolt” to find over 30 links to live examples. Here are a few you might find interesting:

  • A simple starter dangling raw pointer example.
  • This one’s simple but fun… quick, how is the pointer use on line 11 invalidated by the following line, line 12?
  • From C++17: A dangling string_view, which is important because it turns out to be easy to convert a std::string to a string_view, so that dangling is almost the default behavior.
  • From the very latest bleeding edge: A dangling filter_view from the Ranges TS that we’re about to see if we can merge into the standard in time for C++20. Those are non-owning indirections, so they can dangle too.
  • From C++98 with a dash of C++11: You know how using auto to deduce a vector<bool> subscript [] operator actually captures a vector<bool>::reference proxy, which can dangle after a push_back or reserve? If you didn’t: Sorry to be the bearer of sad tidings, but here’s some good news about that example.
  • This short example can take a few minutes to grok… take a cup of coffee to understand who owns what and points where, and why the pointers are dangling (or not), and what the compiler is understanding about our code in order to be able to tell us about the problems accurately.

If you’re interested in preventing common cases of dangling pointers, iterators, string_views, spans, and more, efficiently at compile time with high quality diagnostics, check out the examples in the paper and play around with them on Godbolt.

If you find new examples that are correctly diagnosed that you think are particularly cool, feel free to distill them down to their essence (and sanitize them if they came from real code) and post them as new Godbolt links in the comments below — bonus points if you also briefly summarize what the problem is, and extra bonus points if they did come from real world code. I may add some of them to the paper, with attribution, and maybe even use one in next week’s talk.

10 thoughts on “Lifetime profile v1.0 posted

  1. > Is the rule for propagating function parameter lifetimes to function results not implemented in clang yet?

    The equivalent code using pointers *does* warn so I think this is a bug in the handling of references.

  2. It’s a little bit unclear that the definition of “POin” is actually defining two different sets “Pin” and “Oin” (and likewise for “OIn_weak”).

  3. It might be good to some examples showing the treatment of Values. For example consider

    class X {
        X() : a(new int(0)), b(new char(0)) {}
        int& get_a() { return *a; }
        char& get_b() { return *b; }
        unique_ptr<int> a;
        unique_ptr<char> b;

    X can’t be an Owner or Pointer and it isn’t an Aggregate. It appears to me there is no possible valid lifetime annotation for the return values of get_a and get_b. It also appears that the inferred return psets will be {static}. Is that correct?

  4. One thing that would be good to clarify in the interest of rigor is what “o” can be in a pset. It looks like “o” must be a local variable (including exploded aggregate members and parameters), but (unlike the “var” case) nothing seems to explicitly say that.


    int& f(int& a) {
        return a;
    int& hello() {
        int x = 0;
        return f(x);

    This produces no warnings. Is the rule for propagating function parameter lifetimes to function results not implemented in clang yet? If not, it might be worth pointing that out so people don’t get the impression the results are more meaningful than they actually are.

  6. Why does “assert(p)” remove null from pset(p)? “assert” typically compiles to nothing in non-debug builds, so this could hide null-dereference bugs in release builds.

  7. Unfortunately, exceptions are not properly supported in either of the implementations yet.

  8. We have been using a slightly longer version of the following in interviews for several years now:

    Looks a bit absurd, but it is actually the distilled version of what we saw in a real-life code review once.

    The current analysis yields a false positive (uninitialized reference e), but does not find the actual issue (dangling reference msg).

Comments are closed.