Skip to content

Commit 20164f5

Browse files
Merge pull request diffblue#5106 from romainbrenguier/refactor/assign-from-json
[TG-9450] Allocate array with right length when "@nondetLength" not used in Json
2 parents 2082719 + 5829c8a commit 20164f5

File tree

3 files changed

+507
-47
lines changed

3 files changed

+507
-47
lines changed

jbmc/src/java_bytecode/assignments_from_json.cpp

Lines changed: 94 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ has_enum_type(const exprt &expr, const symbol_table_baset &symbol_table)
9999
/// \param declaring_class_type: type of the class where \p expr is declared.
100100
/// \return `true` if \p expr has an enum type and is declared within the
101101
/// definition of that same type, `false` otherwise.
102-
bool is_enum_with_type_equal_to_declaring_type(
102+
static bool is_enum_with_type_equal_to_declaring_type(
103103
const exprt &expr,
104104
const symbol_table_baset &symbol_table,
105105
const java_class_typet &declaring_class_type)
@@ -188,9 +188,8 @@ static bool has_nondet_length(const jsont &json)
188188
if(!json.is_object())
189189
return false;
190190
const auto &json_object = to_json_object(json);
191-
if(json_object.find("@nondetLength") != json_object.end())
192-
return (json["@nondetLength"].is_true());
193-
return false;
191+
auto nondet_it = json_object.find("@nondetLength");
192+
return nondet_it != json_object.end() && nondet_it->second.is_true();
194193
}
195194

196195
/// For typed versions of primitive, string or array types, looks up their
@@ -438,63 +437,82 @@ static void allocate_array(
438437
info.block.add(assign);
439438
}
440439

440+
/// Declare a non-deterministic length expression
441+
/// \param[out] allocate: allocation functor
442+
/// \param[out] code: code block to which code will get appended
443+
/// \param loc: location for the created code
444+
/// \return the length expression that has been non-deterministically created
445+
static symbol_exprt nondet_length(
446+
allocate_objectst &allocate,
447+
code_blockt &code,
448+
source_locationt loc)
449+
{
450+
const symbol_exprt length_expr = allocate.allocate_automatic_local_object(
451+
java_int_type(), "user_specified_array_length");
452+
code.add(code_assignt{
453+
length_expr, side_effect_expr_nondett{java_int_type(), std::move(loc)}});
454+
code.add(code_assumet{binary_predicate_exprt{
455+
length_expr, ID_ge, from_integer(0, java_int_type())}});
456+
return length_expr;
457+
}
458+
441459
/// One of the cases in the recursive algorithm: the case where \p expr
442-
/// represents an array.
443-
/// The length of the array is given by a symbol: \p given_length_expr if it is
444-
/// specified (this will be the case when there are two or more reference-equal
445-
/// arrays), or a fresh symbol otherwise.
446-
/// If \p given_length_expr is specified, we assume that an array with this
447-
/// symbol as its length has already been allocated and that \p expr has been
448-
/// assigned to it.
449-
/// Either way, the length symbol stores a nondet integer, and we add
450-
/// constraints on this: if "nondetLength" is specified in \p json, then the
451-
/// number of elements specified in \p json should be the minimum length of the
452-
/// array. Otherwise the number of elements should be the exact length of the
453-
/// array.
460+
/// represents an array which is not flagged with `@nondetLength`.
461+
/// The length of the array is given by symbol \p given_length_expr.
462+
/// We assume that an array with this symbol as its length has already been
463+
/// allocated and that \p expr has been assigned to it.
464+
/// We constraint the length of the array to be the number of elements, which
465+
/// is known and constant.
454466
/// For the assignment of the array elements, see
455467
/// \ref assign_array_data_component_from_json.
456468
/// For the overall algorithm, see \ref assign_from_json_rec.
457-
static void assign_array_from_json(
469+
static void assign_det_length_array_from_json(
458470
const exprt &expr,
459471
const jsont &json,
460-
const optionalt<symbol_exprt> &given_length_expr,
472+
const exprt &given_length_expr,
461473
const optionalt<std::string> &type_from_array,
462474
object_creation_infot &info)
463475
{
464476
PRECONDITION(is_java_array_type(expr.type()));
465477
const auto &element_type =
466478
java_array_element_type(to_struct_tag_type(expr.type().subtype()));
479+
const json_arrayt json_array = get_untyped_array(json, element_type);
480+
const auto number_of_elements =
481+
from_integer(json_array.size(), java_int_type());
482+
info.block.add(
483+
code_assumet{equal_exprt{given_length_expr, number_of_elements}});
484+
assign_array_data_component_from_json(expr, json, type_from_array, info);
485+
}
467486

468-
exprt length_expr;
469-
if(given_length_expr)
470-
length_expr = *given_length_expr;
471-
else
472-
{
473-
length_expr = info.allocate_objects.allocate_automatic_local_object(
474-
java_int_type(), "user_specified_array_length");
475-
info.block.add(code_assignt{
476-
length_expr, side_effect_expr_nondett{java_int_type(), info.loc}});
477-
info.block.add(code_assumet{binary_predicate_exprt{
478-
length_expr, ID_ge, from_integer(0, java_int_type())}});
479-
allocate_array(expr, length_expr, info);
480-
}
487+
/// One of the cases in the recursive algorithm: the case where \p expr
488+
/// represents an array which is flagged with @nondetLength.
489+
/// The length of the array is given by symbol \p given_length_expr.
490+
/// We assume that an array with this symbol as its length has already been
491+
/// allocated and that \p expr has been assigned to it.
492+
/// We constrain the length of the array to be greater or equal to the number
493+
/// of elements specified in \p json.
494+
/// For the assignment of the array elements, see
495+
/// \ref assign_array_data_component_from_json.
496+
/// For the overall algorithm, see \ref assign_from_json_rec.
497+
static void assign_nondet_length_array_from_json(
498+
const exprt &expr,
499+
const jsont &json,
500+
const exprt &given_length_expr,
501+
const optionalt<std::string> &type_from_array,
502+
object_creation_infot &info)
503+
{
504+
PRECONDITION(is_java_array_type(expr.type()));
505+
const auto &element_type =
506+
java_array_element_type(to_struct_tag_type(expr.type().subtype()));
481507
const json_arrayt json_array = get_untyped_array(json, element_type);
482508
const auto number_of_elements =
483509
from_integer(json_array.size(), java_int_type());
484-
info.block.add(code_assumet{
485-
binary_predicate_exprt{length_expr, ID_ge, number_of_elements}});
486-
if(has_nondet_length(json))
487-
{
488-
info.block.add(code_assumet{binary_predicate_exprt{
489-
length_expr,
510+
info.block.add(code_assumet{and_exprt{
511+
binary_predicate_exprt{given_length_expr, ID_ge, number_of_elements},
512+
binary_predicate_exprt{
513+
given_length_expr,
490514
ID_le,
491-
from_integer(info.max_user_array_length, java_int_type())}});
492-
}
493-
else
494-
{
495-
info.block.add(code_assumet{
496-
binary_predicate_exprt{length_expr, ID_le, number_of_elements}});
497-
}
515+
from_integer(info.max_user_array_length, java_int_type())}}});
498516
assign_array_data_component_from_json(expr, json, type_from_array, info);
499517
}
500518

@@ -771,8 +789,18 @@ static void assign_reference_from_json(
771789
{
772790
if(is_java_array_type(expr.type()))
773791
{
774-
assign_array_from_json(
775-
reference.expr, json, reference.array_length, type_from_array, info);
792+
INVARIANT(
793+
reference.array_length, "an array reference should store its length");
794+
if(has_nondet_length(json))
795+
{
796+
assign_nondet_length_array_from_json(
797+
reference.expr, json, *reference.array_length, type_from_array, info);
798+
}
799+
else
800+
{
801+
assign_det_length_array_from_json(
802+
reference.expr, json, *reference.array_length, type_from_array, info);
803+
}
776804
}
777805
else
778806
assign_struct_from_json(dereference_exprt(reference.expr), json, info);
@@ -810,7 +838,26 @@ void assign_from_json_rec(
810838
assign_reference_from_json(expr, json, type_from_array, info);
811839
}
812840
else if(is_java_array_type(expr.type()))
813-
assign_array_from_json(expr, json, {}, type_from_array, info);
841+
{
842+
if(has_nondet_length(json))
843+
{
844+
const exprt length =
845+
nondet_length(info.allocate_objects, info.block, info.loc);
846+
allocate_array(expr, length, info);
847+
assign_nondet_length_array_from_json(
848+
expr, json, length, type_from_array, info);
849+
}
850+
else
851+
{
852+
PRECONDITION(is_java_array_type(expr.type()));
853+
const auto &element_type =
854+
java_array_element_type(to_struct_tag_type(expr.type().subtype()));
855+
const std::size_t length = get_untyped_array(json, element_type).size();
856+
allocate_array(expr, from_integer(length, java_int_type()), info);
857+
assign_array_data_component_from_json(
858+
expr, json, type_from_array, info);
859+
}
860+
}
814861
else if(
815862
const auto runtime_type =
816863
::runtime_type(json, type_from_array, info.symbol_table))

jbmc/unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ SRC += java_bytecode/ci_lazy_methods/lazy_load_lambdas.cpp \
4848
java_bytecode/java_object_factory/gen_nondet_string_init.cpp \
4949
java_bytecode/java_object_factory/struct_tag_types.cpp \
5050
java_bytecode/java_replace_nondet/replace_nondet.cpp \
51+
java_bytecode/java_static_initializers/assignments_from_json.cpp \
5152
java_bytecode/java_static_initializers/java_static_initializers.cpp \
5253
java_bytecode/java_string_library_preprocess/convert_exprt_to_string_exprt.cpp \
5354
java_bytecode/java_trace_validation/java_trace_validation.cpp \

0 commit comments

Comments
 (0)