Skip to content

Commit 1d112d5

Browse files
Java object factory for nondet strings
This add a new function for initialization of nondeterministic strings. Refactor max_value to use (un)signedbv_typet largest. max_value was assuming 32 bits which may not always be the case.
1 parent 0ae71b0 commit 1d112d5

File tree

2 files changed

+190
-51
lines changed

2 files changed

+190
-51
lines changed

src/java_bytecode/java_object_factory.cpp

+184-51
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Author: Daniel Kroening, [email protected]
3131

3232
#include "java_types.h"
3333
#include "java_utils.h"
34+
#include "java_string_library_preprocess.h"
35+
#include "java_root_class.h"
3436

3537
static symbolt &new_tmp_symbol(
3638
symbol_tablet &symbol_table,
@@ -460,8 +462,9 @@ class recursion_set_entryt
460462
/// Initialize a recursion-set entry owner operating on a given set.
461463
/// Initially it does not own any set entry.
462464
/// \param _recursion_set: set to operate on.
463-
recursion_set_entryt(std::unordered_set<irep_idt, irep_id_hash> &_recursion_set):
464-
recursion_set(_recursion_set)
465+
explicit recursion_set_entryt(
466+
std::unordered_set<irep_idt, irep_id_hash> &_recursion_set)
467+
: recursion_set(_recursion_set)
465468
{ }
466469

467470
/// Removes erase_entry (if set) from the controlled set.
@@ -494,6 +497,165 @@ class recursion_set_entryt
494497
}
495498
};
496499

500+
/// Get max value for an integer type
501+
/// \param type:
502+
/// Type to find maximum value for
503+
/// \return Maximum integer value
504+
static mp_integer max_value(const typet &type)
505+
{
506+
if(type.id() == ID_signedbv)
507+
return to_signedbv_type(type).largest();
508+
else if(type.id() == ID_unsignedbv)
509+
return to_unsignedbv_type(type).largest();
510+
UNREACHABLE;
511+
}
512+
513+
/// Initialize a nondeterministic String structure
514+
/// \param obj: struct to initialize, must have been declared using
515+
/// code of the form:
516+
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
517+
/// struct java.lang.String { struct \@java.lang.Object;
518+
/// int length; char *data; } tmp_object_factory$1;
519+
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
520+
/// \param max_nondet_string_length: maximum length of strings to initialize
521+
/// \param loc: location in the source
522+
/// \param symbol_table: the symbol table
523+
/// \return code for initialization of the strings
524+
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
525+
/// int tmp_object_factory$1;
526+
/// tmp_object_factory$1 = NONDET(int);
527+
/// __CPROVER_assume(tmp_object_factory$1 >= 0);
528+
/// __CPROVER_assume(tmp_object_factory$1 <= max_nondet_string_length);
529+
/// char nondet_infinite_array$2[INFINITY()];
530+
/// nondet_infinite_array$2 = NONDET(char [INFINITY()]);
531+
/// cprover_associate_array_to_pointer_func
532+
/// (nondet_infinite_array$2, &nondet_infinite_array$2[0]);
533+
/// prover_associate_length_to_array_func
534+
/// (nondet_infinite_array$2, tmp_object_factory$1);
535+
/// arg = { .\@java.lang.Object={ .\@class_identifier="java.lang.String",
536+
/// .\@lock=false }, .length=tmp_object_factory$1,
537+
/// .data=nondet_infinite_array$2 };
538+
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
539+
/// Unit tests in `unit/java_bytecode/java_object_factory/` ensure
540+
/// it is the case.
541+
codet initialize_nondet_string_struct(
542+
const exprt &obj,
543+
const std::size_t &max_nondet_string_length,
544+
const source_locationt &loc,
545+
symbol_tablet &symbol_table)
546+
{
547+
PRECONDITION(
548+
java_string_library_preprocesst::implements_java_char_sequence(obj.type()));
549+
550+
const namespacet ns(symbol_table);
551+
code_blockt code;
552+
553+
// `obj` is `*expr`
554+
const struct_typet &struct_type = to_struct_type(ns.follow(obj.type()));
555+
const irep_idt &class_id = struct_type.get_tag();
556+
557+
// @clsid = String and @lock = false:
558+
const symbol_typet jlo_symbol("java::java.lang.Object");
559+
const struct_typet &jlo_type = to_struct_type(ns.follow(jlo_symbol));
560+
struct_exprt jlo_init(jlo_symbol);
561+
java_root_class_init(jlo_init, jlo_type, false, class_id);
562+
563+
struct_exprt struct_expr(obj.type());
564+
struct_expr.copy_to_operands(jlo_init);
565+
566+
// In case the type for string was not added to the symbol table,
567+
// (typically when string refinement is not activated), `struct_type`
568+
// just contains the standard Object field and no length and data fields.
569+
if(struct_type.has_component("length"))
570+
{
571+
// length_expr = nondet(int);
572+
const symbolt length_sym =
573+
new_tmp_symbol(symbol_table, loc, java_int_type());
574+
const symbol_exprt length_expr = length_sym.symbol_expr();
575+
const side_effect_expr_nondett nondet_length(length_expr.type());
576+
code.add(code_declt(length_expr));
577+
code.add(code_assignt(length_expr, nondet_length));
578+
579+
// assume (length_expr >= 0);
580+
code.add(
581+
code_assumet(
582+
binary_relation_exprt(
583+
length_expr, ID_ge, from_integer(0, java_int_type()))));
584+
585+
// assume (length_expr <= max_input_length)
586+
if(max_nondet_string_length <= max_value(length_expr.type()))
587+
{
588+
exprt max_length =
589+
from_integer(max_nondet_string_length, length_expr.type());
590+
code.add(
591+
code_assumet(binary_relation_exprt(length_expr, ID_le, max_length)));
592+
}
593+
594+
// data_expr = nondet(char[INFINITY]) // we use infinity for variable size
595+
exprt data_expr = make_nondet_infinite_char_array(symbol_table, loc, code);
596+
597+
struct_expr.copy_to_operands(length_expr);
598+
599+
const address_of_exprt first_index(
600+
index_exprt(data_expr, from_integer(0, java_int_type())));
601+
struct_expr.copy_to_operands(first_index);
602+
603+
add_pointer_to_array_association(
604+
first_index, data_expr, symbol_table, loc, code);
605+
606+
add_array_to_length_association(
607+
data_expr, length_expr, symbol_table, loc, code);
608+
}
609+
610+
// tmp_object = struct_expr;
611+
code.add(code_assignt(obj, struct_expr));
612+
return code;
613+
}
614+
615+
/// Add code for the initialization of a string using a nondeterministic
616+
/// content and association of its address to the pointer `expr`.
617+
/// \param expr: pointer to be affected
618+
/// \param max_nondet_string_length: maximum length of strings to initialize
619+
/// \param symbol_table: the symbol table
620+
/// \param loc: location in the source
621+
/// \param [out] code: code block in which initialization code is added
622+
/// \return false if code was added, true to signal an error when the given
623+
/// object does not implement CharSequence or does not have data and
624+
/// length fields, in which case it should be initialized another way.
625+
static bool add_nondet_string_pointer_initialization(
626+
const exprt &expr,
627+
const std::size_t &max_nondet_string_length,
628+
symbol_tablet &symbol_table,
629+
const source_locationt &loc,
630+
code_blockt &code)
631+
{
632+
if(
633+
!java_string_library_preprocesst::implements_java_char_sequence_pointer(
634+
expr.type()))
635+
return true;
636+
637+
const namespacet ns(symbol_table);
638+
const dereference_exprt obj(expr, expr.type().subtype());
639+
const struct_typet &struct_type =
640+
to_struct_type(ns.follow(to_symbol_type(obj.type())));
641+
642+
if(!struct_type.has_component("data") || !struct_type.has_component("length"))
643+
return true;
644+
645+
const symbolt tmp_object_sym = new_tmp_symbol(symbol_table, loc, struct_type);
646+
// Note that it is fine to use a tmp_object here as this should only be used
647+
// in __CPROVER_start whose scope covers all the program execution.
648+
const symbol_exprt tmp_object = tmp_object_sym.symbol_expr();
649+
// struct java.lang.String tmp_object;
650+
code.add(code_declt(tmp_object));
651+
code.add(
652+
initialize_nondet_string_struct(
653+
tmp_object, max_nondet_string_length, loc, symbol_table));
654+
// expr = &tmp_object;
655+
code.add(code_assignt(expr, address_of_exprt(tmp_object), loc));
656+
return false;
657+
}
658+
497659
/// Initializes a pointer \p expr of type \p pointer_type to a primitive-typed
498660
/// value or an object tree. It allocates child objects as necessary and
499661
/// nondet-initializes their members, or if MUST_UPDATE_IN_PLACE is set,
@@ -534,7 +696,6 @@ void java_object_factoryt::gen_nondet_pointer_init(
534696
const update_in_placet &update_in_place)
535697
{
536698
PRECONDITION(expr.type().id()==ID_pointer);
537-
538699
const pointer_typet &replacement_pointer_type=
539700
pointer_type_selector.convert_pointer_type(pointer_type, ns);
540701

@@ -623,27 +784,29 @@ void java_object_factoryt::gen_nondet_pointer_init(
623784
// vector of assignments that create a new object (recursively initializes it)
624785
// and asign to `expr` the address of such object
625786
code_blockt non_null_inst;
626-
gen_pointer_target_init(
627-
non_null_inst,
628-
expr,
629-
subtype,
630-
alloc_type,
631-
depth,
632-
update_in_placet::NO_UPDATE_IN_PLACE);
787+
788+
if(
789+
add_nondet_string_pointer_initialization(
790+
expr,
791+
object_factory_parameters.max_nondet_string_length,
792+
symbol_table,
793+
loc,
794+
assignments))
795+
{
796+
gen_pointer_target_init(
797+
non_null_inst,
798+
expr,
799+
subtype,
800+
alloc_type,
801+
depth,
802+
update_in_placet::NO_UPDATE_IN_PLACE);
803+
}
633804

634805
auto set_null_inst=get_null_assignment(expr, pointer_type);
635806

636-
// Determine whether the pointer can be null. In particular:
637-
// - the 'data' of a String should not be null.
638-
// - the pointers inside the java.lang.Class class shall not be null
639-
bool not_null=
640-
!allow_null ||
641-
((class_identifier=="java.lang.String" ||
642-
class_identifier=="java.lang.StringBuilder" ||
643-
class_identifier=="java.lang.StringBuffer" ||
644-
class_identifier=="java.lang.CharSequence") &&
645-
subtype.id()==ID_array) ||
646-
class_identifier=="java.lang.Class";
807+
// Determine whether the pointer can be null. In particular the pointers
808+
// inside the java.lang.Class class shall not be null
809+
const bool not_null = !allow_null || class_identifier == "java.lang.Class";
647810

648811
// Alternatively, if this is a void* we *must* initialise with null:
649812
// (This can currently happen for some cases of #exception_value)
@@ -750,19 +913,6 @@ symbol_exprt java_object_factoryt::gen_nondet_subtype_pointer_init(
750913
return new_symbol.symbol_expr();
751914
}
752915

753-
/// Get max value for an integral type
754-
/// \param type:
755-
/// Type to find maximum value for
756-
/// \return Maximum integral valu
757-
static size_t max_value(const typet& type)
758-
{
759-
if(type.id()==ID_signedbv)
760-
return std::numeric_limits<int32_t>::max();
761-
else if(type.id()==ID_unsignedbv)
762-
return std::numeric_limits<uint32_t>::max();
763-
UNREACHABLE;
764-
}
765-
766916
/// Initializes an object tree rooted at `expr`, allocating child objects as
767917
/// necessary and nondet-initializes their members, or if MUST_UPDATE_IN_PLACE
768918
/// is set, re-initializes already-allocated objects.
@@ -866,23 +1016,6 @@ void java_object_factoryt::gen_nondet_struct_init(
8661016
true, // allow_null always true for sub-objects
8671017
depth,
8681018
substruct_in_place);
869-
870-
if(name=="length")
871-
{
872-
if(class_identifier=="java.lang.String" ||
873-
class_identifier=="java.lang.StringBuffer" ||
874-
class_identifier=="java.lang.StringBuilder")
875-
{
876-
if(object_factory_parameters.max_nondet_string_length <=
877-
max_value(me.type()))
878-
{
879-
exprt max_length=from_integer(
880-
object_factory_parameters.max_nondet_string_length, me.type());
881-
assignments.add(code_assumet(
882-
binary_relation_exprt(me, ID_le, max_length)));
883-
}
884-
}
885-
}
8861019
}
8871020
}
8881021
}

src/java_bytecode/java_object_factory.h

+6
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,10 @@ void allocate_dynamic_object_with_decl(
152152
const source_locationt &loc,
153153
code_blockt &output_code);
154154

155+
codet initialize_nondet_string_struct(
156+
const exprt &obj,
157+
const std::size_t &max_nondet_string_length,
158+
const source_locationt &loc,
159+
symbol_tablet &symbol_table);
160+
155161
#endif // CPROVER_JAVA_BYTECODE_JAVA_OBJECT_FACTORY_H

0 commit comments

Comments
 (0)