@@ -18,7 +18,7 @@ Author: Peter Schrammel
1818#include < util/format_expr.h>
1919#include < util/invariant.h>
2020#include < util/namespace.h>
21- #include < util/pointer_expr .h>
21+ #include < util/pointer_offset_size .h>
2222#include < util/ssa_expr.h>
2323#include < util/std_expr.h>
2424
@@ -54,6 +54,16 @@ static void remove_array_type_l2(typet &type)
5454 size.remove_level_2 ();
5555}
5656
57+ exprt deref_expr (const exprt &expr)
58+ {
59+ if (expr.id () == ID_address_of)
60+ {
61+ return to_address_of_expr (expr).object ();
62+ }
63+
64+ return dereference_exprt (expr);
65+ }
66+
5767void clean_pointer_expr (exprt &expr, const typet &type)
5868{
5969 if (
@@ -81,6 +91,21 @@ void clean_pointer_expr(exprt &expr, const typet &type)
8191 POSTCONDITION (expr.type ().id () == ID_pointer);
8292}
8393
94+ void log_set_field (
95+ const namespacet &ns,
96+ const messaget &log,
97+ const irep_idt &field_name,
98+ const exprt &expr,
99+ const exprt &value)
100+ {
101+ log.conditional_output (
102+ log.debug (), [field_name, ns, expr, value](messaget::mstreamt &mstream) {
103+ mstream << " Shadow memory: set_field: " << id2string (field_name)
104+ << " for " << format (expr) << " to " << format (value)
105+ << messaget::eom;
106+ });
107+ }
108+
84109void log_get_field (
85110 const namespacet &ns,
86111 const messaget &log,
@@ -828,3 +853,239 @@ std::vector<std::pair<exprt, exprt>> get_shadow_dereference_candidates(
828853 }
829854 return result;
830855}
856+
857+ // TODO: doxygen?
858+ // Unfortunately.
859+ static object_descriptor_exprt
860+ normalize (const object_descriptor_exprt &expr, const namespacet &ns)
861+ {
862+ if (expr.object ().id () == ID_symbol)
863+ {
864+ return expr;
865+ }
866+ if (expr.offset ().id () == ID_unknown)
867+ {
868+ return expr;
869+ }
870+
871+ object_descriptor_exprt result = expr;
872+ mp_integer offset =
873+ numeric_cast_v<mp_integer>(to_constant_expr (expr.offset ()));
874+ exprt object = expr.object ();
875+
876+ while (true )
877+ {
878+ if (object.id () == ID_index)
879+ {
880+ const index_exprt &index_expr = to_index_expr (object);
881+ mp_integer index =
882+ numeric_cast_v<mp_integer>(to_constant_expr (index_expr.index ()));
883+
884+ offset += *pointer_offset_size (index_expr.type (), ns) * index;
885+ object = index_expr.array ();
886+ }
887+ else if (object.id () == ID_member)
888+ {
889+ const member_exprt &member_expr = to_member_expr (object);
890+ const struct_typet &struct_type =
891+ to_struct_type (ns.follow (member_expr.struct_op ().type ()));
892+ offset +=
893+ *member_offset (struct_type, member_expr.get_component_name (), ns);
894+ object = member_expr.struct_op ();
895+ }
896+ else
897+ {
898+ break ;
899+ }
900+ }
901+ result.object () = object;
902+ result.offset () = from_integer (offset, expr.offset ().type ());
903+ return result;
904+ }
905+
906+ bool set_field_check_null (
907+ const namespacet &ns,
908+ const messaget &log,
909+ const std::vector<exprt> &value_set,
910+ const exprt &expr)
911+ {
912+ const null_pointer_exprt null_pointer (to_pointer_type (expr.type ()));
913+ if (value_set.size () == 1 && contains_null_or_invalid (value_set, null_pointer))
914+ {
915+ // TODO: duplicated in log_value_set_match
916+ #ifdef DEBUG_SM
917+ log.conditional_output (
918+ log.debug (), [ns, null_pointer, expr](messaget::mstreamt &mstream) {
919+ mstream << " Shadow memory: value set match: " << format (null_pointer)
920+ << " <-- " << format (expr) << messaget::eom;
921+ mstream << " Shadow memory: ignoring set field on NULL object"
922+ << messaget::eom;
923+ });
924+ #endif
925+ return true ;
926+ }
927+ return false ;
928+ }
929+
930+ // / Used for set_field and shadow memory copy
931+ static std::vector<std::pair<exprt, exprt>>
932+ get_shadow_memory_for_matched_object (
933+ const exprt &expr,
934+ const exprt &matched_object,
935+ const std::vector<shadow_memory_statet::shadowed_addresst> &addresses,
936+ const namespacet &ns,
937+ const messaget &log,
938+ bool &exact_match)
939+ {
940+ std::vector<std::pair<exprt, exprt>> result;
941+ for (const auto &shadowed_address : addresses)
942+ {
943+ log_try_shadow_address (ns, log, shadowed_address);
944+
945+ if (!are_types_compatible (expr.type (), shadowed_address.address .type ()))
946+ {
947+ #ifdef DEBUG_SM
948+ log.debug () << " Shadow memory: incompatible types "
949+ << from_type (ns, " " , expr.type ()) << " , "
950+ << from_type (ns, " " , shadowed_address.address .type ())
951+ << messaget::eom;
952+ #endif
953+ continue ;
954+ }
955+
956+ object_descriptor_exprt matched_base_descriptor =
957+ normalize (to_object_descriptor_expr (matched_object), ns);
958+
959+ value_set_dereferencet::valuet dereference =
960+ value_set_dereferencet::build_reference_to (
961+ matched_base_descriptor, expr, ns);
962+
963+ exprt matched_base_address =
964+ address_of_exprt (matched_base_descriptor.object ());
965+ clean_string_constant (to_address_of_expr (matched_base_address).op ());
966+
967+ // NULL has already been handled in the caller; skip.
968+ if (matched_base_descriptor.object ().id () == ID_null_object)
969+ {
970+ continue ;
971+ }
972+ const value_set_dereferencet::valuet shadow_dereference =
973+ get_shadow_dereference (
974+ shadowed_address.shadow , matched_base_descriptor, expr, ns, log);
975+ log_value_set_match (
976+ ns,
977+ log,
978+ shadowed_address,
979+ matched_base_address,
980+ dereference,
981+ expr,
982+ shadow_dereference);
983+
984+ const exprt base_cond = get_matched_base_cond (
985+ shadowed_address.address , matched_base_address, ns, log);
986+ log_cond (ns, log, " base_cond" , base_cond);
987+ if (base_cond.is_false ())
988+ {
989+ continue ;
990+ }
991+
992+ const exprt expr_cond =
993+ get_matched_expr_cond (dereference.pointer , expr, ns, log);
994+ if (expr_cond.is_false ())
995+ {
996+ continue ;
997+ }
998+
999+ if (base_cond.is_true () && expr_cond.is_true ())
1000+ {
1001+ #ifdef DEBUG_SM
1002+ log.debug () << " exact match" << messaget::eom;
1003+ #endif
1004+ exact_match = true ;
1005+ result.clear ();
1006+ result.push_back ({base_cond, shadow_dereference.pointer });
1007+ break ;
1008+ }
1009+
1010+ if (base_cond.is_true ())
1011+ {
1012+ // No point looking at further shadow addresses
1013+ // as only one of them can match.
1014+ #ifdef DEBUG_SM
1015+ log.debug () << " base match" << messaget::eom;
1016+ #endif
1017+ result.clear ();
1018+ result.emplace_back (expr_cond, shadow_dereference.pointer );
1019+ break ;
1020+ }
1021+ else
1022+ {
1023+ #ifdef DEBUG_SM
1024+ log.debug () << " conditional match" << messaget::eom;
1025+ #endif
1026+ result.emplace_back (
1027+ and_exprt (base_cond, expr_cond), shadow_dereference.pointer );
1028+ }
1029+ }
1030+ return result;
1031+ }
1032+
1033+ optionalt<exprt> get_shadow_memory (
1034+ const exprt &expr,
1035+ const std::vector<exprt> &value_set,
1036+ const std::vector<shadow_memory_statet::shadowed_addresst> &addresses,
1037+ const namespacet &ns,
1038+ const messaget &log,
1039+ size_t &mux_size)
1040+ {
1041+ std::vector<std::pair<exprt, exprt>> conds_values;
1042+ for (const auto &matched_object : value_set)
1043+ {
1044+ if (matched_object.id () != ID_object_descriptor)
1045+ {
1046+ log.warning () << " Shadow memory: value set contains unknown for "
1047+ << format (expr) << messaget::eom;
1048+ continue ;
1049+ }
1050+ if (
1051+ to_object_descriptor_expr (matched_object).root_object ().id () ==
1052+ ID_integer_address)
1053+ {
1054+ log.warning () << " Shadow memory: value set contains integer_address for "
1055+ << format (expr) << messaget::eom;
1056+ continue ;
1057+ }
1058+ if (matched_object.type ().get_bool (ID_C_is_failed_symbol))
1059+ {
1060+ log.warning () << " Shadow memory: value set contains failed symbol for "
1061+ << format (expr) << messaget::eom;
1062+ continue ;
1063+ }
1064+
1065+ bool exact_match = false ;
1066+ auto per_value_set_conds_values = get_shadow_memory_for_matched_object (
1067+ expr, matched_object, addresses, ns, log, exact_match);
1068+
1069+ if (!per_value_set_conds_values.empty ())
1070+ {
1071+ if (exact_match)
1072+ {
1073+ conds_values.clear ();
1074+ }
1075+ conds_values.insert (
1076+ conds_values.begin (),
1077+ per_value_set_conds_values.begin (),
1078+ per_value_set_conds_values.end ());
1079+ mux_size += conds_values.size () - 1 ;
1080+ if (exact_match)
1081+ {
1082+ break ;
1083+ }
1084+ }
1085+ }
1086+ if (!conds_values.empty ())
1087+ {
1088+ return build_if_else_expr (conds_values);
1089+ }
1090+ return {};
1091+ }
0 commit comments