Skip to content

Commit f40203a

Browse files
author
Enrico Steffinlongo
authored
Merge pull request #7840 from esteffin/esteffin/shadow-memory-get-field-op
Add shadow memory get_field function
2 parents 1e8a703 + 74f6669 commit f40203a

File tree

5 files changed

+991
-6
lines changed

5 files changed

+991
-6
lines changed

regression/cbmc-shadow-memory/custom-init1/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FUTURE
1+
CORE
22
main.c
33

44
^EXIT=0$

regression/cbmc-shadow-memory/void-ptr-param-get1/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FUTURE
1+
CORE
22
main.c
33

44
^EXIT=6$

src/goto-symex/shadow_memory.cpp

+140-3
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ void shadow_memoryt::initialize_shadow_memory(
5050
else
5151
{
5252
exprt init_expr = field_pair.second;
53-
if(init_expr.id() == ID_typecast)
54-
init_expr = to_typecast_expr(field_pair.second).op();
5553
const auto init_value =
5654
expr_initializer(type, expr.source_location(), ns, init_expr);
5755
CHECK_RETURN(init_value.has_value());
@@ -95,12 +93,151 @@ void shadow_memoryt::symex_set_field(
9593
// To be implemented
9694
}
9795

96+
// Function synopsis
97+
// value_set = get_value_set(expr)
98+
// foreach object in value_set:
99+
// if(object invalid) continue;
100+
// get_field(&exact_match)
101+
// if(exact_match)
102+
// return;
103+
// return;
98104
void shadow_memoryt::symex_get_field(
99105
goto_symex_statet &state,
100106
const exprt &lhs,
101107
const exprt::operandst &arguments)
102108
{
103-
// To be implemented
109+
INVARIANT(
110+
arguments.size() == 2, CPROVER_PREFIX "get_field requires 2 arguments");
111+
irep_idt field_name = extract_field_name(arguments[1]);
112+
113+
exprt expr = arguments[0];
114+
typet expr_type = expr.type();
115+
DATA_INVARIANT(
116+
expr_type.id() == ID_pointer,
117+
"shadow memory requires a pointer expression");
118+
log_get_field(ns, log, field_name, expr);
119+
120+
INVARIANT(
121+
state.shadow_memory.address_fields.count(field_name) == 1,
122+
id2string(field_name) + " should exist");
123+
const auto &addresses = state.shadow_memory.address_fields.at(field_name);
124+
125+
// Return null (invalid object) instead of auto-object or invalid-object.
126+
// This will "polish" expr from invalid and auto-obj
127+
replace_invalid_object_by_null(expr);
128+
129+
std::vector<exprt> value_set = state.value_set.get_value_set(expr, ns);
130+
log_value_set(ns, log, value_set);
131+
132+
std::vector<std::pair<exprt, exprt>> rhs_conds_values;
133+
const null_pointer_exprt null_pointer(to_pointer_type(expr.type()));
134+
// Used to give a default value for invalid pointers and other usages
135+
const exprt &field_init_expr = get_field_init_expr(field_name, state);
136+
137+
if(contains_null_or_invalid(value_set, null_pointer))
138+
{
139+
log_value_set_match(ns, log, null_pointer, expr);
140+
// If we have an invalid pointer, then return the default value of the
141+
// shadow memory as dereferencing it would fail
142+
rhs_conds_values.emplace_back(
143+
true_exprt(),
144+
typecast_exprt::conditional_cast(field_init_expr, lhs.type()));
145+
}
146+
147+
for(const auto &matched_object : value_set)
148+
{
149+
// Ignore "unknown"
150+
if(matched_object.id() != ID_object_descriptor)
151+
{
152+
log.warning() << "Shadow memory: value set contains unknown for "
153+
<< format(expr) << messaget::eom;
154+
continue;
155+
}
156+
// Ignore "integer_address"
157+
if(
158+
to_object_descriptor_expr(matched_object).root_object().id() ==
159+
ID_integer_address)
160+
{
161+
log.warning() << "Shadow memory: value set contains integer_address for "
162+
<< format(expr) << messaget::eom;
163+
continue;
164+
}
165+
// Ignore "ID_C_is_failed_symbol" (another incarnation of invalid pointer)
166+
// TODO: check if this is obsolete (or removed by
167+
// replace_invalid_object_by_null) or add default value
168+
if(matched_object.type().get_bool(ID_C_is_failed_symbol))
169+
{
170+
log.warning() << "Shadow memory: value set contains failed symbol for "
171+
<< format(expr) << messaget::eom;
172+
continue;
173+
}
174+
175+
bool exact_match = false;
176+
177+
// List of condition ==> value (read condition implies values)
178+
auto per_matched_object_conds_values = get_shadow_dereference_candidates(
179+
ns,
180+
log,
181+
matched_object,
182+
addresses,
183+
field_init_expr.type(),
184+
expr,
185+
lhs.type(),
186+
exact_match);
187+
188+
// If we have an exact match we discard all the previous conditions and
189+
// create an assignment. Then we'll break
190+
if(exact_match)
191+
{
192+
rhs_conds_values.clear();
193+
}
194+
// Process this match (exact will contain only one set of conditions).
195+
rhs_conds_values.insert(
196+
rhs_conds_values.end(),
197+
per_matched_object_conds_values.begin(),
198+
per_matched_object_conds_values.end());
199+
if(exact_match)
200+
{
201+
break;
202+
}
203+
}
204+
205+
// If we have at least a condition ==> value
206+
if(!rhs_conds_values.empty())
207+
{
208+
// Build the rhs expression from the shadow memory (big switch for all
209+
// condition ==> value)
210+
exprt rhs = typecast_exprt::conditional_cast(
211+
build_if_else_expr(rhs_conds_values), lhs.type());
212+
const size_t mux_size = rhs_conds_values.size() - 1;
213+
// Don't debug if the switch is too big
214+
if(mux_size >= 10)
215+
{
216+
log.warning() << "Shadow memory: mux size get_field: " << mux_size
217+
<< messaget::eom;
218+
}
219+
else
220+
{
221+
log.debug() << "Shadow memory: mux size get_field: " << mux_size
222+
<< messaget::eom;
223+
}
224+
#ifdef DEBUG_SM
225+
log.debug() << "Shadow memory: RHS: " << format(rhs) << messaget::eom;
226+
#endif
227+
// TODO: create the assignment of __CPROVER_shadow_memory_get_field
228+
symex_assign(state, lhs, typecast_exprt::conditional_cast(rhs, lhs.type()));
229+
}
230+
else
231+
{
232+
// We don't have any condition ==> value for the pointer, so we fall-back to
233+
// the initialization value of the shadow-memory.
234+
log.warning() << "Shadow memory: cannot get_field for " << format(expr)
235+
<< messaget::eom;
236+
symex_assign(
237+
state,
238+
lhs,
239+
typecast_exprt::conditional_cast(field_init_expr, lhs.type()));
240+
}
104241
}
105242

106243
// TODO: the following 4 functions (`symex_field_static_init`,

0 commit comments

Comments
 (0)