-
Notifications
You must be signed in to change notification settings - Fork 273
Make global string_container more resilient to different static init orders #1213
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
Conversation
clang -Wall says: Struct_Initialization1/main.c:16:38: warning: suggest braces around initialization of subobject [-Wmissing-braces] struct _classinfo nullclass1 = { 42, 1, 2, 3, 4 }; ^~~~ { } and then constructs a suitable object. Our implementation now attempts to build an initializer list if a variable-length array is encountered; if this succeeds, the same suitable object is constructed. Variable-length arrays in the middle of a struct are not permitted (neither by GCC nor Clang or our C front-end).
Previously the code would rely on type sizes being constant when building a subtraction; this is unnecessary as the expression is sent to the solver for evaluation anyway.
fgets may (and certainly does when successful) change the contents of the buffer passed in. Building a regression test showed further deficiences in the stdio library model: 1) MacOS uses _fdopen; 2) fclose uses free from stdlib.h.
Licensing: I had contributed these myself to the SV-COMP benchmarks.
Array initialization with a non-array is expected to fail
…apply miniBDD: added a non-recursive variant of APPLY
vectors don't need to be handled, they have been removed via remove_vector.
Unlike CBMC, all output is enabled in debug mode only.
All symex limits use value -1 as marking "not set". Use size_t for counting statistics.
The solver back end cannot necessarily handle unbounded integers. Do not use them unless explicitly requested/supported.
fix for operator< on reverse_keyt in miniBDD, fixing segfault in ebmc
Symex improvements
C library modelling: fgets, getopt, vasprintf
Avoid using integer_typet where unsuitable
Follow-up to 260e03d: instead of using negative numbers to represent "limit not set", use the maximum value as default.
Avoid spurious signed/unsigned comparison warnings
Support out-of-bounds checks on arrays of dynamic size
Enable extractbits over arbitrary types, fix byte extract omission
Stop using C headers
fe41573
to
ee8ea7d
Compare
src/util/string_container.cpp
Outdated
/// Get a reference to the global string container. | ||
string_containert &get_string_container() | ||
{ | ||
static string_containert ret{}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are those {}
required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They're not, but they make it clear that default-initialisation is intentional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be done if done consistently across the code base. Else please remove them for we don't (yet) do it elsewhere.
What is the performance difference? |
I'm not sure how to measure the performance difference. This PR shouldn't affect performance at all, because it only changes the order in which static objects are initialised. The total number of static initialisations is unchanged. |
ee8ea7d
to
e6dcaa7
Compare
I believe this is a problem that needs to be addressed before this PR can be merged.
How about the non-inlined function calls that will now be necessary each time |
e6dcaa7
to
eb89bc0
Compare
Possible alternative: instead of a
The cost should be minimal for most sensible implementations per http://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables |
Apart from the cost of function call there's going to be a performance hit similar to reading atomic ("magic static" - C++11 static variable initialisation is thread safe, so likely implemented using atomics). It's not implemented in VC2013 which we're supporting. If irep reference counting is not thread safe either, then that is a problem that can be safely ignored. (VC Support) Moving |
If we explicitly inline the function, wouldn't we end up with one copy of the static local variable for each translation unit? |
@reuk Apparently not.
|
Some of the answers on StackOverflow say you may still end up with one instance per TU but the linker will pick a specific one to be the "canonical" instance, although I guess this may be implementation-dependent and may depend on LTO... I haven't been able to find hard evidence one way or the other. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving on the basis that my original problem is fixed, but I don't know enough to weigh in on the other topics. Obviously a senior developer needs to approve this anyways.
Don't get me wrong: I'm all for getting rid of the undefinedness that initialisation of static global objects induces; but this must not be merged until a performance evaluation is performed. |
@tautschnig How would you propose to benchmark this PR? |
This PR should not be benchmarked differently from any other PR, even though it is slightly easier here. Doing a summary profile across the regression tests might suffice for this PR if specific attention is paid to where in the profile the affected functions ( Proper benchmarking would entail analysis of the effect on overall performance across a large set of benchmark inputs. |
The following are times to run With patch:
Master:
|
That experiment won't provide more than the most basic sanity check. The bare minimum is actual profiling so that you can get information on what fraction of the total time is spent on the mentioned functions. |
If it would help, I should be int he office tomorrow and have done quite a bit of profiling of CBMC and we could chat about it. Also at one point @Degiorgio had an interest in this code... |
Closing as duplicate of #1218 seeing as both are targeting develop now. |
At the moment, if we initialise a static object which depends on the global string_container, there's no guarantee which object will be initialised first, which means the string_container may be uninitialised when first used. This problem was spotted by @jasigal recently.
This PR wraps the global object in a function which ensures it is initialised before it is first used.