|
31 | 31 |
|
32 | 32 | #include "java_types.h"
|
33 | 33 | #include "java_utils.h"
|
| 34 | +#include "java_string_library_preprocess.h" |
| 35 | +#include "java_root_class.h" |
34 | 36 |
|
35 | 37 | static symbolt &new_tmp_symbol(
|
36 | 38 | symbol_tablet &symbol_table,
|
@@ -460,8 +462,9 @@ class recursion_set_entryt
|
460 | 462 | /// Initialize a recursion-set entry owner operating on a given set.
|
461 | 463 | /// Initially it does not own any set entry.
|
462 | 464 | /// \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) |
465 | 468 | { }
|
466 | 469 |
|
467 | 470 | /// Removes erase_entry (if set) from the controlled set.
|
@@ -494,6 +497,165 @@ class recursion_set_entryt
|
494 | 497 | }
|
495 | 498 | };
|
496 | 499 |
|
| 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 | + |
497 | 659 | /// Initializes a pointer \p expr of type \p pointer_type to a primitive-typed
|
498 | 660 | /// value or an object tree. It allocates child objects as necessary and
|
499 | 661 | /// nondet-initializes their members, or if MUST_UPDATE_IN_PLACE is set,
|
@@ -534,7 +696,6 @@ void java_object_factoryt::gen_nondet_pointer_init(
|
534 | 696 | const update_in_placet &update_in_place)
|
535 | 697 | {
|
536 | 698 | PRECONDITION(expr.type().id()==ID_pointer);
|
537 |
| - |
538 | 699 | const pointer_typet &replacement_pointer_type=
|
539 | 700 | pointer_type_selector.convert_pointer_type(pointer_type, ns);
|
540 | 701 |
|
@@ -623,27 +784,29 @@ void java_object_factoryt::gen_nondet_pointer_init(
|
623 | 784 | // vector of assignments that create a new object (recursively initializes it)
|
624 | 785 | // and asign to `expr` the address of such object
|
625 | 786 | 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 | + } |
633 | 804 |
|
634 | 805 | auto set_null_inst=get_null_assignment(expr, pointer_type);
|
635 | 806 |
|
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"; |
647 | 810 |
|
648 | 811 | // Alternatively, if this is a void* we *must* initialise with null:
|
649 | 812 | // (This can currently happen for some cases of #exception_value)
|
@@ -750,19 +913,6 @@ symbol_exprt java_object_factoryt::gen_nondet_subtype_pointer_init(
|
750 | 913 | return new_symbol.symbol_expr();
|
751 | 914 | }
|
752 | 915 |
|
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 |
| - |
766 | 916 | /// Initializes an object tree rooted at `expr`, allocating child objects as
|
767 | 917 | /// necessary and nondet-initializes their members, or if MUST_UPDATE_IN_PLACE
|
768 | 918 | /// is set, re-initializes already-allocated objects.
|
@@ -866,23 +1016,6 @@ void java_object_factoryt::gen_nondet_struct_init(
|
866 | 1016 | true, // allow_null always true for sub-objects
|
867 | 1017 | depth,
|
868 | 1018 | 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 |
| - } |
886 | 1019 | }
|
887 | 1020 | }
|
888 | 1021 | }
|
|
0 commit comments