Skip to content

Commit f3b47ea

Browse files
dcattaruzzaDegiorgio
authored andcommitted
JBMC: Modified the instrumentation of monitorexit/enter instructions
The monitorenter and monitorexit instructions are used by the JVM to coordinate access to an object in the context of multiple threads. We have previously added two methods to the object model that use a counter to implement a reentrant lock. Calls to 'org.cprover.CProver.atomicBegin:()V"' and 'org.cprover.CProver.atomicEnd:()V' ensure that multiple threads do not race in the access/modification of this counter. In-order to support synchronization blocks, when the monitorexit/moniitorenter bytecode instruction is executed JBMC must call the aforementioned object model. To this end, this commit makes the following changes: 1. Transforms the monitorenter and monitorexit bytecode instructions into function-calls to the object model. Specifically, 'java.lang.Object.monitorenter:(Ljava/lang/Object;)V' and 'java.lang.Object.monitorexit:(Ljava/lang/Object;)V'. 2. Transforms 'org.cprover.CProver.atomicBegin:()V"' and 'org.cprover.CProver.atomicEnd:()V' into the appropriate codet instructions. Added the appropriate target-handlers if monitorenter or monitorexit are in the context of a try-catch block.
1 parent e151051 commit f3b47ea

File tree

3 files changed

+42
-24
lines changed

3 files changed

+42
-24
lines changed

jbmc/src/java_bytecode/java_bytecode_convert_method.cpp

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,8 @@ codet java_bytecode_convert_methodt::convert_instructions(
10141014
}
10151015

10161016
if(i_it->statement=="athrow" ||
1017+
i_it->statement=="monitorenter" ||
1018+
i_it->statement=="monitorexit" ||
10171019
i_it->statement=="putfield" ||
10181020
i_it->statement=="getfield" ||
10191021
i_it->statement=="checkcast" ||
@@ -1304,6 +1306,20 @@ codet java_bytecode_convert_methodt::convert_instructions(
13041306
loc.set_function(method_id);
13051307
c.add_source_location()=loc;
13061308
}
1309+
// replace calls to CProver.atomicBegin
1310+
else if(statement == "invokestatic" &&
1311+
id2string(arg0.get(ID_identifier)) ==
1312+
"java::org.cprover.CProver.atomicBegin:()V")
1313+
{
1314+
c = codet(ID_atomic_begin);
1315+
}
1316+
// replace calls to CProver.atomicEnd
1317+
else if(statement == "invokestatic" &&
1318+
id2string(arg0.get(ID_identifier)) ==
1319+
"java::org.cprover.CProver.atomicEnd:()V")
1320+
{
1321+
c = codet(ID_atomic_end);
1322+
}
13071323
else if(statement=="invokeinterface" ||
13081324
statement=="invokespecial" ||
13091325
statement=="invokevirtual" ||
@@ -2340,33 +2356,30 @@ codet java_bytecode_convert_methodt::convert_instructions(
23402356
results[0]=
23412357
binary_predicate_exprt(op[0], ID_java_instanceof, arg0);
23422358
}
2343-
else if(statement=="monitorenter")
2344-
{
2345-
// becomes a function call
2346-
code_typet type;
2347-
type.return_type()=void_typet();
2348-
type.parameters().resize(1);
2349-
type.parameters()[0].type()=java_reference_type(void_typet());
2350-
code_function_callt call;
2351-
call.function()=symbol_exprt("java::monitorenter", type);
2352-
call.lhs().make_nil();
2353-
call.arguments().push_back(op[0]);
2354-
call.add_source_location()=i_it->source_location;
2355-
c=call;
2356-
}
2357-
else if(statement=="monitorexit")
2359+
else if(statement == "monitorenter" || statement == "monitorexit")
23582360
{
2361+
std::string descriptor;
2362+
if(statement == "monitorenter")
2363+
descriptor =
2364+
"java::java.lang.Object.monitorenter:(Ljava/lang/Object;)V";
2365+
else
2366+
descriptor =
2367+
"java::java.lang.Object.monitorexit:(Ljava/lang/Object;)V";
2368+
23592369
// becomes a function call
23602370
code_typet type;
2361-
type.return_type()=void_typet();
2371+
type.return_type() = void_typet();
23622372
type.parameters().resize(1);
2363-
type.parameters()[0].type()=java_reference_type(void_typet());
2373+
type.parameters()[0].type() = java_reference_type(void_typet());
2374+
23642375
code_function_callt call;
2365-
call.function()=symbol_exprt("java::monitorexit", type);
2376+
call.function() = symbol_exprt(descriptor, type);
23662377
call.lhs().make_nil();
23672378
call.arguments().push_back(op[0]);
2368-
call.add_source_location()=i_it->source_location;
2369-
c=call;
2379+
call.add_source_location() = i_it->source_location;
2380+
if(needed_lazy_methods && symbol_table.has_symbol(descriptor))
2381+
needed_lazy_methods->add_needed_method(descriptor);
2382+
c = call;
23702383
}
23712384
else if(statement=="swap")
23722385
{

jbmc/src/java_bytecode/simple_method_stubbing.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,13 @@ void java_simple_method_stubst::create_method_stub(symbolt &symbol)
222222
void java_simple_method_stubst::check_method_stub(const irep_idt &symname)
223223
{
224224
const symbolt &sym = *symbol_table.lookup(symname);
225-
if(
226-
!sym.is_type && sym.value.id() == ID_nil && sym.type.id() == ID_code &&
227-
// Don't stub internal locking primitives:
228-
sym.name != "java::monitorenter" && sym.name != "java::monitorexit")
225+
if(!sym.is_type && sym.value.id() == ID_nil &&
226+
sym.type.id() == ID_code &&
227+
// do not stub internal locking calls
228+
sym.name !=
229+
"java::java.lang.Object.monitorenter:(Ljava/lang/Object;)V" &&
230+
sym.name !=
231+
"java::java.lang.Object.monitorexit:(Ljava/lang/Object;)V")
229232
{
230233
create_method_stub(*symbol_table.get_writeable(symname));
231234
}

src/goto-programs/builtin_functions.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,12 +883,14 @@ void goto_convertt::do_function_call_symbol(
883883
}
884884
else if(identifier==CPROVER_PREFIX "atomic_begin" ||
885885
identifier=="__CPROVER::atomic_begin" ||
886+
identifier=="java::org.cprover.CProver.atomicBegin:()V" ||
886887
identifier=="__VERIFIER_atomic_begin")
887888
{
888889
do_atomic_begin(lhs, function, arguments, dest);
889890
}
890891
else if(identifier==CPROVER_PREFIX "atomic_end" ||
891892
identifier=="__CPROVER::atomic_end" ||
893+
identifier=="java::org.cprover.CProver.atomicEnd:()V" ||
892894
identifier=="__VERIFIER_atomic_end")
893895
{
894896
do_atomic_end(lhs, function, arguments, dest);

0 commit comments

Comments
 (0)