|
34 | 34 | #include <util/simplify_expr.h>
|
35 | 35 | #include <util/ssa_expr.h>
|
36 | 36 |
|
| 37 | +#include <deque> |
| 38 | + |
37 | 39 | /// Returns true if \p expr is complicated enough that a local definition (using
|
38 | 40 | /// a let expression) is preferable to repeating it, potentially many times.
|
39 | 41 | /// Of course this is just a heuristic -- currently we allow any expression that
|
@@ -139,7 +141,13 @@ exprt value_set_dereferencet::dereference(
|
139 | 141 | }
|
140 | 142 | }
|
141 | 143 |
|
142 |
| - // type of the object |
| 144 | + return handle_dereference_base_case(pointer, display_points_to_sets); |
| 145 | +} |
| 146 | + |
| 147 | +exprt value_set_dereferencet::handle_dereference_base_case( |
| 148 | + const exprt &pointer, |
| 149 | + bool display_points_to_sets) |
| 150 | +{ // type of the object |
143 | 151 | const typet &type=pointer.type().subtype();
|
144 | 152 |
|
145 | 153 | // collect objects the pointer may point to
|
@@ -167,95 +175,89 @@ exprt value_set_dereferencet::dereference(
|
167 | 175 | compare_against_pointer = fresh_binder.symbol_expr();
|
168 | 176 | }
|
169 | 177 |
|
170 |
| - std::list<valuet> values = |
171 |
| - make_range(retained_values).map([&](const exprt &value) { |
172 |
| - return build_reference_to(value, compare_against_pointer, ns); |
| 178 | + auto values = |
| 179 | + make_range(retained_values) |
| 180 | + .map([&](const exprt &value) { |
| 181 | + return build_reference_to(value, compare_against_pointer, ns); |
| 182 | + }) |
| 183 | + .collect<std::deque<valuet>>(); |
| 184 | + |
| 185 | + const bool may_fail = |
| 186 | + values.empty() || |
| 187 | + std::any_of(values.begin(), values.end(), [](const valuet &value) { |
| 188 | + return value.value.is_nil(); |
173 | 189 | });
|
174 | 190 |
|
175 |
| - // can this fail? |
176 |
| - bool may_fail; |
177 |
| - |
178 |
| - if(values.empty()) |
179 |
| - { |
180 |
| - may_fail=true; |
181 |
| - } |
182 |
| - else |
183 |
| - { |
184 |
| - may_fail=false; |
185 |
| - for(std::list<valuet>::const_iterator |
186 |
| - it=values.begin(); |
187 |
| - it!=values.end(); |
188 |
| - it++) |
189 |
| - if(it->value.is_nil()) |
190 |
| - may_fail=true; |
191 |
| - } |
192 |
| - |
193 | 191 | if(may_fail)
|
194 | 192 | {
|
195 |
| - // first see if we have a "failed object" for this pointer |
196 |
| - |
197 |
| - exprt failure_value; |
198 |
| - |
199 |
| - if( |
200 |
| - const symbolt *failed_symbol = |
201 |
| - dereference_callback.get_or_create_failed_symbol(pointer)) |
202 |
| - { |
203 |
| - // yes! |
204 |
| - failure_value=failed_symbol->symbol_expr(); |
205 |
| - failure_value.set(ID_C_invalid_object, true); |
206 |
| - } |
207 |
| - else |
208 |
| - { |
209 |
| - // else: produce new symbol |
210 |
| - symbolt &symbol = get_fresh_aux_symbol( |
211 |
| - type, |
212 |
| - "symex", |
213 |
| - "invalid_object", |
214 |
| - pointer.source_location(), |
215 |
| - language_mode, |
216 |
| - new_symbol_table); |
217 |
| - |
218 |
| - // make it a lvalue, so we can assign to it |
219 |
| - symbol.is_lvalue=true; |
220 |
| - |
221 |
| - failure_value=symbol.symbol_expr(); |
222 |
| - failure_value.set(ID_C_invalid_object, true); |
223 |
| - } |
224 |
| - |
225 |
| - valuet value; |
226 |
| - value.value=failure_value; |
227 |
| - value.pointer_guard=true_exprt(); |
228 |
| - values.push_front(value); |
| 193 | + values.push_front(get_failure_value(pointer, type)); |
229 | 194 | }
|
230 | 195 |
|
231 | 196 | // now build big case split, but we only do "good" objects
|
232 | 197 |
|
233 |
| - exprt value=nil_exprt(); |
| 198 | + exprt result_value = nil_exprt{}; |
234 | 199 |
|
235 |
| - for(std::list<valuet>::const_iterator |
236 |
| - it=values.begin(); |
237 |
| - it!=values.end(); |
238 |
| - it++) |
| 200 | + for(const auto &value : values) |
239 | 201 | {
|
240 |
| - if(it->value.is_not_nil()) |
| 202 | + if(value.value.is_not_nil()) |
241 | 203 | {
|
242 |
| - if(value.is_nil()) // first? |
243 |
| - value=it->value; |
| 204 | + if(result_value.is_nil()) // first? |
| 205 | + result_value = value.value; |
244 | 206 | else
|
245 |
| - value=if_exprt(it->pointer_guard, it->value, value); |
| 207 | + result_value = if_exprt(value.pointer_guard, value.value, result_value); |
246 | 208 | }
|
247 | 209 | }
|
248 | 210 |
|
249 | 211 | if(compare_against_pointer != pointer)
|
250 |
| - value = let_exprt(to_symbol_expr(compare_against_pointer), pointer, value); |
| 212 | + result_value = |
| 213 | + let_exprt(to_symbol_expr(compare_against_pointer), pointer, result_value); |
251 | 214 |
|
252 | 215 | if(display_points_to_sets)
|
253 | 216 | {
|
254 | 217 | log.status() << value_set_dereference_stats_to_json(
|
255 |
| - pointer, points_to_set, retained_values, value); |
| 218 | + pointer, points_to_set, retained_values, result_value); |
256 | 219 | }
|
257 | 220 |
|
258 |
| - return value; |
| 221 | + return result_value; |
| 222 | +} |
| 223 | + |
| 224 | +value_set_dereferencet::valuet value_set_dereferencet::get_failure_value( |
| 225 | + const exprt &pointer, |
| 226 | + const typet &type) |
| 227 | +{ |
| 228 | + // first see if we have a "failed object" for this pointer |
| 229 | + exprt failure_value; |
| 230 | + |
| 231 | + if( |
| 232 | + const symbolt *failed_symbol = |
| 233 | + dereference_callback.get_or_create_failed_symbol(pointer)) |
| 234 | + { |
| 235 | + // yes! |
| 236 | + failure_value = failed_symbol->symbol_expr(); |
| 237 | + failure_value.set(ID_C_invalid_object, true); |
| 238 | + } |
| 239 | + else |
| 240 | + { |
| 241 | + // else: produce new symbol |
| 242 | + symbolt &symbol = get_fresh_aux_symbol( |
| 243 | + type, |
| 244 | + "symex", |
| 245 | + "invalid_object", |
| 246 | + pointer.source_location(), |
| 247 | + language_mode, |
| 248 | + new_symbol_table); |
| 249 | + |
| 250 | + // make it a lvalue, so we can assign to it |
| 251 | + symbol.is_lvalue = true; |
| 252 | + |
| 253 | + failure_value = symbol.symbol_expr(); |
| 254 | + failure_value.set(ID_C_invalid_object, true); |
| 255 | + } |
| 256 | + |
| 257 | + valuet result{}; |
| 258 | + result.value = failure_value; |
| 259 | + result.pointer_guard = true_exprt(); |
| 260 | + return result; |
259 | 261 | }
|
260 | 262 |
|
261 | 263 | /// Check if the two types have matching number of ID_pointer levels, with
|
|
0 commit comments