@@ -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;
98104void 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