Skip to content

Commit a9ad534

Browse files
Merge pull request diffblue#4280 from thomasspriggs/tas/entry_point
Parameterise usage of `java_build_arguments` to allow replacing this function only
2 parents 13b5e2b + fe24914 commit a9ad534

File tree

3 files changed

+206
-138
lines changed

3 files changed

+206
-138
lines changed

jbmc/src/java_bytecode/java_bytecode_language.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,15 @@ bool java_bytecode_languaget::generate_support_functions(
862862
assert_uncaught_exceptions,
863863
object_factory_parameters,
864864
get_pointer_type_selector(),
865-
string_refinement_enabled);
865+
string_refinement_enabled,
866+
[&](const symbolt &function, symbol_table_baset &symbol_table) {
867+
return java_build_arguments(
868+
function,
869+
symbol_table,
870+
assume_inputs_non_null,
871+
object_factory_parameters,
872+
get_pointer_type_selector());
873+
});
866874
}
867875

868876
/// Uses a simple context-insensitive ('ci') analysis to determine which methods

jbmc/src/java_bytecode/java_entry_point.cpp

Lines changed: 90 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ Author: Daniel Kroening, [email protected]
2828

2929
#define JAVA_MAIN_METHOD "main:([Ljava/lang/String;)V"
3030

31+
static optionalt<codet> record_return_value(
32+
const symbolt &function,
33+
const symbol_table_baset &symbol_table);
34+
35+
static code_blockt record_pointer_parameters(
36+
const symbolt &function,
37+
const std::vector<exprt> &arguments,
38+
const symbol_table_baset &symbol_table);
39+
40+
static codet record_exception(
41+
const symbolt &function,
42+
const symbol_table_baset &symbol_table);
43+
3144
static void create_initialize(symbol_table_baset &symbol_table)
3245
{
3346
// If __CPROVER_initialize already exists, replace it. It may already exist
@@ -72,22 +85,6 @@ static bool should_init_symbol(const symbolt &sym)
7285
return is_java_string_literal_id(sym.name);
7386
}
7487

75-
/// Get the symbol name of java.lang.Class' initializer method. This method
76-
/// should initialize a Class instance with known properties of the type it
77-
/// represents, such as its name, whether it is abstract, or an enumeration,
78-
/// etc. The method may or may not exist in any particular symbol table; it is
79-
/// up to the caller to check.
80-
/// The method's Java signature is:
81-
/// void cproverInitializeClassLiteral(
82-
/// String name,
83-
/// boolean isAnnotation,
84-
/// boolean isArray,
85-
/// boolean isInterface,
86-
/// boolean isSynthetic,
87-
/// boolean isLocalClass,
88-
/// boolean isMemberClass,
89-
/// boolean isEnum);
90-
/// \return Class initializer method's symbol name.
9188
irep_idt get_java_class_literal_initializer_signature()
9289
{
9390
static irep_idt signature =
@@ -294,18 +291,8 @@ bool is_java_main(const symbolt &function)
294291
return named_main && is_static && has_correct_type && public_access;
295292
}
296293

297-
/// Extends \p init_code with code that allocates the objects used as test
298-
/// arguments for the function under test (\p function) and
299-
/// non-deterministically initializes them.
300-
///
301-
/// All the code generated by this function goes to __CPROVER__start, just
302-
/// before the call to the method under test.
303-
///
304-
/// \returns A std::vector of symbol_exprt, one per parameter of \p function,
305-
/// containing the objects that can be used as arguments for \p function.
306-
exprt::operandst java_build_arguments(
294+
std::pair<code_blockt, std::vector<exprt>> java_build_arguments(
307295
const symbolt &function,
308-
code_blockt &init_code,
309296
symbol_table_baset &symbol_table,
310297
bool assume_init_pointers_not_null,
311298
java_object_factory_parameterst object_factory_parameters,
@@ -314,6 +301,7 @@ exprt::operandst java_build_arguments(
314301
const java_method_typet::parameterst &parameters =
315302
to_java_method_type(function.type).parameters();
316303

304+
code_blockt init_code;
317305
exprt::operandst main_arguments;
318306
main_arguments.resize(parameters.size());
319307

@@ -444,83 +432,98 @@ exprt::operandst java_build_arguments(
444432
init_code.add(std::move(input));
445433
}
446434

447-
return main_arguments;
435+
return make_pair(init_code, main_arguments);
448436
}
449437

450-
void java_record_outputs(
438+
/// Mark return value, pointer type parameters and the exception as outputs.
439+
static code_blockt java_record_outputs(
451440
const symbolt &function,
452441
const exprt::operandst &main_arguments,
453-
code_blockt &init_code,
454442
symbol_table_baset &symbol_table)
455443
{
456-
const java_method_typet::parameterst &parameters =
457-
to_java_method_type(function.type).parameters();
444+
code_blockt init_code;
458445

459-
exprt::operandst result;
460-
result.reserve(parameters.size()+1);
446+
if(auto return_value = record_return_value(function, symbol_table))
447+
{
448+
init_code.add(std::move(*return_value));
449+
}
461450

462-
bool has_return_value =
463-
to_java_method_type(function.type).return_type() != java_void_type();
451+
init_code.append(
452+
record_pointer_parameters(function, main_arguments, symbol_table));
464453

465-
if(has_return_value)
466-
{
467-
// record return value
468-
codet output(ID_output);
469-
output.operands().resize(2);
454+
init_code.add(record_exception(function, symbol_table));
470455

471-
const symbolt &return_symbol=
472-
*symbol_table.lookup(JAVA_ENTRY_POINT_RETURN_SYMBOL);
456+
return init_code;
457+
}
473458

474-
output.op0()=
475-
address_of_exprt(
476-
index_exprt(
477-
string_constantt(return_symbol.base_name),
478-
from_integer(0, index_type())));
479-
output.op1()=return_symbol.symbol_expr();
480-
output.add_source_location()=function.location;
459+
static optionalt<codet> record_return_value(
460+
const symbolt &function,
461+
const symbol_table_baset &symbol_table)
462+
{
463+
if(to_java_method_type(function.type).return_type() == java_void_type())
464+
return {};
481465

482-
init_code.add(std::move(output));
483-
}
466+
const symbolt &return_symbol =
467+
*symbol_table.lookup(JAVA_ENTRY_POINT_RETURN_SYMBOL);
484468

485-
for(std::size_t param_number=0;
486-
param_number<parameters.size();
469+
codet output(ID_output);
470+
output.operands().resize(2);
471+
output.op0() = address_of_exprt(index_exprt(
472+
string_constantt(return_symbol.base_name), from_integer(0, index_type())));
473+
output.op1() = return_symbol.symbol_expr();
474+
output.add_source_location() = function.location;
475+
return output;
476+
}
477+
478+
static code_blockt record_pointer_parameters(
479+
const symbolt &function,
480+
const std::vector<exprt> &arguments,
481+
const symbol_table_baset &symbol_table)
482+
{
483+
const java_method_typet::parameterst &parameters =
484+
to_java_method_type(function.type).parameters();
485+
486+
code_blockt init_code;
487+
488+
for(std::size_t param_number = 0; param_number < parameters.size();
487489
param_number++)
488490
{
489-
const symbolt &p_symbol=
491+
const symbolt &p_symbol =
490492
*symbol_table.lookup(parameters[param_number].get_identifier());
491493

492-
if(p_symbol.type.id()==ID_pointer)
493-
{
494-
// record as an output
495-
codet output(ID_output);
496-
output.operands().resize(2);
497-
output.op0()=
498-
address_of_exprt(
499-
index_exprt(
500-
string_constantt(p_symbol.base_name),
501-
from_integer(0, index_type())));
502-
output.op1()=main_arguments[param_number];
503-
output.add_source_location()=function.location;
504-
505-
init_code.add(std::move(output));
506-
}
494+
if(!can_cast_type<pointer_typet>(p_symbol.type))
495+
continue;
496+
497+
codet output(ID_output);
498+
output.operands().resize(2);
499+
output.op0() = address_of_exprt(index_exprt(
500+
string_constantt(p_symbol.base_name), from_integer(0, index_type())));
501+
output.op1() = arguments[param_number];
502+
output.add_source_location() = function.location;
503+
504+
init_code.add(std::move(output));
507505
}
506+
return init_code;
507+
}
508508

509+
static codet record_exception(
510+
const symbolt &function,
511+
const symbol_table_baset &symbol_table)
512+
{
509513
// record exceptional return variable as output
510514
codet output(ID_output);
511515
output.operands().resize(2);
512516

513517
// retrieve the exception variable
514-
const symbolt exc_symbol=*symbol_table.lookup(
515-
JAVA_ENTRY_POINT_EXCEPTION_SYMBOL);
518+
const symbolt &exc_symbol =
519+
symbol_table.lookup_ref(JAVA_ENTRY_POINT_EXCEPTION_SYMBOL);
516520

517521
output.op0()=address_of_exprt(
518522
index_exprt(string_constantt(exc_symbol.base_name),
519523
from_integer(0, index_type())));
520524
output.op1()=exc_symbol.symbol_expr();
521525
output.add_source_location()=function.location;
522-
523-
init_code.add(std::move(output));
526+
return output;
524527
}
525528

526529
main_function_resultt get_main_symbol(
@@ -580,40 +583,6 @@ main_function_resultt get_main_symbol(
580583
}
581584
}
582585

583-
/// Given the \p symbol_table and the \p main_class to test, this function
584-
/// generates a new function __CPROVER__start that calls the method under tests.
585-
///
586-
/// If __CPROVER__start is already in the `symbol_table`, it silently returns.
587-
/// Otherwise it finds the method under test using `get_main_symbol` and
588-
/// constructs a body for __CPROVER__start which does as follows:
589-
///
590-
/// 1. Allocates and initializes the parameters of the method under test.
591-
/// 2. Call it and save its return variable in the variable 'return'.
592-
/// 3. Declare variable 'return' as an output variable (codet with id
593-
/// ID_output), together with other objects possibly altered by the execution
594-
/// the method under test (in `java_record_outputs`)
595-
///
596-
/// When \p assume_init_pointers_not_null is false, the generated parameter
597-
/// initialization code will non-deterministically set input parameters to
598-
/// either null or a stack-allocated object. Observe that the null/non-null
599-
/// setting only applies to the parameter itself, and is not propagated to other
600-
/// pointers that it might be necessary to initialize in the object tree rooted
601-
/// at the parameter.
602-
/// Parameter \p max_nondet_array_length provides the maximum length for an
603-
/// array used as part of the input to the method under test, and
604-
/// \p max_nondet_tree_depth defines the maximum depth of the object tree
605-
/// created for such inputs. This maximum depth is used **in conjunction** with
606-
/// the so-called "recursive type set" (see field `recursive_set` in class
607-
/// java_object_factoryt) to bound the depth of the object tree for the
608-
/// parameter. Only when
609-
/// - the depth of the tree is >= max_nondet_tree_depth **AND**
610-
/// - the type of the object under initialization is already found in the
611-
/// recursive set
612-
/// then that object is not initalized and the reference pointing to it is
613-
/// (deterministically) set to null. This is a source of underapproximation in
614-
/// our approach to test generation, and should perhaps be fixed in the future.
615-
///
616-
/// \return true if error occurred on entry point search
617586
bool java_entry_point(
618587
symbol_table_baset &symbol_table,
619588
const irep_idt &main_class,
@@ -622,7 +591,8 @@ bool java_entry_point(
622591
bool assert_uncaught_exceptions,
623592
const java_object_factory_parameterst &object_factory_parameters,
624593
const select_pointer_typet &pointer_type_selector,
625-
bool string_refinement_enabled)
594+
bool string_refinement_enabled,
595+
const build_argumentst &build_arguments)
626596
{
627597
// check if the entry point is already there
628598
if(symbol_table.symbols.find(goto_functionst::entry_point())!=
@@ -653,31 +623,20 @@ bool java_entry_point(
653623
symbol,
654624
symbol_table,
655625
message_handler,
656-
assume_init_pointers_not_null,
657626
assert_uncaught_exceptions,
658627
object_factory_parameters,
659-
pointer_type_selector);
628+
pointer_type_selector,
629+
build_arguments);
660630
}
661631

662-
/// Generate a _start function for a specific function. See
663-
/// java_entry_point for more details.
664-
/// \param symbol: The symbol representing the function to call
665-
/// \param symbol_table: Global symbol table
666-
/// \param message_handler: Where to write output to
667-
/// \param assume_init_pointers_not_null: When creating pointers, assume they
668-
/// always take a non-null value.
669-
/// \param assert_uncaught_exceptions: Add an uncaught-exception check
670-
/// \param object_factory_parameters: Parameters for creation of arguments
671-
/// \param pointer_type_selector: Logic for substituting types of pointers
672-
/// \return true if error occurred on entry point search, false otherwise
673632
bool generate_java_start_function(
674633
const symbolt &symbol,
675634
symbol_table_baset &symbol_table,
676635
message_handlert &message_handler,
677-
bool assume_init_pointers_not_null,
678636
bool assert_uncaught_exceptions,
679637
const java_object_factory_parameterst &object_factory_parameters,
680-
const select_pointer_typet &pointer_type_selector)
638+
const select_pointer_typet &pointer_type_selector,
639+
const build_argumentst &build_arguments)
681640
{
682641
messaget message(message_handler);
683642
code_blockt init_code;
@@ -744,15 +703,10 @@ bool generate_java_start_function(
744703

745704
// create code that allocates the objects used as test arguments and
746705
// non-deterministically initializes them
747-
exprt::operandst main_arguments=
748-
java_build_arguments(
749-
symbol,
750-
init_code,
751-
symbol_table,
752-
assume_init_pointers_not_null,
753-
object_factory_parameters,
754-
pointer_type_selector);
755-
call_main.arguments()=main_arguments;
706+
const std::pair<code_blockt, std::vector<exprt>> main_arguments =
707+
build_arguments(symbol, symbol_table);
708+
init_code.append(main_arguments.first);
709+
call_main.arguments() = main_arguments.second;
756710

757711
// Create target labels for the toplevel exception handler:
758712
code_labelt toplevel_catch("toplevel_catch", code_skipt());
@@ -791,8 +745,9 @@ bool generate_java_start_function(
791745
// Converge normal and exceptional return:
792746
init_code.add(std::move(after_catch));
793747

794-
// declare certain (which?) variables as test outputs
795-
java_record_outputs(symbol, main_arguments, init_code, symbol_table);
748+
// Mark return value, pointer type parameters and the exception as outputs.
749+
init_code.append(
750+
java_record_outputs(symbol, main_arguments.second, symbol_table));
796751

797752
// add uncaught-exception check if requested
798753
if(assert_uncaught_exceptions)

0 commit comments

Comments
 (0)