-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How do we handle "immortal" pointers that are reachable for entire lifetime of an app? #1068
Comments
Per our editor's discussion, Herb, can you please:
|
Besides that issue, are there other problems why |
My motivating example is the following pull request google/googletest#1142 for gtest. In summary, MSVC's debug CRT built-in memory leak detector is reporting false positives due to pointers to objects that are intentionally reachable for the entire lifetime of the app. Some previous authors have ignored Google's forbidden variables of static storage duration guideline and have attempted to fix this issue by ensuring all memory is deallocated before app terminates. I believe this fix is theoretically possible given sufficient engineering effort. However the engineering effort maybe too costly as it's very difficult to verify the fix given all the different build/platform configurations used for gtest in the wild, e.g. the .obj files maybe complied in different order which could change the destruction order of static variables. Instead, as Google recommends, a simpler engineering solution is to allow pointers to "immortal" objects that are never destructed as this can avoid a lot of engineering complications, especially when it's difficult coordinate the destruction order of static variables with destruction order of various threads. |
(a) In the correct context, a pointer to an object that’s intentionally reachable for the entire lifetime of the app, let’s call it an “immortal pointer”, should be a supported coding idiom as it leads to simpler code. Especially if the alternative is to coordinate the destruction order of static variables with destruction of various threads that access the before mentioned static variables (I believe this is the essence of Titus’ reasoning). (b) If we accept that immortal pointers should be a supported coding idiom then it would be helpful to use a special coding convention to identify its usage in code. e.g.
for the following reasons:
|
IMHO that is a perfectly good way to say "this pointer has an owner that lives for the duration of the program". Maybe add a I appreciate it doesn't help solve the debug CRT giving false positives. |
I agree and, by convention, the following
could implicitly mean "this pointer has an owner that lives for the duration of the program". The debug CRT giving false positives can be solved by
So strictly speaking the type However in the gtest, which is my original motivation, the pointer I need to mark as "immortal" is a non-const member variable and not a static which, at first glance, does seem odd. |
From this discussion, it seems to me that if you really want to say "dynamically allocated object that is never deleted, not even during static destruction," then
is a reasonable answer today. I would expect static checkers not to warn on the missing Have you tried that solution? |
Yes
is a good solution for this particular pattern. The other use case from gtest is
is the following the right answer?
I was expecting that static checkers should or, sometime in the future, warn that |
The main problem with anything remotely immortal is that it breaks dynamic linking and reuse in libraries. At least static globals or locals do not. That is in addition to producing spurious warnings in memory leak analysis tools. The static global initialization order rule is important to check but then again is mostly about tracing dependencies between these globals. The actual order rarely matters. |
That's true and Google also notes that their Abeil library suffers from the same limitation: From https://abseil.io/about/compatibility.
I believe Google's reasoning is that, if you can live with this limitation, then immortal pointers can greatly simplify code as don't need to track dependencies to ensure correct destruction order. Especially for multi-threaded apps. |
The "Google C++ Style Guide" forbids variables of static storage duration and Titus Winters in
"CppCon 2017: Titus Winters “Hands-On With Abseil" ( https://www.youtube.com/watch?v=xu7q8dGvuwk ) gave some of the engineering reasons behind this rules which seems to be entirely reasonable.
In short , at the global namespace, Google's prefers this
over
as
new std::string("Hello")
is intended to be reachable for the entire lifetime of the app and thus it's not strictly necessary to run std::string's dtor and deallocate memory as the OS will eventually recover the memory when process finally terminates. In fact it helps ifnew std::string("Hello")
is never deleted as we can avoid the complication of coordinating its destruction order with respect to other static variables/threads that may refer to it when a program exits main.In this situation, I assume
static gsl::owner<std::string*> s = new std::string("Hello");
is not appropriate as the code checking tools should warn that adelete s
is missing?Instead, does it makes sense to have a
gsl::immortal
to indicate that the object is intentionally never deleted? e.g.In addition, we could complement gsl::immortal with gsl::make_immortal(...) as this give us :
This would be especially helpful for the light-weight mem leak detector that's built into MSVC's debug CRT.
e.g.
The text was updated successfully, but these errors were encountered: