Skip to content

Commit ff19cc6

Browse files
NlightNFotisEnrico Steffinlongo
authored and
Enrico Steffinlongo
committed
Add implementation of symex_set_field.
1 parent f40203a commit ff19cc6

File tree

3 files changed

+379
-1
lines changed

3 files changed

+379
-1
lines changed

src/goto-symex/shadow_memory.cpp

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ Author: Peter Schrammel
1111

1212
#include "shadow_memory.h"
1313

14+
#include <util/arith_tools.h>
1415
#include <util/bitvector_types.h>
1516
#include <util/expr_initializer.h>
1617
#include <util/format_expr.h>
1718
#include <util/format_type.h>
1819
#include <util/fresh_symbol.h>
1920
#include <util/pointer_expr.h>
21+
#include <util/pointer_offset_size.h>
2022
#include <util/prefix.h>
2123
#include <util/string_constant.h>
2224

@@ -90,7 +92,91 @@ void shadow_memoryt::symex_set_field(
9092
goto_symex_statet &state,
9193
const exprt::operandst &arguments)
9294
{
93-
// To be implemented
95+
// parse set_field call
96+
INVARIANT(
97+
arguments.size() == 3, CPROVER_PREFIX "set_field requires 3 arguments");
98+
irep_idt field_name = extract_field_name(arguments[1]);
99+
100+
exprt expr = arguments[0];
101+
typet expr_type = expr.type();
102+
DATA_INVARIANT_WITH_DIAGNOSTICS(
103+
expr_type.id() == ID_pointer,
104+
"shadow memory requires a pointer expression",
105+
irep_pretty_diagnosticst{expr_type});
106+
107+
exprt value = arguments[2];
108+
log_set_field(ns, log, field_name, expr, value);
109+
INVARIANT(
110+
state.shadow_memory.address_fields.count(field_name) == 1,
111+
id2string(field_name) + " should exist");
112+
const auto &addresses = state.shadow_memory.address_fields.at(field_name);
113+
114+
// get value set
115+
replace_invalid_object_by_null(expr);
116+
#ifdef DEBUG_SM
117+
log_set_field(ns, log, field_name, expr, value);
118+
#endif
119+
std::vector<exprt> value_set = state.value_set.get_value_set(expr, ns);
120+
log_value_set(ns, log, value_set);
121+
if(set_field_check_null(ns, log, value_set, expr))
122+
{
123+
log.warning() << "Shadow memory: cannot set shadow memory of NULL"
124+
<< messaget::eom;
125+
return;
126+
}
127+
128+
// build lhs
129+
const exprt &rhs = value;
130+
size_t mux_size = 0;
131+
optionalt<exprt> maybe_lhs =
132+
get_shadow_memory(expr, value_set, addresses, ns, log, mux_size);
133+
134+
// add to equation
135+
if(maybe_lhs.has_value())
136+
{
137+
if(mux_size >= 10)
138+
{
139+
log.warning() << "Shadow memory: mux size set_field: " << mux_size
140+
<< messaget::eom;
141+
}
142+
else
143+
{
144+
log.debug() << "Shadow memory: mux size set_field: " << mux_size
145+
<< messaget::eom;
146+
}
147+
const exprt lhs = deref_expr(*maybe_lhs);
148+
#ifdef DEBUG_SM
149+
log.debug() << "Shadow memory: LHS: " << format(lhs) << messaget::eom;
150+
#endif
151+
if(lhs.type().id() == ID_empty)
152+
{
153+
std::stringstream s;
154+
s << "Shadow memory: cannot set shadow memory via type void* for "
155+
<< format(expr)
156+
<< ". Insert a cast to the type that you want to access.";
157+
throw invalid_input_exceptiont(s.str());
158+
}
159+
// We replicate the rhs value on each byte of the value that we set.
160+
// This allows the get_field or/max semantics to operate correctly
161+
// on unions.
162+
const auto per_byte_rhs =
163+
expr_initializer(lhs.type(), expr.source_location(), ns, rhs);
164+
CHECK_RETURN(per_byte_rhs.has_value());
165+
166+
#ifdef DEBUG_SM
167+
log.debug() << "Shadow memory: RHS: " << format(per_byte_rhs.value())
168+
<< messaget::eom;
169+
#endif
170+
symex_assign(
171+
state,
172+
lhs,
173+
typecast_exprt::conditional_cast(per_byte_rhs.value(), lhs.type()));
174+
}
175+
else
176+
{
177+
log.warning() << "Shadow memory: cannot set_field for " << format(expr)
178+
<< messaget::eom;
179+
}
94180
}
95181

96182
// Function synopsis

src/goto-symex/shadow_memory_util.cpp

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Author: Peter Schrammel
1919
#include <util/invariant.h>
2020
#include <util/namespace.h>
2121
#include <util/pointer_expr.h>
22+
#include <util/pointer_offset_size.h>
2223
#include <util/ssa_expr.h>
2324
#include <util/std_expr.h>
2425

@@ -54,6 +55,16 @@ static void remove_array_type_l2(typet &type)
5455
size.remove_level_2();
5556
}
5657

58+
exprt deref_expr(const exprt &expr)
59+
{
60+
if(expr.id() == ID_address_of)
61+
{
62+
return to_address_of_expr(expr).object();
63+
}
64+
65+
return dereference_exprt(expr);
66+
}
67+
5768
void clean_pointer_expr(exprt &expr, const typet &type)
5869
{
5970
if(
@@ -81,6 +92,21 @@ void clean_pointer_expr(exprt &expr, const typet &type)
8192
POSTCONDITION(expr.type().id() == ID_pointer);
8293
}
8394

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

0 commit comments

Comments
 (0)