Join GitHub today
GitHub is home to over 36 million developers working together to host and review code, manage projects, and build software together.
Sign upstring_id::NULL_ID isn't always initialized in time #17197
Comments
Coolthulhu
added
the
<Crash / Freeze>
label
Jun 15, 2016
Coolthulhu
added this to the 0.D milestone
Jun 15, 2016
This comment has been minimized.
This comment has been minimized.
|
I say the item factory (which causes the linked bug) should be initialized from the game class (maybe from its constructor). Currently it's statically created, the same as the NULL_ID and that causes the problem. Alternatively it could be created as static object inside a static wrapper function (similar to |
This comment has been minimized.
This comment has been minimized.
|
I'd much prefer initializing from the game object between those
alternatives.
|
oseiler
referenced this issue
Jul 7, 2016
Closed
fixes #17197: Change string_id<>::NULL_ID to static function #17600
This comment has been minimized.
This comment has been minimized.
|
Would it be possible to have a single "has ID" class with an "init null ID" method, invoke the method in init.cpp and statically warn if a class uses a null ID but doesn't have said class? Alternatively, ensure that using null ID causes a crash if it isn't explicitly invoked somewhere. |
This comment has been minimized.
This comment has been minimized.
|
Why not change static const string_id<Foo> &string_id<Foo>::NULL_ID() {
static const string_id<Foo> instance( "..." );
return instance;
}That has no external dependencies and is initialized as soon as it's needed. |
This comment has been minimized.
This comment has been minimized.
|
What would happen if it was invoked circularly? Crash or unspecified behavior? |
This comment has been minimized.
This comment has been minimized.
|
It's simply not invoked circular. The constructor (that gets invoked when If we have a circular dependency, it needs to be changed anyway. Function static objects are the best solution because C++ guarantees their constructor is invoked at most once (it's even thread-safe). |
This comment has been minimized.
This comment has been minimized.
|
This keeps coming up in different parts of the code and is due to the idiom
of returning const references to things and then sometimes not having a
reference to return. Do we have a clear idea of the benefit of this idiom,
because the cost so far is crash bugs scattered around in the code?
If we return by value instead this issue disappears for good.
|
This comment has been minimized.
This comment has been minimized.
|
When did local reference return cause crashes? It should cause a compiler warning rather than undefined behavior later on. NULL_ID not being initialized in time is not related to references, but rather static initialization. At the moment NULL_IDs are initialized in static context, which means the order varies between OSes and compilers (Windows+mingw doesn't sort alphabetically, for example). |
This comment has been minimized.
This comment has been minimized.
|
Local reference return is undefined, and we have had crashes caused by it
since the local goes out of scope and is reused. The safer option is
returning by value, which allows us to return a local variable safely.
|
This comment has been minimized.
This comment has been minimized.
|
Yes, but the compiler should warn about it. I'm sure it does in the most common case. It is only risky in the case of objects that change a lot between worlds. But I don't recall this happening in the core game (someone would need to redefine "null" object or something like that) and those objects also benefit the most from not being rebuilt every time. |
This comment has been minimized.
This comment has been minimized.
In theory yes, in practice this isn't the first time this specific idiom (returning a const reference) has broken things, and I guarantee it won't be the last. My question is, do we have evidence that the performance benefit of doing it this way is worth the fragility that comes with it? People seem to find it easy to internalize the "return objects by const reference is good" mantra, but when one of these methods needs to return a null object, they frequently do not know or think to use the safe idiom. I'm proposing that we can simply make the method return a copy instead, which has none of this fragility. The only down side to this approach is a potential performance penalty, which AFAIK is totally unquantified, which is why I said:
|
This comment has been minimized.
This comment has been minimized.
When did it break things? The only fragile part of it I can think of here is item factory, which changes between save+load and sometimes during single game. But then, it HAS to return references/pointers in many cases, because items need pointers to types.
I don't see that fragility. I recall multiple crashes related to pointer/reference getting scrambled, but I can't think of a single case when fixing it by returning a value was a real option. The crash related to NULL_ID would still happen just fine with by-value returns since it depends on constructors being invoked in unspecified order, which by-value return doesn't affect.
You mean the null id function or everything in general? It's the static order that causes the crash here, because As for performance: |
codemime
referenced this issue
Jan 15, 2017
Closed
Current master (8a5215) doesn't build with clang #18493
This comment has been minimized.
This comment has been minimized.
Remove the definition but leave the declaration for that operator. You should get a series of linker errors for each usage. You may need to adjust your compiler flags to suppress the '...and 43 other occurrences' contraction. |
kevingranade
added this to Blockers
in 0.D Release
Mar 2, 2017
This comment has been minimized.
This comment has been minimized.
|
This is purely a code quality issue. |
This comment has been minimized.
This comment has been minimized.
|
Can I take it off from blockers? |
kevingranade
removed this from the 0.D milestone
Mar 21, 2017
Coolthulhu
moved this from Blockers
to Open Issues
in 0.D Release
Mar 25, 2017
This comment has been minimized.
This comment has been minimized.
|
I don't know if this is wholly related, but clang-3.8 and above warns about undefined instantiations of ::NULL_ID variants in various templated classes. Example:
I don't know if adding explicit instatiation declarations where they are needed will help the problem, but at least this current design is causing build failures with the current setup with RELEASE=1 on clang-3.8+. |
kevingranade
removed this from Easy Issues
in 0.D Release
Apr 15, 2017
Leland
referenced this issue
May 5, 2017
Merged
[READY] Add explicit instantiation of string_id<T>::NULL_ID to make clang happy. #20946
This comment has been minimized.
This comment has been minimized.
|
@kevingranade with #20946 merged, is this closed? |
This comment has been minimized.
This comment has been minimized.
|
Good catch, the new template code does force us to in it everything up front, so this should not recur. |
kevingranade
closed this
May 18, 2017
This comment has been minimized.
This comment has been minimized.
|
I was mistaken, we're still vulnerable to this: |
Coolthulhu commentedJun 15, 2016
Causes #17177, currently hacked around with #17179 but it's still a big risk of future crashes and so should be fixed by actually addressing the problem.