Making the instrumented clinit_wrapper function thread-safe#1786
Making the instrumented clinit_wrapper function thread-safe#1786Degiorgio wants to merge 93 commits intodiffblue:developfrom
Conversation
a79f687 to
76b1842
Compare
|
. @smowton should definitely look at this as has been touching this recently, I'd also appreciate a test-gen pointer bump. |
76b1842 to
9694036
Compare
There was a problem hiding this comment.
Do you require a full int here?
There was a problem hiding this comment.
It might be worth factoring out the clinit generation into a separate .cpp file in order to reduce the size of this monster.cpp.
There was a problem hiding this comment.
agreed, will do this.
There was a problem hiding this comment.
Hang on! This is already done in the PR this is racing against :)
smowton
left a comment
There was a problem hiding this comment.
Some nitpicks, and some bad news: this is going to clash with #1774, which I hope to get in later today, and reworks how static init methods are generated to create them lazily, and create their state variables (the bool already_run, and now your new state variable) before method conversion.
The good news however: this should be quite easy to rebase on #1774 -- simply create your additional global where #1774 does and copy-paste your init code into my new java_static_initializers.cpp file.
The local variable should be created during method elaboration (i.e. in get_clinit_wrapper_body).
There was a problem hiding this comment.
Since this is new code, use the new clang-format-compatible / human-readable operator spacing (i.e. spaces around ==, =, etc)
There was a problem hiding this comment.
Consider making a std_code entry for these?
There was a problem hiding this comment.
Generally base_name is the unqualified name, e.g. name == java::Class.field => base_name == field.
There was a problem hiding this comment.
This thing is rather specific! Probably rename it "add_variable_symbol"?
There was a problem hiding this comment.
These aren't very obvious at the callsite -- perhaps use two-valued enums so we don't mix up true, false and false, true?
There was a problem hiding this comment.
These don't really need to be members -- they're clearly static helpers
|
@smowton, oks will rebase on top of 1774 |
f8a32ea to
6691b0d
Compare
|
@smowton , rebase done, can you take a look please? |
7143b9f to
72c061b
Compare
There was a problem hiding this comment.
instead of 'RETURN'? yes INIT_COMPLETE is better, changing.
There was a problem hiding this comment.
@Degiorgio Do not forget to update the documentation above
There was a problem hiding this comment.
Rename this variable _thread_local rather than just _local to clarify we mean thread-locality not that it's a function local
There was a problem hiding this comment.
Out of date? AFAIK there is no state named READY anymore
There was a problem hiding this comment.
yep this should be RETURN
There was a problem hiding this comment.
?? Will that work? Presumably we want the other thread to busy-wait for IN_PROGRESS to transition to DONE in this case. If this is indeed magic that symex understands like a wait then write that in the comments.
There was a problem hiding this comment.
Yes, that will work. It's exactly how POSIX mutexes are implemented in pthread_mutex_lock, see here:
https://github.com/diffblue/cbmc/blob/develop/src/ansi-c/library/pthread_lib.c#L132
Thanks, we will indeed document it.
There was a problem hiding this comment.
Typo: "is used as an optimization"
0b9e580 to
bfe8097
Compare
|
@smowton all suggestions applied, please have a another look |
43ed109 to
43e69ac
Compare
|
@peterschrammel can you take another look at this please? All the issues you raised should be addressed. |
smowton
left a comment
There was a problem hiding this comment.
Sorry, more stuff to fix
There was a problem hiding this comment.
fwiw the value member of a local variable is ignored; it's up to you to generate an initialiser. Therefore recommend passing nil_exprt() there and checking in add-new-symbol that function-scoped (non-global) variables do not attempt to specify an initialiser this way.
There was a problem hiding this comment.
I think this comment is inaccurate, does it belong to the thread-local variable instead? The function-local one is just used to copy the global so you can inspect it and then maybe return outside a critical section.
There was a problem hiding this comment.
the comment is misleading agreed. rewording.
There was a problem hiding this comment.
We are using a local boolean for inspection on purpose. The reason being that inspecting the global state resulted in symex related propagation issues in multi-threaded code.
There was a problem hiding this comment.
Also the local should be created in the populate-function-body phase. Only globals should be created at this stage (i.e. the global, the thread-scoped variable, and the function symbol itself).
de6a0e4 to
ef8bf61
Compare
A temporary variable is introduced later for this if_exprt and the mode needs to be known for the variable, other an invariant may fail.
This checks the ID_mode fix for if_expr in preprocessing works correctly.
This is an implementation detail that need not be exposed to users - the interface is the free function base_type_eq.
... and sort the remaining ones lexicographically.
The previous version of clinit_wrapper did not conform to the JVM specification (section 5.5) as it did not support concurrency. More specifically, the clinit_wrapper has to be carefully synchronised as other threads may try to initialize a given class or interface at the same-time. This commit makes the clinit_wrapper thread-safe by introducing a critical section and two state variables. The commit implements a simplification of the algorithm defined in section 5.5 of the JVM specification. For instance, exceptions thrown during the execution of static initializers are not properly handled.
Setting this option will enable support for analysing multi-threaded java programs. For now, this means that a thread-safe version of clinit_wrapper is generated. This was made opt-in instead of opt-out as the inclusion of thread-safe clinit wrapper has negative implications for performance. Commit also adds appropriate regression tests that use this flag to test the resulting modifications to the clinit_wrapper
a5ab2ef to
4c7b646
Compare
The previous version of clinit_wrapper did not conform to the JVM specification (section 5.5) as it did not support concurrency. More specifically, the clinit_wrapper has to be carefully synchronized
as other threads may try to initialize a given class or interface at the same-time.
This commit adds a new implementation of the clinit_wrapper that is thread-safe. This is achieved by introducing a critical section and two state variables. The commit implements a simplification of the algorithm defined in section 5.5 of the JVM spec. For instance exceptions thrown during the execution of static initializers are not properly handled. To use this implementation instead of the old one, a new option has been added 'java-threading'. We made this opt-in instead of simply replacing the old one for performance reasons.
Commit duplicates some regression tests, while these tests do not exhibit concurrency, the resulting change to the clinit_wrapper trigged by specifying 'java-threading' effects non-concurrent code.
Note: this change is required in-order to add concurrency support to the java-front-end.