CBMC
Loading...
Searching...
No Matches
shadow_memory_util.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Symex Shadow Memory Instrumentation
4
5Author: Peter Schrammel
6
7\*******************************************************************/
8
11
12#include "shadow_memory_util.h"
13
14#include <util/arith_tools.h>
15#include <util/bitvector_expr.h>
16#include <util/byte_operators.h>
17#include <util/c_types.h>
18#include <util/config.h>
19#include <util/format_expr.h>
20#include <util/invariant.h>
21#include <util/namespace.h>
23#include <util/simplify_expr.h>
24#include <util/ssa_expr.h>
25#include <util/std_expr.h>
27
28#include <langapi/language_util.h> // IWYU pragma: keep
31
33 const namespacet &ns,
34 const messaget &log,
35 const irep_idt &field_name,
36 const exprt &expr,
37 const exprt &value)
38{
39#ifdef DEBUG_SHADOW_MEMORY
40 log.conditional_output(
41 log.debug(), [field_name, ns, expr, value](messaget::mstreamt &mstream) {
42 mstream << "Shadow memory: set_field: " << id2string(field_name)
43 << " for " << format(expr) << " to " << format(value)
44 << messaget::eom;
45 });
46#endif
47}
48
50 const namespacet &ns,
51 const messaget &log,
52 const irep_idt &field_name,
53 const exprt &expr)
54{
55#ifdef DEBUG_SHADOW_MEMORY
56 log.conditional_output(
57 log.debug(), [ns, field_name, expr](messaget::mstreamt &mstream) {
58 mstream << "Shadow memory: get_field: " << id2string(field_name)
59 << " for " << format(expr) << messaget::eom;
60 });
61#endif
62}
63
65 const namespacet &ns,
66 const messaget &log,
67 const std::vector<exprt> &value_set)
68{
69#ifdef DEBUG_SHADOW_MEMORY
70 log.conditional_output(
71 log.debug(), [ns, value_set](messaget::mstreamt &mstream) {
72 for(const auto &e : value_set)
73 {
74 mstream << "Shadow memory: value_set: " << format(e) << messaget::eom;
75 }
76 });
77#endif
78}
79
81 const namespacet &ns,
82 const messaget &log,
83 const exprt &address,
84 const exprt &expr)
85{
86 // Leave guards rename to DEBUG_SHADOW_MEMORY
87#ifdef DEBUG_SHADOW_MEMORY
88 log.conditional_output(
89 log.debug(), [ns, address, expr](messaget::mstreamt &mstream) {
90 mstream << "Shadow memory: value_set_match: " << format(address)
91 << " <-- " << format(expr) << messaget::eom;
92 });
93#endif
94}
95
97 const namespacet &ns,
98 const messaget &log,
99 const char *text,
100 const exprt &expr)
101{
102#ifdef DEBUG_SHADOW_MEMORY
103 log.conditional_output(
104 log.debug(), [ns, text, expr](messaget::mstreamt &mstream) {
105 mstream << "Shadow memory: " << text << ": " << format(expr)
106 << messaget::eom;
107 });
108#endif
109}
110
115 const namespacet &ns,
116 const messaget &log,
120 const exprt &expr,
122{
123#ifdef DEBUG_SHADOW_MEMORY
124 log.conditional_output(
125 log.debug(),
126 [ns,
128 expr,
132 mstream << "Shadow memory: value_set_match: " << messaget::eom;
133 mstream << "Shadow memory: base: " << format(shadowed_address.address)
134 << " <-- " << format(matched_base_address) << messaget::eom;
135 mstream << "Shadow memory: cell: " << format(dereference.pointer)
136 << " <-- " << format(expr) << messaget::eom;
137 mstream << "Shadow memory: shadow_ptr: "
138 << format(shadow_dereference.pointer) << messaget::eom;
139 mstream << "Shadow memory: shadow_val: "
140 << format(shadow_dereference.value) << messaget::eom;
141 });
142#endif
143}
144
147 const namespacet &ns,
148 const messaget &log,
150{
151#ifdef DEBUG_SHADOW_MEMORY
152 log.conditional_output(
153 log.debug(), [ns, shadowed_address](messaget::mstreamt &mstream) {
154 mstream << "Shadow memory: trying shadowed address: "
155 << format(shadowed_address.address) << messaget::eom;
156 });
157#endif
158}
159
161static void log_shadow_memory_message(const messaget &log, const char *text)
162{
163#ifdef DEBUG_SHADOW_MEMORY
164 log.debug() << text << messaget::eom;
165#endif
166}
167
169 const namespacet &ns,
170 const exprt &expr,
172 const messaget &log)
173{
174#ifdef DEBUG_SHADOW_MEMORY
175 log.debug() << "Shadow memory: incompatible types "
176 << from_type(ns, "", expr.type()) << ", "
177 << from_type(ns, "", shadowed_address.address.type())
178 << messaget::eom;
179#endif
180}
181
183 const messaget &log,
184 const namespacet &ns,
185 const exprt &expr,
186 const exprt &null_pointer)
187{
188#ifdef DEBUG_SHADOW_MEMORY
189 log.conditional_output(
190 log.debug(), [ns, null_pointer, expr](messaget::mstreamt &mstream) {
191 mstream << "Shadow memory: value set match: " << format(null_pointer)
192 << " <-- " << format(expr) << messaget::eom;
193 mstream << "Shadow memory: ignoring set field on NULL object"
194 << messaget::eom;
195 });
196#endif
197}
198
200 const messaget &log,
201 const namespacet &ns,
202 const exprt &expr,
204{
205#ifdef DEBUG_SHADOW_MEMORY
206 log.debug() << "Shadow memory: incompatible types "
207 << from_type(ns, "", expr.type()) << ", "
208 << from_type(ns, "", shadowed_address.address.type())
209 << messaget::eom;
210#endif
211}
212
214{
222 {
223 return string_expr.get(ID_value);
224 }
225 else
226 {
227 UNREACHABLE_BECAUSE("Failed to extract shadow memory field name.");
228 }
229}
230
234static void remove_array_type_l2(typet &type)
235{
236 if(to_array_type(type).size().id() != ID_symbol)
237 return;
238
239 ssa_exprt &size = to_ssa_expr(to_array_type(type).size());
240 size.remove_level_2();
241}
242
244{
246 {
247 return to_address_of_expr(expr).object();
248 }
249
250 return dereference_exprt(expr);
251}
252
254{
255 if(
258 to_array_type(expr.type()).size().get_bool(ID_C_SSA_symbol))
259 {
261 exprt original_expr = to_ssa_expr(expr).get_original_expr();
263 to_ssa_expr(expr).set_expression(original_expr);
264 }
265 if(expr.id() == ID_string_constant)
266 {
267 expr = address_of_exprt(expr);
268 expr.type() = pointer_type(char_type());
269 }
271 {
272 expr = to_dereference_expr(expr).pointer();
273 }
274 else
275 {
276 expr = address_of_exprt(expr);
277 }
279}
280
282{
283 if(
284 expr.id() == ID_symbol && expr.type().id() == ID_pointer &&
285 (id2string(to_symbol_expr(expr).get_identifier()).rfind("invalid_object") !=
286 std::string::npos ||
287 id2string(to_symbol_expr(expr).get_identifier()).rfind("$object") !=
288 std::string::npos))
289 {
291 return;
292 }
293 Forall_operands(it, expr)
294 {
296 }
297}
298
299const exprt &
301{
304 {
305 return field_type_it->second;
306 }
309 return field_type_it->second;
310}
311
312const typet &
314{
316 return field_init_expr.type();
317}
318
320 const std::vector<exprt> &value_set,
321 const exprt &address)
322{
323 if(address.is_constant() && to_constant_expr(address).is_null_pointer())
324 {
325 for(const auto &e : value_set)
326 {
327 if(e.id() != ID_object_descriptor)
328 continue;
329
330 const exprt &expr = to_object_descriptor_expr(e).object();
331 if(expr.id() == ID_null_object)
332 return true;
333 }
334 return false;
335 }
336
337 for(const auto &e : value_set)
338 {
339 if(e.id() == ID_unknown || e.id() == ID_object_descriptor)
340 return true;
341 }
342 return false;
343}
344
349{
350 if(value.type().id() != ID_floatbv)
351 {
352 return value;
353 }
354 return make_byte_extract(
355 value,
357 unsignedbv_typet(to_bitvector_type(value.type()).get_width()));
358}
359
368 const exprt &value,
369 const typet &type,
370 const typet &field_type,
371 exprt::operandst &values)
372{
373 INVARIANT(
375 "Cannot combine with *or* elements of a non-bitvector type.");
376 const size_t size =
377 to_bitvector_type(type).get_width() / config.ansi_c.char_width;
378 values.push_back(typecast_exprt::conditional_cast(value, field_type));
379 for(size_t i = 1; i < size; ++i)
380 {
381 values.push_back(typecast_exprt::conditional_cast(
382 lshr_exprt(value, from_integer(8 * i, size_type())), field_type));
383 }
384}
385
397 exprt element,
398 const typet &field_type,
399 const namespacet &ns,
400 const messaget &log,
401 const bool is_union,
402 exprt::operandst &values)
403{
405 if(element.type().id() == ID_unsignedbv || element.type().id() == ID_signedbv)
406 {
407 exprt value = element;
408 if(is_union)
409 {
410 extract_bytes_of_bv(value, element.type(), field_type, values);
411 }
412 else
413 {
414 values.push_back(typecast_exprt::conditional_cast(value, field_type));
415 }
416 }
417 else
418 {
419 exprt value = compute_or_over_bytes(element, field_type, ns, log, is_union);
420 values.push_back(typecast_exprt::conditional_cast(value, field_type));
421 }
422}
423
431static exprt or_values(const exprt::operandst &values, const typet &field_type)
432{
433 if(values.size() == 1)
434 {
435 return values[0];
436 }
437 return multi_ary_exprt(ID_bitor, values, field_type);
438}
439
441 const exprt &expr,
442 const typet &field_type,
443 const namespacet &ns,
444 const messaget &log,
445 const bool is_union)
446{
447 INVARIANT(
448 can_cast_type<c_bool_typet>(field_type) ||
449 can_cast_type<bool_typet>(field_type),
450 "Can aggregate bytes with *or* only if the shadow memory type is _Bool.");
451
452 if(
453 expr.type().id() == ID_struct || expr.type().id() == ID_union ||
454 expr.type().id() == ID_struct_tag || expr.type().id() == ID_union_tag)
455 {
456 const auto &components =
457 (expr.type().id() == ID_struct_tag || expr.type().id() == ID_union_tag)
458 ? ns.follow_tag(to_struct_or_union_tag_type(expr.type())).components()
459 : to_struct_union_type(expr.type()).components();
460 exprt::operandst values;
461 for(const auto &component : components)
462 {
463 if(component.get_is_padding())
464 {
465 continue;
466 }
468 member_exprt(expr, component), field_type, ns, log, is_union, values);
469 }
470 return or_values(values, field_type);
471 }
472 else if(expr.type().id() == ID_array)
473 {
474 const array_typet &array_type = to_array_type(expr.type());
475 if(array_type.size().is_constant())
476 {
477 exprt::operandst values;
478 const mp_integer size =
480 for(mp_integer index = 0; index < size; ++index)
481 {
483 index_exprt(expr, from_integer(index, array_type.index_type())),
484 field_type,
485 ns,
486 log,
487 is_union,
488 values);
489 }
490 return or_values(values, field_type);
491 }
492 else
493 {
494 log.warning()
495 << "Shadow memory: cannot compute or over variable-size array "
496 << format(expr) << messaget::eom;
497 }
498 }
499 exprt::operandst values;
500 if(is_union)
501 {
504 expr.type(),
505 field_type,
506 values);
507 }
508 else
509 {
510 values.push_back(typecast_exprt::conditional_cast(
511 conditional_cast_floatbv_to_unsignedbv(expr), field_type));
512 }
513 return or_values(values, field_type);
514}
515
524std::pair<exprt, exprt> compare_to_collection(
525 const std::vector<exprt>::const_iterator &expr_iterator,
526 const std::vector<exprt>::const_iterator &end)
527{
528 // We need at least an element in the collection
529 INVARIANT(expr_iterator != end, "Cannot compute max of an empty collection");
531
532 // Iterator for the other elements in the collection in the interval denoted
533 // by `expr_iterator` and `end`.
534 std::vector<exprt>::const_iterator expr_to_compare_to =
535 std::next(expr_iterator);
536 if(expr_to_compare_to == end)
537 {
538 return {nil_exprt{}, current_expr};
539 }
540
541 std::vector<exprt> comparisons;
543 {
544 // Compare the current element with the n-th following it
545 comparisons.emplace_back(
547 }
548
550}
551
558 const std::vector<std::pair<exprt, exprt>> &conditions_and_values)
559{
560 // We need at least one element
561 INVARIANT(
562 conditions_and_values.size() > 0,
563 "Cannot compute max of an empty collection");
564
565 // We use reverse-iterator, so the last element is the one in the last else
566 // case.
567 auto reverse_ite = conditions_and_values.rbegin();
568
569 // The last element must have `nil_exprt` as condition
570 INVARIANT(
571 reverse_ite->first == nil_exprt{},
572 "Last element of condition-value list must have nil_exprt condition.");
573
574 exprt res = std::move(reverse_ite->second);
575
577 {
578 res = if_exprt(reverse_ite->first, reverse_ite->second, res);
579 }
580
581 return res;
582}
583
587static exprt create_max_expr(const std::vector<exprt> &values)
588{
589 std::vector<std::pair<exprt, exprt>> rows;
590 rows.reserve(values.size());
591 for(auto byte_it = values.begin(); byte_it != values.end(); ++byte_it)
592 {
593 // Create a pair condition-element where the condition is the comparison of
594 // the element with all the ones contained in the rest of the collection.
595 rows.emplace_back(compare_to_collection(byte_it, values.end()));
596 }
597
599}
600
602 const exprt &expr,
603 const typet &field_type,
604 const namespacet &ns)
605{
606 // Compute the bit-width of the type of `expr`.
607 std::size_t size = boolbv_widtht{ns}(expr.type());
608
609 // Compute how many bytes are in `expr`
610 std::size_t byte_count = size / config.ansi_c.char_width;
611
612 // Extract each byte of `expr` by using byte_extract.
613 std::vector<exprt> extracted_bytes;
615 for(std::size_t i = 0; i < byte_count; ++i)
616 {
618 expr, from_integer(i, unsigned_long_int_type()), field_type));
619 }
620
621 // Compute the max of the bytes extracted from `expr`.
623
624 INVARIANT(
625 max_expr.type() == field_type,
626 "Aggregated max value type must be the same as shadow memory field's "
627 "type.");
628
629 return max_expr;
630}
631
633 const std::vector<std::pair<exprt, exprt>> &conds_values)
634{
636 !conds_values.empty(), "build_if_else_expr requires non-empty argument");
637 exprt result = nil_exprt();
638 for(const auto &cond_value : conds_values)
639 {
640 if(result.is_nil())
641 {
642 result = cond_value.second;
643 }
644 else
645 {
646 result = if_exprt(cond_value.first, cond_value.second, result);
647 }
648 }
649 return result;
650}
651
658static bool
660{
661 if(expr_type.id() != ID_pointer || shadow_type.id() != ID_pointer)
662 return true;
663
664 // We filter out the particularly annoying case of char ** being definitely
665 // incompatible with char[].
666 const typet &expr_subtype = to_pointer_type(expr_type).base_type();
667 const typet &shadow_subtype = to_pointer_type(shadow_type).base_type();
668
669 if(
670 expr_subtype.id() == ID_pointer &&
671 to_pointer_type(expr_subtype).base_type().id() != ID_pointer &&
672 shadow_subtype.id() == ID_array &&
673 to_array_type(shadow_subtype).element_type().id() != ID_pointer)
674 {
675 return false;
676 }
677 if(
678 shadow_subtype.id() == ID_pointer &&
679 to_pointer_type(shadow_subtype).base_type().id() != ID_pointer &&
680 expr_subtype.id() != ID_pointer)
681 {
682 return false;
683 }
684 return true;
685}
686
690static void clean_string_constant(exprt &expr)
691{
693 if(
694 index_expr && index_expr->index().is_zero() &&
696 {
697 expr = index_expr->array();
698 }
699}
700
705static void adjust_array_types(typet &type)
706{
708 if(!pointer_type)
709 {
710 return;
711 }
712 if(
713 const auto *array_type =
715 {
716 pointer_type->base_type() = array_type->element_type();
717 }
719 {
721 }
722}
723
731 const exprt &shadowed_address,
733 const namespacet &ns,
734 const messaget &log)
735{
738 exprt lhs =
742 exprt base_cond = simplify_expr(equal_exprt(lhs, rhs), ns);
743 if(
744 base_cond.id() == ID_equal &&
746 {
747 return true_exprt();
748 }
749 if(base_cond.id() == ID_equal)
750 {
752 const bool equality_types_match =
753 equal_expr.lhs().type() == equal_expr.rhs().type();
756 "types of expressions on each side of equality should match",
759 }
760
761 return base_cond;
762}
763
771 const exprt &expr,
772 const namespacet &ns,
773 const messaget &log)
774{
775 typet expr_type = expr.type();
781 ns);
782 if(
783 expr_cond.id() == ID_equal &&
785 {
786 return true_exprt();
787 }
788 if(expr_cond.id() == ID_equal)
789 {
791 const bool equality_types_match =
792 equal_expr.lhs().type() == equal_expr.rhs().type();
795 "types of expressions on each side of equality should match",
798 }
799 return expr_cond;
800}
801
813 const exprt &shadow,
815 const exprt &expr,
816 const namespacet &ns,
817 const messaget &log)
818{
820 shadowed_object.object() = shadow;
823#ifdef DEBUG_SHADOW_MEMORY
824 log.debug() << "Shadow memory: shadow-deref: "
826#endif
827 return shadow_dereference;
828}
829
830/* foreach shadowed_address in SM:
831 * if(incompatible(shadow.object, object)) continue; // Type incompatibility
832 * base_match = object == shadow_object; // Do the base obj match the SM obj
833 * if(!base_match) continue;
834 * if(object is null) continue; // Done in the caller
835 * if(type_of(dereference object is void)
836 * // we terminate as we don't know how big is the memory at that location
837 * shadowed_dereference.pointer = deref(shadow.shadowed_object, expr);
838 * aggregate the object depending on the type
839 * expr_match = shadowed_dereference == expr
840 * if(!expr_match)
841 * continue;
842 * shadow_dereference = deref(shadow.object, expr);
843 * if(expr_match)
844 * result = shadow_dereference.value [exact match]
845 * break;
846 * if(base_match) [shadow memory matches]
847 * result += (expr_match, shadow_dereference.value)
848 * break;
849 * result += (base_match & expr_match, shadow_dereference.value)
850*/
851std::vector<std::pair<exprt, exprt>> get_shadow_dereference_candidates(
852 const namespacet &ns,
853 const messaget &log,
854 const exprt &matched_object,
855 const std::vector<shadow_memory_statet::shadowed_addresst> &addresses,
856 const typet &field_type,
857 const exprt &expr,
858 const typet &lhs_type,
859 bool &exact_match)
860{
861 std::vector<std::pair<exprt, exprt>> result;
862
863 for(const auto &shadowed_address : addresses)
864 {
866 if(!are_types_compatible(expr.type(), shadowed_address.address.type()))
867 {
869 continue;
870 }
876
877 // NULL has already been handled in the caller; skip.
878 if(matched_base_descriptor.object().id() == ID_null_object)
879 {
880 continue;
881 }
882
883 // Used only to check if the pointer is `void`
886
887 if(is_void_pointer(dereference.pointer.type()))
888 {
889 std::stringstream s;
890 s << "Shadow memory: cannot get shadow memory via type void* for "
891 << format(expr)
892 << ". Insert a cast to the type that you want to access.";
893 throw invalid_input_exceptiont(s.str());
894 }
895
896 // Replace original memory with the shadow object (symbolic dereferencing is
897 // performed during symex later on).
900 shadowed_address.shadow, matched_base_descriptor, expr, ns, log);
902 ns,
903 log,
907 expr,
909
910 const bool is_union = matched_base_descriptor.type().id() == ID_union ||
912
913 exprt value;
914 // Aggregate the value depending on the type
915 if(field_type.id() == ID_c_bool || field_type.id() == ID_bool)
916 {
917 // Value is of bool type, so aggregate with or.
920 shadow_dereference.value, field_type, ns, log, is_union),
921 lhs_type);
922 }
923 else
924 {
925 // Value is of other (bitvector) type, so aggregate with max
926 value = compute_max_over_bytes(shadow_dereference.value, field_type, ns);
927 }
928
932 if(base_cond.is_false())
933 {
934 continue;
935 }
936
937 const exprt expr_cond =
938 get_matched_expr_cond(dereference.pointer, expr, ns, log);
939 if(expr_cond.is_false())
940 {
941 continue;
942 }
943
944 if(base_cond.is_true() && expr_cond.is_true())
945 {
946#ifdef DEBUG_SHADOW_MEMORY
947 log.debug() << "exact match" << messaget::eom;
948#endif
949 exact_match = true;
950 result.clear();
951 result.emplace_back(base_cond, value);
952 break;
953 }
954
955 if(base_cond.is_true())
956 {
957 // No point looking at further shadow addresses
958 // as only one of them can match.
959#ifdef DEBUG_SHADOW_MEMORY
960 log.debug() << "base match" << messaget::eom;
961#endif
962 result.clear();
963 result.emplace_back(expr_cond, value);
964 break;
965 }
966 else
967 {
968#ifdef DEBUG_SHADOW_MEMORY
969 log.debug() << "conditional match" << messaget::eom;
970#endif
971 result.emplace_back(and_exprt(base_cond, expr_cond), value);
972 }
973 }
974 return result;
975}
976
977// Unfortunately.
980{
981 if(expr.object().id() == ID_symbol)
982 {
983 return expr;
984 }
985 if(!expr.offset().is_constant())
986 {
987 return expr;
988 }
989
990 object_descriptor_exprt result = expr;
991 mp_integer offset =
993 exprt object = expr.object();
994
995 while(true)
996 {
997 if(object.id() == ID_index)
998 {
999 const index_exprt &index_expr = to_index_expr(object);
1000 mp_integer index =
1002
1003 offset += *pointer_offset_size(index_expr.type(), ns) * index;
1004 object = index_expr.array();
1005 }
1006 else if(object.id() == ID_member)
1007 {
1008 const member_exprt &member_expr = to_member_expr(object);
1009 const auto &struct_op = member_expr.struct_op();
1010 const struct_typet &struct_type =
1011 struct_op.type().id() == ID_struct_tag
1012 ? ns.follow_tag(to_struct_tag_type(struct_op.type()))
1013 : to_struct_type(struct_op.type());
1014 offset +=
1015 *member_offset(struct_type, member_expr.get_component_name(), ns);
1016 object = struct_op;
1017 }
1018 else
1019 {
1020 break;
1021 }
1022 }
1023 result.object() = object;
1024 result.offset() = from_integer(offset, expr.offset().type());
1025 return result;
1026}
1027
1029 const namespacet &ns,
1030 const messaget &log,
1031 const std::vector<exprt> &value_set,
1032 const exprt &expr)
1033{
1034 INVARIANT(
1036 "Cannot check if value_set contains only NULL as `expr` type is not a "
1037 "pointer.");
1039 if(value_set.size() == 1 && contains_null_or_invalid(value_set, null_pointer))
1040 {
1042 return true;
1043 }
1044 return false;
1045}
1046
1048static std::vector<std::pair<exprt, exprt>>
1050 const exprt &expr,
1051 const exprt &matched_object,
1052 const std::vector<shadow_memory_statet::shadowed_addresst> &addresses,
1053 const namespacet &ns,
1054 const messaget &log,
1055 bool &exact_match)
1056{
1057 std::vector<std::pair<exprt, exprt>> result;
1058 for(const auto &shadowed_address : addresses)
1059 {
1061
1062 if(!are_types_compatible(expr.type(), shadowed_address.address.type()))
1063 {
1065 continue;
1066 }
1067
1070
1073 matched_base_descriptor, expr, ns);
1074
1078
1079 // NULL has already been handled in the caller; skip.
1080 if(matched_base_descriptor.object().id() == ID_null_object)
1081 {
1082 continue;
1083 }
1086 shadowed_address.shadow, matched_base_descriptor, expr, ns, log);
1088 ns,
1089 log,
1093 expr,
1095
1099 if(base_cond.is_false())
1100 {
1101 continue;
1102 }
1103
1104 const exprt expr_cond =
1105 get_matched_expr_cond(dereference.pointer, expr, ns, log);
1106 if(expr_cond.is_false())
1107 {
1108 continue;
1109 }
1110
1111 if(base_cond.is_true() && expr_cond.is_true())
1112 {
1113 log_shadow_memory_message(log, "exact match");
1114
1115 exact_match = true;
1116 result.clear();
1117 result.push_back({base_cond, shadow_dereference.pointer});
1118 break;
1119 }
1120
1121 if(base_cond.is_true())
1122 {
1123 // No point looking at further shadow addresses
1124 // as only one of them can match.
1125 log_shadow_memory_message(log, "base match");
1126
1127 result.clear();
1128 result.emplace_back(expr_cond, shadow_dereference.pointer);
1129 break;
1130 }
1131 else
1132 {
1133 log_shadow_memory_message(log, "conditional match");
1134 result.emplace_back(
1136 }
1137 }
1138 return result;
1139}
1140
1141std::optional<exprt> get_shadow_memory(
1142 const exprt &expr,
1143 const std::vector<exprt> &value_set,
1144 const std::vector<shadow_memory_statet::shadowed_addresst> &addresses,
1145 const namespacet &ns,
1146 const messaget &log,
1147 size_t &mux_size)
1148{
1149 std::vector<std::pair<exprt, exprt>> conds_values;
1150 for(const auto &matched_object : value_set)
1151 {
1153 {
1154 log.warning() << "Shadow memory: value set contains unknown for "
1155 << format(expr) << messaget::eom;
1156 continue;
1157 }
1158 if(
1159 to_object_descriptor_expr(matched_object).root_object().id() ==
1161 {
1162 log.warning() << "Shadow memory: value set contains integer_address for "
1163 << format(expr) << messaget::eom;
1164 continue;
1165 }
1166 if(matched_object.type().get_bool(ID_C_is_failed_symbol))
1167 {
1168 log.warning() << "Shadow memory: value set contains failed symbol for "
1169 << format(expr) << messaget::eom;
1170 continue;
1171 }
1172
1173 bool exact_match = false;
1176
1177 if(!per_value_set_conds_values.empty())
1178 {
1179 if(exact_match)
1180 {
1182 }
1183 conds_values.insert(
1184 conds_values.begin(),
1187 mux_size += conds_values.size() - 1;
1188 if(exact_match)
1189 {
1190 break;
1191 }
1192 }
1193 }
1194 if(!conds_values.empty())
1195 {
1197 }
1198 return {};
1199}
configt config
Definition config.cpp:25
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
API to expression classes for bitvectors.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
byte_extract_exprt make_byte_extract(const exprt &_op, const exprt &_offset, const typet &_type)
Construct a byte_extract_exprt with endianness and byte width matching the current configuration.
Expression classes for byte-level operators.
unsignedbv_typet unsigned_int_type()
Definition c_types.cpp:36
unsignedbv_typet unsigned_long_int_type()
Definition c_types.cpp:86
pointer_typet pointer_type(const typet &subtype)
Definition c_types.cpp:235
bitvector_typet char_type()
Definition c_types.cpp:106
Operator to return the address of an object.
virtual void clear()
Reset the abstract state.
Definition ai.h:265
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
Boolean AND.
Definition std_expr.h:2125
Arrays with given size.
Definition std_types.h:807
A base class for expressions that are predicates, i.e., Boolean-typed, and that take exactly two argu...
Definition std_expr.h:731
struct configt::ansi_ct ansi_c
Operator to dereference a pointer.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Equality.
Definition std_expr.h:1366
Base class for all expressions.
Definition expr.h:56
std::vector< exprt > operandst
Definition expr.h:58
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:212
typet & type()
Return the type of the expression.
Definition expr.h:84
Central data structure: state.
shadow_memory_statet shadow_memory
The trinary if-then-else operator.
Definition std_expr.h:2502
Array index operator.
Definition std_expr.h:1470
Thrown when user-provided input cannot be processed.
const irep_idt & id() const
Definition irep.h:388
bool is_nil() const
Definition irep.h:368
Logical right shift.
Extract member of struct or union.
Definition std_expr.h:2972
Class that provides messages with a built-in verbosity 'level'.
Definition message.h:154
static eomt eom
Definition message.h:289
A base class for multi-ary expressions Associativity is not specified.
Definition std_expr.h:912
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition namespace.cpp:49
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
The NIL expression.
Definition std_expr.h:3209
The null pointer constant.
Split an expression into a base object and a (byte) offset.
const typet & base_type() const
The type of the data what we point to.
field_definitiont global_fields
Field definitions for global-scope fields.
field_definitiont local_fields
Field definitions for local-scope fields.
shadow_memory_field_definitionst fields
The available shadow memory field definitions.
Expression providing an SSA-renamed symbol of expressions.
Definition ssa_expr.h:17
void remove_level_2()
Definition ssa_expr.cpp:199
Structure type, corresponds to C style structs.
Definition std_types.h:231
The Boolean constant true.
Definition std_expr.h:3191
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:2081
The type of an expression, extends irept.
Definition type.h:29
Fixed-width bit-vector with unsigned binary interpretation.
Return value for build_reference_to; see that method for documentation.
static valuet build_reference_to(const exprt &what, const exprt &pointer, const namespacet &ns)
#define Forall_operands(it, expr)
Definition expr.h:27
static format_containert< T > format(const T &o)
Definition format.h:37
void dereference(const irep_idt &function_id, goto_programt::const_targett target, exprt &expr, const namespacet &ns, value_setst &value_sets, message_handlert &message_handler)
Remove dereferences in expr using value_sets to determine to what objects the pointers may be pointin...
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
std::string from_type(const namespacet &ns, const irep_idt &identifier, const typet &type)
double log(double x)
Definition math.c:2449
bool is_void_pointer(const typet &type)
This method tests, if the given typet is a pointer of type void.
const object_descriptor_exprt & to_object_descriptor_expr(const exprt &expr)
Cast an exprt to an object_descriptor_exprt.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
std::optional< mp_integer > pointer_offset_size(const typet &type, const namespacet &ns)
Compute the size of a type in bytes, rounding up to full bytes.
std::optional< mp_integer > member_offset(const struct_typet &type, const irep_idt &member, const namespacet &ns)
Pointer Logic.
void replace_invalid_object_by_null(exprt &expr)
Replace an invalid object by a null pointer.
static object_descriptor_exprt normalize(const object_descriptor_exprt &expr, const namespacet &ns)
void shadow_memory_log_value_set_match(const namespacet &ns, const messaget &log, const exprt &address, const exprt &expr)
Logs a successful match between an address and a value within the value set.
std::optional< exprt > get_shadow_memory(const exprt &expr, const std::vector< exprt > &value_set, const std::vector< shadow_memory_statet::shadowed_addresst > &addresses, const namespacet &ns, const messaget &log, size_t &mux_size)
Get shadow memory values for a given expression within a specified value set.
static void clean_string_constant(exprt &expr)
Simplify &string_constant[0] to &string_constant to facilitate expression equality for exact matching...
exprt deref_expr(const exprt &expr)
Wraps a given expression into a dereference_exprt unless it is an address_of_exprt in which case it j...
bool contains_null_or_invalid(const std::vector< exprt > &value_set, const exprt &address)
Given a pointer expression check to see if it can be a null pointer or an invalid object within value...
const exprt & get_field_init_expr(const irep_idt &field_name, const goto_symex_statet &state)
Retrieve the expression that a field was initialised with within a given symex state.
static exprt or_values(const exprt::operandst &values, const typet &field_type)
Translate a list of values into an or expression.
exprt compute_or_over_bytes(const exprt &expr, const typet &field_type, const namespacet &ns, const messaget &log, const bool is_union)
Performs aggregation of the shadow memory field value over multiple bytes for fields whose type is _B...
static bool are_types_compatible(const typet &expr_type, const typet &shadow_type)
Checks given types (object type and shadow memory field type) for equality.
static void extract_bytes_of_expr(exprt element, const typet &field_type, const namespacet &ns, const messaget &log, const bool is_union, exprt::operandst &values)
Extract the components from the input expression value and places them into the array values.
static void adjust_array_types(typet &type)
Flattens type of the form pointer_type(array_type(element_type)) to pointer_type(element_type) and po...
bool check_value_set_contains_only_null_ptr(const namespacet &ns, const messaget &log, const std::vector< exprt > &value_set, const exprt &expr)
Checks if value_set contains only a NULL pointer expression of the same type of expr.
const typet & get_field_init_type(const irep_idt &field_name, const goto_symex_statet &state)
Retrieves the type of the shadow memory by returning the type of the shadow memory initializer value.
static void log_value_set_match(const namespacet &ns, const messaget &log, const shadow_memory_statet::shadowed_addresst &shadowed_address, const exprt &matched_base_address, const value_set_dereferencet::valuet &dereference, const exprt &expr, const value_set_dereferencet::valuet &shadow_dereference)
Log a match between an address and the value set.
void shadow_memory_log_set_field(const namespacet &ns, const messaget &log, const irep_idt &field_name, const exprt &expr, const exprt &value)
Logs setting a value to a given shadow field.
void clean_pointer_expr(exprt &expr)
Clean the given pointer expression so that it has the right shape for being used for identifying shad...
static exprt combine_condition_and_max_values(const std::vector< std::pair< exprt, exprt > > &conditions_and_values)
Combine each (condition, value) element in the input collection into a if-then-else expression such a...
static exprt get_matched_expr_cond(const exprt &dereference_pointer, const exprt &expr, const namespacet &ns, const messaget &log)
Function that compares the two arguments dereference_pointer and expr, simplifies the comparison expr...
std::vector< std::pair< exprt, exprt > > get_shadow_dereference_candidates(const namespacet &ns, const messaget &log, const exprt &matched_object, const std::vector< shadow_memory_statet::shadowed_addresst > &addresses, const typet &field_type, const exprt &expr, const typet &lhs_type, bool &exact_match)
Get a list of (condition, value) pairs for a certain pointer from the shadow memory,...
static void log_try_shadow_address(const namespacet &ns, const messaget &log, const shadow_memory_statet::shadowed_addresst &shadowed_address)
Log trying out a match between an object and a (target) shadow address.
static void log_value_set_contains_only_null(const messaget &log, const namespacet &ns, const exprt &expr, const exprt &null_pointer)
static void log_are_types_incompatible(const namespacet &ns, const exprt &expr, const shadow_memory_statet::shadowed_addresst &shadowed_address, const messaget &log)
exprt compute_max_over_bytes(const exprt &expr, const typet &field_type, const namespacet &ns)
Performs aggregation of the shadow memory field value over multiple cells for fields whose type is a ...
static void log_shadow_memory_incompatible_types(const messaget &log, const namespacet &ns, const exprt &expr, const shadow_memory_statet::shadowed_addresst &shadowed_address)
exprt build_if_else_expr(const std::vector< std::pair< exprt, exprt > > &conds_values)
Build an if-then-else chain from a vector containing pairs of expressions.
static void log_shadow_memory_message(const messaget &log, const char *text)
Generic logging function to log a text if DEBUG_SHADOW_MEMORY is defined.
void shadow_memory_log_get_field(const namespacet &ns, const messaget &log, const irep_idt &field_name, const exprt &expr)
Logs getting a value corresponding to a shadow memory field.
irep_idt extract_field_name(const exprt &string_expr)
Extracts the field name identifier from a string expression, e.g.
static exprt create_max_expr(const std::vector< exprt > &values)
Create an expression encoding the max operation over the collection values
static void remove_array_type_l2(typet &type)
If the given type is an array type, then remove the L2 level renaming from its size.
void shadow_memory_log_value_set(const namespacet &ns, const messaget &log, const std::vector< exprt > &value_set)
Logs the retrieval of the value associated with a given shadow memory field.
void shadow_memory_log_text_and_expr(const namespacet &ns, const messaget &log, const char *text, const exprt &expr)
Generic logging function that will log depending on the configured verbosity.
std::pair< exprt, exprt > compare_to_collection(const std::vector< exprt >::const_iterator &expr_iterator, const std::vector< exprt >::const_iterator &end)
Create an expression comparing the element at expr_iterator with the following elements of the collec...
static value_set_dereferencet::valuet get_shadow_dereference(const exprt &shadow, const object_descriptor_exprt &matched_base_descriptor, const exprt &expr, const namespacet &ns, const messaget &log)
Retrieve the shadow value a pointer expression may point to.
static exprt conditional_cast_floatbv_to_unsignedbv(const exprt &value)
Casts a given (float) bitvector expression to an unsigned bitvector.
static std::vector< std::pair< exprt, exprt > > get_shadow_memory_for_matched_object(const exprt &expr, const exprt &matched_object, const std::vector< shadow_memory_statet::shadowed_addresst > &addresses, const namespacet &ns, const messaget &log, bool &exact_match)
Used for set_field and shadow memory copy.
static void extract_bytes_of_bv(const exprt &value, const typet &type, const typet &field_type, exprt::operandst &values)
Extract byte-sized elements from the input bitvector-typed expression value and places them into the ...
static exprt get_matched_base_cond(const exprt &shadowed_address, const exprt &matched_base_address, const namespacet &ns, const messaget &log)
Function that compares the two arguments shadowed_address and matched_base_address,...
Symex Shadow Memory Instrumentation Utilities.
exprt simplify_expr(exprt src, const namespacet &ns)
BigInt mp_integer
Definition smt_terms.h:17
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition invariant.h:534
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
#define DATA_INVARIANT_WITH_DIAGNOSTICS(CONDITION, REASON,...)
Definition invariant.h:535
#define POSTCONDITION(CONDITION)
Definition invariant.h:479
#define UNREACHABLE_BECAUSE(REASON)
Definition invariant.h:526
const ssa_exprt & to_ssa_expr(const exprt &expr)
Cast a generic exprt to an ssa_exprt.
Definition ssa_expr.h:145
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition std_expr.cpp:122
API to expression classes.
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1538
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2107
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3064
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3173
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:272
const equal_exprt & to_equal_expr(const exprt &expr)
Cast an exprt to an equal_exprt.
Definition std_expr.h:1407
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition std_types.h:308
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:518
const struct_or_union_tag_typet & to_struct_or_union_tag_type(const typet &type)
Cast a typet to a struct_or_union_tag_typet.
Definition std_types.h:478
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:888
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition std_types.h:214
#define size_type
Definition unistd.c:186
Pointer Dereferencing.