@@ -50,8 +50,6 @@ void shadow_memoryt::initialize_shadow_memory(
50
50
else
51
51
{
52
52
exprt init_expr = field_pair.second ;
53
- if (init_expr.id () == ID_typecast)
54
- init_expr = to_typecast_expr (field_pair.second ).op ();
55
53
const auto init_value =
56
54
expr_initializer (type, expr.source_location (), ns, init_expr);
57
55
CHECK_RETURN (init_value.has_value ());
@@ -95,12 +93,151 @@ void shadow_memoryt::symex_set_field(
95
93
// To be implemented
96
94
}
97
95
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;
98
104
void shadow_memoryt::symex_get_field (
99
105
goto_symex_statet &state,
100
106
const exprt &lhs,
101
107
const exprt::operandst &arguments)
102
108
{
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
+ }
104
241
}
105
242
106
243
// TODO: the following 4 functions (`symex_field_static_init`,
0 commit comments