
The C++ Lifetime Profile: How It Plans to Make C++ Code Safer - ingve
https://pspdfkit.com/blog/2020/the-cpp-lifetime-profile/
======
xiphias2
I would prefer if C++ would be extended with a function level borrow checker
with real safety guarantees that could optionally be turned on for functions.

In the first look Lifetime profile looks like it just tries to find the low
hanging fruit cases.

Can it be further extended to guarantee safety guarantees in the future, or
it's just a hack? I'm not sure about it.

~~~
ryanianian
RAII solves lots of lifetime problems, but it's surprisingly easy to have refs
outlive their targets (among other things). Static-analysis can spot a portion
of these, but in general the lifetime of input and output values of
functions/scopes needs to be explicitly stated by the user (part of the type)
and can thus be verified by the compiler.

I think Rust captures the core lifetime concepts pretty well, but the notation
can be cumbersome, and I think C++'s rich type-system could make for a less-
tedious solution. TFA mentions doing some implicit lifetime-analysis based on
signatures (e.g. inferring ownership based on type-traits), but ultimately it
is 'just' low-hanging fruit. It would be nice to capture in signatures/types
that "the input must outlive the output" and have more meaningful error
diagnostics and less implicit magic ("did I follow the iterator traits
correctly?").

~~~
xiphias2
I think the main problem for C++ programmers is not the notation of Rust, as
Rust is a simpler language than C++.

It's backwards compatibility: there are hundreds of millions, or probably
billions of lines of C++ code out there. I found working with big code bases
really hard, because the memory ownership situation is crazy, in fact
impossible to keep track of.

That's why my question was whether there's a future path for C++ Lifetime
Profile to get programs to Rust like memory safety in the future, but I still
don't know the answer.

~~~
safercplusplus
I think the answer is yes. There's a complementary project [1] that aims to
enforce a slightly more restricted memory safe subset of C++ than the lifetime
profile checker does (or eventually will). The restrictions do not manifest as
limitations on the code, but rather as extra run-time checks in some
scenarios.

The C++ language maps one-to-one to the safe subset, so auto-conversion of
(reasonable) existing C++ code to the safe subset should be a straightforward
(if tedious) undertaking. The issue will be the performance of the converted
code, which will depend on how pointers/references are used in the original
code.

Pointers that are expected to never point to (in addition to never dereference
to) a destroyed object can be converted to "safe" pointers with little run-
time overhead [2]. Otherwise the pointer would need to converted to one with
more overhead [3]. Pointers that can be verified (by the static analyzer) to
conform to "scope lifetime" rules (akin to Rust) can remain zero-overhead
pointers.

New code written in the safe subset would generally have performance in the
ballpark of traditional C++ [4].

[1]
[https://github.com/duneroadrunner/scpptool](https://github.com/duneroadrunner/scpptool)

[2] [https://github.com/duneroadrunner/SaferCPlusPlus#norad-
point...](https://github.com/duneroadrunner/SaferCPlusPlus#norad-pointers)

[3]
[https://github.com/duneroadrunner/SaferCPlusPlus#registered-...](https://github.com/duneroadrunner/SaferCPlusPlus#registered-
pointers)

[4] [https://github.com/duneroadrunner/SaferCPlusPlus-
BenchmarksG...](https://github.com/duneroadrunner/SaferCPlusPlus-
BenchmarksGame) (note that the benchmark code is quite old and will be updated
soon)

~~~
muizelaar
Is there a document that describes roughly how to do the conversion? How are
things like pointer arithmetic handled?

~~~
safercplusplus
Unfortunately, documentation [1] is still kind of lacking. Like Rust (and
arguably modern C++ conventions?), the safe subset doesn't support pointer
arithmetic directly. You would have to convert the pointer to an iterator (and
its target to an appropriate container).

Auto-conversion of code that uses pointer arithmetic is challenging, but has
been demonstrated to be solvable in the general case [2].

[1] [https://github.com/duneroadrunner/SaferCPlusPlus#getting-
sta...](https://github.com/duneroadrunner/SaferCPlusPlus#getting-started-on-
safening-existing-code)

[2] [https://github.com/duneroadrunner/SaferCPlusPlus-
AutoTransla...](https://github.com/duneroadrunner/SaferCPlusPlus-
AutoTranslation)

------
youdontknowtho
I'm really interested in the Core guidelines. They are only a few years old,
however. It will be super interesting to see some case studies of large
codebase adoption in the next few years. The lifetime profile is the one that
I 'm most interested in seeing some real studies on. Some of the changes seem
pretty simple (of course, I don't have to make them in any codebases) so it
makes me wonder if they are expressive enough to solve a large chunk of the
use after free problems.

------
axilmar
Not a long term approach, in my humble opinion (as a C++ veteran that has
worked with it for 20 years).

What the language needs is a new set of types that will ensure memory safety.
Using the old types with the new ones should not allow the code to be
compiled, thus ensuring memory safety.

It would be nice to have such a tool in short-term, though. At least some old
bugs could possibly be more easily revealed.

------
jupp0r
Here’s my problem with the approach: it’s a compiler warning. Nobody looks at
those so it’s configured to be treated as an error. Now you have to deal with
false positives and differences between implementations across compilers. I’d
rather have this be part of the language with string guarantees and an
obligation for compilers to adhere to the spec. Of course that isn’t possible
in C++ without breaking existing code, which is why this ended up where it is.

------
vkaku
TL;DR - Ownership to C++

------
thrower123
At this point, why not write Rust instead?

I know, C++ is a dirty snowball rolling downhill, gobbling up every feature it
can put its tendrils on, and always has been, but it is getting silly.

~~~
dgellow
Even if you don't care about the language itself, there is a giant amount of
C++ in the wild that won't be reimplemented. Anything that can make that code
safer is a huge win.

~~~
thrower123
How much of that existing code, really, is ever going to be updated to the
standard of even C++11?

~~~
seren
I am working on a device, where the initial code was written in 1995-1997 on a
pre cpp98 compiler, the code has recently been updated to cpp11, I am sure we
will move to cpp14/17 soon. So this is slowly but steadily moving, even if
very conservatively.

On the other hand, Hell would freeze over before you could convince the
business to throw the cpp codebase and replace it by anything else, without
necessarily a lot of things to show to the customer. And as much as we like to
criticize business decisions, here it is probably the right call.

However, if you are startup starting today, it would probably be a good idea
to consider other options, that could be used as an advantage against
incumbents.

------
hwc
A common issue with C++ software is the need for a stable, standard ABI, which
C provides but C++ does not (except through `extern "C"`). Because C++ name
mangling is not standardized and the standard library headers have tons of
implementation-specific details, something like `void
foo(std::unique_ptr<Bar>);` does not have a stable ABI.

~~~
jcranmer
In practice, there is a stable and standard ABI in C++. On Windows systems,
you use the (undocumented, but mostly reverse-engineered) MSVC ABI. On
everybody else, you use the confusingly-named Itanium ABI, except for
exception handling on ARM, which uses a slightly different ABI.

Standard library implementations do not necessarily share the same ABI, but it
is possible to interoperate between libc++ and libstdc++, and libstdc++
maintains ABI compatibility across different versions.

And, to be pedantic, C does not provide a stable, standard ABI. It is the
platforms themselves that provide this ABI standard, and these platforms
equally provide a C++ ABI standard. So C++ ABI compatibility is no more or
less a problem than C ABI compatibility.

~~~
paulddraper
The legitimate difference between C and C++ ABIs is that the C ABI is easier
to understand and reason about.

It's analogous to Java and Scala; each has an ABI, but it's easier to tell
when the former breaks ABI than the latter.

~~~
likeliv
That's right. C being more limited, it has a more simplistic ABI. But the
parent comment was replying the "need for a stable, standard ABI, which C
provide". Which is misleading as both C++ and C have the same level of
stability and standardisation of their ABI. (I.e: none of them is
standardized, but both of them are stable on practice)

~~~
paulddraper
Yep, you're right.

There is a difference, but the difference is in complexity, not availability.

