Skip to content

Commit 4d91aa5

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 0691f03 commit 4d91aa5

File tree

4 files changed

+59
-50
lines changed

4 files changed

+59
-50
lines changed

jbmc/src/java_bytecode/java_bytecode_convert_method.cpp

+41-38
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,8 @@ codet java_bytecode_convert_methodt::convert_instructions(
10211021
}
10221022

10231023
if(i_it->statement=="athrow" ||
1024+
i_it->statement=="monitorenter" ||
1025+
i_it->statement=="monitorexit" ||
10241026
i_it->statement=="putfield" ||
10251027
i_it->statement=="getfield" ||
10261028
i_it->statement=="checkcast" ||
@@ -1246,6 +1248,20 @@ codet java_bytecode_convert_methodt::convert_instructions(
12461248
"function expected to have exactly one parameter");
12471249
c = replace_call_to_cprover_assume(i_it->source_location, c);
12481250
}
1251+
// replace calls to CProver.atomicBegin
1252+
else if(statement == "invokestatic" &&
1253+
arg0.get(ID_identifier) ==
1254+
"java::org.cprover.CProver.atomicBegin:()V")
1255+
{
1256+
c = codet(ID_atomic_begin);
1257+
}
1258+
// replace calls to CProver.atomicEnd
1259+
else if(statement == "invokestatic" &&
1260+
arg0.get(ID_identifier) ==
1261+
"java::org.cprover.CProver.atomicEnd:()V")
1262+
{
1263+
c = codet(ID_atomic_end);
1264+
}
12491265
else if(statement=="invokeinterface" ||
12501266
statement=="invokespecial" ||
12511267
statement=="invokevirtual" ||
@@ -1634,13 +1650,9 @@ codet java_bytecode_convert_methodt::convert_instructions(
16341650
results[0]=
16351651
binary_predicate_exprt(op[0], ID_java_instanceof, arg0);
16361652
}
1637-
else if(statement=="monitorenter")
1653+
else if(statement == "monitorenter" || statement == "monitorexit")
16381654
{
1639-
c = convert_monitorenter(i_it->source_location, op);
1640-
}
1641-
else if(statement=="monitorexit")
1642-
{
1643-
c = convert_monitorexit(i_it->source_location, op);
1655+
c = convert_monitorenterexit(statement, op, i_it->source_location);
16441656
}
16451657
else if(statement=="swap")
16461658
{
@@ -1960,6 +1972,29 @@ codet java_bytecode_convert_methodt::convert_switch(
19601972
return code_switch;
19611973
}
19621974

1975+
codet java_bytecode_convert_methodt::convert_monitorenterexit(
1976+
const irep_idt &statement,
1977+
const exprt::operandst &op,
1978+
const source_locationt &source_location)
1979+
{
1980+
const irep_idt descriptor = (statement == "monitorenter") ?
1981+
"java::java.lang.Object.monitorenter:(Ljava/lang/Object;)V" :
1982+
"java::java.lang.Object.monitorexit:(Ljava/lang/Object;)V";
1983+
1984+
// becomes a function call
1985+
code_typet type(
1986+
{code_typet::parametert(java_reference_type(void_typet()))},
1987+
void_typet());
1988+
code_function_callt call;
1989+
call.function() = symbol_exprt(descriptor, type);
1990+
call.lhs().make_nil();
1991+
call.arguments().push_back(op[0]);
1992+
call.add_source_location() = source_location;
1993+
if(needed_lazy_methods && symbol_table.has_symbol(descriptor))
1994+
needed_lazy_methods->add_needed_method(descriptor);
1995+
return call;
1996+
}
1997+
19631998
void java_bytecode_convert_methodt::convert_dup2(
19641999
exprt::operandst &op,
19652000
exprt::operandst &results)
@@ -2399,38 +2434,6 @@ codet &java_bytecode_convert_methodt::do_exception_handling(
23992434
return c;
24002435
}
24012436

2402-
codet java_bytecode_convert_methodt::convert_monitorexit(
2403-
const source_locationt &location,
2404-
const exprt::operandst &op) const
2405-
{
2406-
code_typet type;
2407-
type.return_type() = void_typet();
2408-
type.parameters().resize(1);
2409-
type.parameters()[0].type() = java_reference_type(void_typet());
2410-
code_function_callt call;
2411-
call.function() = symbol_exprt("java::monitorexit", type);
2412-
call.lhs().make_nil();
2413-
call.arguments().push_back(op[0]);
2414-
call.add_source_location() = location;
2415-
return call;
2416-
}
2417-
2418-
codet java_bytecode_convert_methodt::convert_monitorenter(
2419-
const source_locationt &location,
2420-
const exprt::operandst &op) const
2421-
{
2422-
code_typet type;
2423-
type.return_type() = void_typet();
2424-
type.parameters().resize(1);
2425-
type.parameters()[0].type() = java_reference_type(void_typet());
2426-
code_function_callt call;
2427-
call.function() = symbol_exprt("java::monitorenter", type);
2428-
call.lhs().make_nil();
2429-
call.arguments().push_back(op[0]);
2430-
call.add_source_location() = location;
2431-
return call;
2432-
}
2433-
24342437
void java_bytecode_convert_methodt::convert_multianewarray(
24352438
const source_locationt &location,
24362439
const exprt &arg0,

jbmc/src/java_bytecode/java_bytecode_convert_method_class.h

+5-8
Original file line numberDiff line numberDiff line change
@@ -420,14 +420,6 @@ class java_bytecode_convert_methodt:public messaget
420420
codet &c,
421421
exprt::operandst &results);
422422

423-
codet convert_monitorenter(
424-
const source_locationt &location,
425-
const exprt::operandst &op) const;
426-
427-
codet convert_monitorexit(
428-
const source_locationt &location,
429-
const exprt::operandst &op) const;
430-
431423
codet &do_exception_handling(
432424
const methodt &method,
433425
const std::set<unsigned int> &working_set,
@@ -446,6 +438,11 @@ class java_bytecode_convert_methodt:public messaget
446438
codet &c,
447439
exprt::operandst &results) const;
448440

441+
codet convert_monitorenterexit(
442+
const irep_idt &statement,
443+
const exprt::operandst &op,
444+
const source_locationt &source_location);
445+
449446
codet &replace_call_to_cprover_assume(source_locationt location, codet &c);
450447

451448
void convert_invoke(

jbmc/src/java_bytecode/simple_method_stubbing.cpp

+11-4
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,17 @@ void java_simple_method_stubst::create_method_stub(symbolt &symbol)
233233
void java_simple_method_stubst::check_method_stub(const irep_idt &symname)
234234
{
235235
const symbolt &sym = *symbol_table.lookup(symname);
236-
if(
237-
!sym.is_type && sym.value.id() == ID_nil && sym.type.id() == ID_code &&
238-
// Don't stub internal locking primitives:
239-
sym.name != "java::monitorenter" && sym.name != "java::monitorexit")
236+
if(!sym.is_type && sym.value.id() == ID_nil &&
237+
sym.type.id() == ID_code &&
238+
// do not stub internal locking calls as 'create_method_stub' does not
239+
// automatically create the appropriate symbols for the formal parameters.
240+
// This means that symex will (rightfully) crash when it encounters the
241+
// function call as it will not be able to find symbols for the fromal
242+
// parameters.
243+
sym.name !=
244+
"java::java.lang.Object.monitorenter:(Ljava/lang/Object;)V" &&
245+
sym.name !=
246+
"java::java.lang.Object.monitorexit:(Ljava/lang/Object;)V")
240247
{
241248
create_method_stub(*symbol_table.get_writeable(symname));
242249
}

src/goto-programs/builtin_functions.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -855,12 +855,14 @@ void goto_convertt::do_function_call_symbol(
855855
}
856856
else if(identifier==CPROVER_PREFIX "atomic_begin" ||
857857
identifier=="__CPROVER::atomic_begin" ||
858+
identifier=="java::org.cprover.CProver.atomicBegin:()V" ||
858859
identifier=="__VERIFIER_atomic_begin")
859860
{
860861
do_atomic_begin(lhs, function, arguments, dest);
861862
}
862863
else if(identifier==CPROVER_PREFIX "atomic_end" ||
863864
identifier=="__CPROVER::atomic_end" ||
865+
identifier=="java::org.cprover.CProver.atomicEnd:()V" ||
864866
identifier=="__VERIFIER_atomic_end")
865867
{
866868
do_atomic_end(lhs, function, arguments, dest);

0 commit comments

Comments
 (0)