CBMC
Loading...
Searching...
No Matches
goto_symex.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Symbolic Execution
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
11
12#include "goto_symex.h"
13
14#include <util/arith_tools.h>
15#include <util/c_types.h>
16#include <util/format_expr.h>
17#include <util/fresh_symbol.h>
21#include <util/simplify_utils.h>
22#include <util/std_code.h>
23#include <util/string_expr.h>
24#include <util/string_utils.h>
25
26#include "expr_skeleton.h"
28#include "symex_assign.h"
29
30#include <climits>
31
32void goto_symext::do_simplify(exprt &expr, const value_sett &value_set)
33{
34 if(symex_config.simplify_opt)
35 {
36 simplify_expr_with_value_sett{value_set, language_mode, ns}.simplify(expr);
37 }
38}
39
41 statet &state,
42 const exprt &o_lhs,
43 const exprt &o_rhs)
44{
45 exprt lhs = clean_expr(o_lhs, state, true);
46 exprt rhs = clean_expr(o_rhs, state, false);
47
49 lhs.type() == rhs.type(),
50 "assignments must be type consistent, got",
51 lhs.type().pretty(),
52 rhs.type().pretty(),
53 state.source.pc->source_location());
54
56 log.debug(), [this, &lhs](messaget::mstreamt &mstream) {
57 mstream << "Assignment to " << format(lhs) << " ["
58 << pointer_offset_bits(lhs.type(), ns).value_or(0) << " bits]"
59 << messaget::eom;
60 });
61
62 // rvalues present within the lhs (for example, "some_array[this_rvalue]" or
63 // "byte_extract <type> from an_lvalue offset this_rvalue") can affect whether
64 // we use field-sensitive symbols or not, so L2-rename them up front:
65 lhs = state.l2_rename_rvalues(lhs, ns);
66 do_simplify(lhs, state.value_set);
67 lhs = state.field_sensitivity.apply(ns, state, std::move(lhs), true);
68
69 if(rhs.id() == ID_side_effect)
70 {
72 const irep_idt &statement = side_effect_expr.get_statement();
73
74 if(
75 statement == ID_cpp_new || statement == ID_cpp_new_array ||
76 statement == ID_java_new_array_data)
77 {
79 }
80 else if(statement == ID_allocate)
82 else if(statement == ID_va_start)
84 else
86 }
87 else
88 {
90
91 // Let's hide return value assignments.
92 if(
93 lhs.id() == ID_symbol &&
94 id2string(to_symbol_expr(lhs).get_identifier()).find("#return_value!") !=
95 std::string::npos)
96 {
98 }
99
100 // We hide if we are in a hidden function.
101 if(state.call_stack().top().hidden_function)
103
104 // We hide if we are executing a hidden instruction.
105 if(state.source.pc->source_location().get_hide())
107
110 state,
111 assignment_type,
112 ns,
115 target};
116
117 // Try to constant propagate potential side effects of the assignment, when
118 // simplification is turned on and there is one thread only. Constant
119 // propagation is only sound for sequential code as here we do not take into
120 // account potential writes from other threads when propagating the values.
121 if(symex_config.simplify_opt && state.threads.size() <= 1)
122 {
124 state, symex_assign, lhs, rhs))
125 return;
126 }
127
128 // We may end up reading (and writing) all components of an object composed
129 // of multiple fields. In such cases, we must do so atomically to avoid
130 // overwriting components modified by another thread. Note that this also
131 // implies multiple shared reads on the rhs being treated as atomic.
132 const bool maybe_divisible =
133 lhs.id() == ID_index ||
134 (is_ssa_expr(lhs) &&
135 state.field_sensitivity.is_divisible(to_ssa_expr(lhs), false));
137 state.threads.size() > 1 &&
138 state.atomic_section_id == 0;
139
141 symex_atomic_begin(state);
142
146 state,
147 assignment_type,
148 ns,
151 target}
152 .assign_rec(lhs, expr_skeletont{}, rhs, lhs_if_then_else_conditions);
153
155 symex_atomic_end(state);
156 }
157}
158
166static std::string get_alnum_string(const array_exprt &char_array)
167{
168 const auto &ibv_type =
169 to_integer_bitvector_type(to_array_type(char_array.type()).element_type());
170
171 const std::size_t n_bits = ibv_type.get_width();
172 CHECK_RETURN(n_bits % 8 == 0);
173
174 static_assert(CHAR_BIT == 8, "bitwidth of char assumed to be 8");
175
176 const std::size_t n_chars = n_bits / 8;
177
178 INVARIANT(
179 sizeof(std::size_t) >= n_chars,
180 "size_t shall be large enough to represent a character");
181
182 std::string result;
183
184 for(const auto &c : char_array.operands())
185 {
187
188 for(std::size_t i = 0; i < n_chars; i++)
189 {
190 const char c_chunk = static_cast<char>((c_val >> (i * 8)) & 0xff);
191 result.push_back(c_chunk);
192 }
193 }
194
195 return escape_non_alnum(result);
196}
197
199 statet &state,
200 symex_assignt &symex_assign,
201 const exprt &lhs,
202 const exprt &rhs)
203{
204 if(rhs.id() == ID_function_application)
205 {
207
208 if(f_l1.function().id() == ID_symbol)
209 {
210 const irep_idt &func_id =
211 to_symbol_expr(f_l1.function()).get_identifier();
212
214 {
216 }
218 {
219 // constant propagating the empty string always succeeds as it does
220 // not depend on potentially non-constant inputs
222 return true;
223 }
225 {
227 }
228 else if(
231 {
233 }
235 {
237 }
239 {
241 }
243 {
245 }
247 {
249 }
251 {
253 }
255 {
256 return constant_propagate_case_change(state, symex_assign, f_l1, false);
257 }
259 {
261 }
263 {
265 }
266 }
267 }
268
269 return false;
270}
271
273 statet &state,
274 symex_assignt &symex_assign,
275 const ssa_exprt &length,
277 const ssa_exprt &char_array,
279{
280 // We need to make sure that the length of the previous array isn't
281 // unconstrained, otherwise it could be arbitrarily large which causes
282 // invalid traces
283 symex_assume(state, equal_exprt{length, from_integer(0, length.type())});
284
285 // assign length of string
286 symex_assign.assign_symbol(length, expr_skeletont{}, new_length, {});
287
288 const std::string aux_symbol_name =
289 get_alnum_string(new_char_array) + "_constant_char_array";
290
291 const bool string_constant_exists =
293
294 const symbolt &aux_symbol =
299
300 INVARIANT(
301 aux_symbol.value == new_char_array,
302 "symbol shall have value derived from char array content");
303
305 index_exprt(aux_symbol.symbol_expr(), from_integer(0, c_index_type())));
306
307 symex_assign.assign_symbol(char_array, expr_skeletont{}, string_data, {});
308
310 {
313 }
314}
315
317 statet &state,
318 symex_assignt &symex_assign,
319 const std::string &aux_symbol_name,
320 const ssa_exprt &char_array,
322{
325
328 "",
331 ns.lookup(to_symbol_expr(char_array.get_original_expr())).mode,
332 ns,
333 state.symbol_table);
334
335 CHECK_RETURN(new_aux_symbol.is_state_var);
336 CHECK_RETURN(new_aux_symbol.is_lvalue);
337
338 new_aux_symbol.is_static_lifetime = true;
339 new_aux_symbol.is_file_local = false;
340 new_aux_symbol.is_thread_local = false;
341
343
344 const exprt arr = state.rename(new_aux_symbol.symbol_expr(), ns).get();
345
346 symex_assign.assign_symbol(
347 to_ssa_expr(arr).get_l1_object(), expr_skeletont{}, new_char_array, {});
348
349 return new_aux_symbol;
350}
351
380
381std::optional<std::reference_wrapper<const array_exprt>>
383 const statet &state,
384 const exprt &content)
385{
386 if(content.id() != ID_symbol)
387 {
388 return {};
389 }
390
391 const auto s_pointer_opt =
392 state.propagation.find(to_symbol_expr(content).get_identifier());
393
394 if(!s_pointer_opt)
395 {
396 return {};
397 }
398
400}
401
402std::optional<std::reference_wrapper<const constant_exprt>>
404{
405 if(expr.id() != ID_symbol)
406 {
407 return {};
408 }
409
410 const auto constant_expr_opt =
411 state.propagation.find(to_symbol_expr(expr).get_identifier());
412
413 if(!constant_expr_opt || !constant_expr_opt->get().is_constant())
414 {
415 return {};
416 }
417
418 return std::optional<std::reference_wrapper<const constant_exprt>>(
420}
421
423 statet &state,
424 symex_assignt &symex_assign,
426{
427 const auto &f_type = f_l1.function_type();
428 const auto &length_type = f_type.domain().at(0);
429 const auto &char_type = to_pointer_type(f_type.domain().at(1)).base_type();
430
431 const constant_exprt length = from_integer(0, length_type);
432
434
436 f_l1.arguments().size() >= 2,
437 "empty string primitive requires two output arguments");
438
440
442 state,
444 to_ssa_expr(f_l1.arguments().at(0)),
445 length,
446 to_ssa_expr(f_l1.arguments().at(1)),
447 char_array);
448}
449
451 statet &state,
452 symex_assignt &symex_assign,
454{
455 const auto &f_type = f_l1.function_type();
456 const auto &length_type = f_type.domain().at(0);
457 const auto &char_type = to_pointer_type(f_type.domain().at(1)).base_type();
458
459 const refined_string_exprt &s1 = to_string_expr(f_l1.arguments().at(2));
460 const auto s1_data_opt = try_evaluate_constant_string(state, s1.content());
461
462 if(!s1_data_opt)
463 return false;
464
465 const array_exprt &s1_data = s1_data_opt->get();
466
467 const refined_string_exprt &s2 = to_string_expr(f_l1.arguments().at(3));
468 const auto s2_data_opt = try_evaluate_constant_string(state, s2.content());
469
470 if(!s2_data_opt)
471 return false;
472
473 const array_exprt &s2_data = s2_data_opt->get();
474
475 const std::size_t new_size =
476 s1_data.operands().size() + s2_data.operands().size();
477
479 from_integer(new_size, length_type);
480
482
483 exprt::operandst operands(s1_data.operands());
484 operands.insert(
485 operands.end(), s2_data.operands().begin(), s2_data.operands().end());
486
487 const array_exprt new_char_array(std::move(operands), new_char_array_type);
488
490 state,
492 to_ssa_expr(f_l1.arguments().at(0)),
494 to_ssa_expr(f_l1.arguments().at(1)),
496
497 return true;
498}
499
501 statet &state,
502 symex_assignt &symex_assign,
504{
505 const std::size_t num_operands = f_l1.arguments().size();
506
509
510 const auto &f_type = f_l1.function_type();
511 const auto &length_type = f_type.domain().at(0);
512 const auto &char_type = to_pointer_type(f_type.domain().at(1)).base_type();
513
514 const refined_string_exprt &s = to_string_expr(f_l1.arguments().at(2));
515 const auto s_data_opt = try_evaluate_constant_string(state, s.content());
516
517 if(!s_data_opt)
518 return false;
519
520 const array_exprt &s_data = s_data_opt->get();
521
523
524 if(num_operands == 5)
525 {
526 const auto end_index_expr_opt =
527 try_evaluate_constant(state, f_l1.arguments().at(4));
528
530 {
531 return false;
532 }
533
534 end_index =
536
537 if(end_index < 0 || end_index > s_data.operands().size())
538 {
539 return false;
540 }
541 }
542 else
543 {
544 end_index = s_data.operands().size();
545 }
546
547 const auto start_index_expr_opt =
548 try_evaluate_constant(state, f_l1.arguments().at(3));
549
551 {
552 return false;
553 }
554
555 const mp_integer start_index =
557
559 {
560 return false;
561 }
562
564 from_integer(end_index - start_index, length_type);
565
567
568 exprt::operandst operands(
569 std::next(
570 s_data.operands().begin(), numeric_cast_v<std::size_t>(start_index)),
571 std::next(
572 s_data.operands().begin(), numeric_cast_v<std::size_t>(end_index)));
573
574 const array_exprt new_char_array(std::move(operands), new_char_array_type);
575
577 state,
579 to_ssa_expr(f_l1.arguments().at(0)),
581 to_ssa_expr(f_l1.arguments().at(1)),
583
584 return true;
585}
586
588 statet &state,
589 symex_assignt &symex_assign,
591{
592 // The function application expression f_l1 takes the following arguments:
593 // - result string length (output parameter)
594 // - result string data array (output parameter)
595 // - integer to convert to a string
596 // - radix (optional, default 10)
597 const std::size_t num_operands = f_l1.arguments().size();
598
601
602 const auto &f_type = f_l1.function_type();
603 const auto &length_type = f_type.domain().at(0);
604 const auto &char_type = to_pointer_type(f_type.domain().at(1)).base_type();
605
606 const auto &integer_opt =
607 try_evaluate_constant(state, f_l1.arguments().at(2));
608
609 if(!integer_opt)
610 {
611 return false;
612 }
613
615
616 unsigned base = 10;
617
618 if(num_operands == 4)
619 {
620 const auto &base_constant_opt =
621 try_evaluate_constant(state, f_l1.arguments().at(3));
622
624 {
625 return false;
626 }
627
629
630 if(!base_opt)
631 {
632 return false;
633 }
634
635 base = *base_opt;
636 }
637
638 std::string s = integer2string(integer, base);
639
641 from_integer(s.length(), length_type);
642
644
645 exprt::operandst operands;
646
647 std::transform(
648 s.begin(),
649 s.end(),
650 std::back_inserter(operands),
651 [&char_type](const char c) { return from_integer(tolower(c), char_type); });
652
653 const array_exprt new_char_array(std::move(operands), new_char_array_type);
654
656 state,
658 to_ssa_expr(f_l1.arguments().at(0)),
660 to_ssa_expr(f_l1.arguments().at(1)),
662
663 return true;
664}
665
667 statet &state,
668 symex_assignt &symex_assign,
670{
671 // The function application expression f_l1 takes the following arguments:
672 // - result string length (output parameter)
673 // - result string data array (output parameter)
674 // - string to delete char from
675 // - index of char to delete
676 PRECONDITION(f_l1.arguments().size() == 4);
677
678 const auto &f_type = f_l1.function_type();
679 const auto &length_type = f_type.domain().at(0);
680 const auto &char_type = to_pointer_type(f_type.domain().at(1)).base_type();
681
682 const refined_string_exprt &s = to_string_expr(f_l1.arguments().at(2));
683 const auto s_data_opt = try_evaluate_constant_string(state, s.content());
684
685 if(!s_data_opt)
686 {
687 return false;
688 }
689
690 const array_exprt &s_data = s_data_opt->get();
691
692 const auto &index_opt = try_evaluate_constant(state, f_l1.arguments().at(3));
693
694 if(!index_opt)
695 {
696 return false;
697 }
698
699 const mp_integer index = numeric_cast_v<mp_integer>(index_opt->get());
700
701 if(index < 0 || index >= s_data.operands().size())
702 {
703 return false;
704 }
705
707 from_integer(s_data.operands().size() - 1, length_type);
708
710
711 exprt::operandst operands;
712 operands.reserve(s_data.operands().size() - 1);
713
714 const std::size_t i = numeric_cast_v<std::size_t>(index);
715
716 operands.insert(
717 operands.end(),
718 s_data.operands().begin(),
719 std::next(s_data.operands().begin(), i));
720
721 operands.insert(
722 operands.end(),
723 std::next(s_data.operands().begin(), i + 1),
724 s_data.operands().end());
725
726 const array_exprt new_char_array(std::move(operands), new_char_array_type);
727
729 state,
731 to_ssa_expr(f_l1.arguments().at(0)),
733 to_ssa_expr(f_l1.arguments().at(1)),
735
736 return true;
737}
738
740 statet &state,
741 symex_assignt &symex_assign,
743{
744 // The function application expression f_l1 takes the following arguments:
745 // - result string length (output parameter)
746 // - result string data array (output parameter)
747 // - string to delete substring from
748 // - index of start of substring to delete (inclusive)
749 // - index of end of substring to delete (exclusive)
750 PRECONDITION(f_l1.arguments().size() == 5);
751
752 const auto &f_type = f_l1.function_type();
753 const auto &length_type = f_type.domain().at(0);
754 const auto &char_type = to_pointer_type(f_type.domain().at(1)).base_type();
755
756 const refined_string_exprt &s = to_string_expr(f_l1.arguments().at(2));
757 const auto s_data_opt = try_evaluate_constant_string(state, s.content());
758
759 if(!s_data_opt)
760 {
761 return false;
762 }
763
764 const array_exprt &s_data = s_data_opt->get();
765
766 const auto &start_opt = try_evaluate_constant(state, f_l1.arguments().at(3));
767
768 if(!start_opt)
769 {
770 return false;
771 }
772
773 const mp_integer start = numeric_cast_v<mp_integer>(start_opt->get());
774
775 if(start < 0 || start > s_data.operands().size())
776 {
777 return false;
778 }
779
780 const auto &end_opt = try_evaluate_constant(state, f_l1.arguments().at(4));
781
782 if(!end_opt)
783 {
784 return false;
785 }
786
788
789 if(start > end)
790 {
791 return false;
792 }
793
794 const std::size_t start_index = numeric_cast_v<std::size_t>(start);
795
796 const std::size_t end_index =
797 std::min(numeric_cast_v<std::size_t>(end), s_data.operands().size());
798
799 const std::size_t new_size =
800 s_data.operands().size() - end_index + start_index;
801
803 from_integer(new_size, length_type);
804
806
807 exprt::operandst operands;
808 operands.reserve(new_size);
809
810 operands.insert(
811 operands.end(),
812 s_data.operands().begin(),
813 std::next(s_data.operands().begin(), start_index));
814
815 operands.insert(
816 operands.end(),
817 std::next(s_data.operands().begin(), end_index),
818 s_data.operands().end());
819
820 const array_exprt new_char_array(std::move(operands), new_char_array_type);
821
823 state,
825 to_ssa_expr(f_l1.arguments().at(0)),
827 to_ssa_expr(f_l1.arguments().at(1)),
829
830 return true;
831}
832
834 statet &state,
835 symex_assignt &symex_assign,
837{
838 // The function application expression f_l1 takes the following arguments:
839 // - result string length (output parameter)
840 // - result string data array (output parameter)
841 // - current string
842 // - new length of the string
843 PRECONDITION(f_l1.arguments().size() == 4);
844
845 const auto &f_type = f_l1.function_type();
846 const auto &length_type = f_type.domain().at(0);
847 const auto &char_type = to_pointer_type(f_type.domain().at(1)).base_type();
848
849 const auto &new_length_opt =
850 try_evaluate_constant(state, f_l1.arguments().at(3));
851
852 if(!new_length_opt)
853 {
854 return false;
855 }
856
857 const mp_integer new_length =
859
860 if(new_length < 0)
861 {
862 return false;
863 }
864
866
868 from_integer(new_size, length_type);
869
871
872 exprt::operandst operands;
873
874 if(new_size != 0)
875 {
876 operands.reserve(new_size);
877
878 const refined_string_exprt &s = to_string_expr(f_l1.arguments().at(2));
879 const auto s_data_opt = try_evaluate_constant_string(state, s.content());
880
881 if(!s_data_opt)
882 {
883 return false;
884 }
885
886 const array_exprt &s_data = s_data_opt->get();
887
888 operands.insert(
889 operands.end(),
890 s_data.operands().begin(),
891 std::next(
892 s_data.operands().begin(),
893 std::min(new_size, s_data.operands().size())));
894
895 operands.insert(
896 operands.end(),
897 new_size - std::min(new_size, s_data.operands().size()),
899 }
900
901 const array_exprt new_char_array(std::move(operands), new_char_array_type);
902
904 state,
906 to_ssa_expr(f_l1.arguments().at(0)),
908 to_ssa_expr(f_l1.arguments().at(1)),
910
911 return true;
912}
913
915 statet &state,
916 symex_assignt &symex_assign,
918{
919 // The function application expression f_l1 takes the following arguments:
920 // - result string length (output parameter)
921 // - result string data array (output parameter)
922 // - current string
923 // - index of char to set
924 // - new char
925 PRECONDITION(f_l1.arguments().size() == 5);
926
927 const auto &f_type = f_l1.function_type();
928 const auto &length_type = f_type.domain().at(0);
929 const auto &char_type = to_pointer_type(f_type.domain().at(1)).base_type();
930
931 const refined_string_exprt &s = to_string_expr(f_l1.arguments().at(2));
932 const auto s_data_opt = try_evaluate_constant_string(state, s.content());
933
934 if(!s_data_opt)
935 {
936 return false;
937 }
938
940
941 const auto &index_opt = try_evaluate_constant(state, f_l1.arguments().at(3));
942
943 if(!index_opt)
944 {
945 return false;
946 }
947
948 const mp_integer index = numeric_cast_v<mp_integer>(index_opt->get());
949
950 if(index < 0 || index >= s_data.operands().size())
951 {
952 return false;
953 }
954
955 const auto &new_char_opt =
956 try_evaluate_constant(state, f_l1.arguments().at(4));
957
958 if(!new_char_opt)
959 {
960 return false;
961 }
962
964 from_integer(s_data.operands().size(), length_type);
965
967
968 s_data.operands()[numeric_cast_v<std::size_t>(index)] = new_char_opt->get();
969
971 std::move(s_data.operands()), new_char_array_type);
972
974 state,
976 to_ssa_expr(f_l1.arguments().at(0)),
978 to_ssa_expr(f_l1.arguments().at(1)),
980
981 return true;
982}
983
985 statet &state,
986 symex_assignt &symex_assign,
988 bool to_upper)
989{
990 const auto &f_type = f_l1.function_type();
991 const auto &length_type = f_type.domain().at(0);
992 const auto &char_type = to_pointer_type(f_type.domain().at(1)).base_type();
993
994 const refined_string_exprt &s = to_string_expr(f_l1.arguments().at(2));
995 const auto s_data_opt = try_evaluate_constant_string(state, s.content());
996
997 if(!s_data_opt)
998 return false;
999
1001
1002 auto &operands = string_data.operands();
1003 for(auto &operand : operands)
1004 {
1007
1008 // Can't guarantee matches against non-ASCII characters.
1009 if(character >= 128)
1010 return false;
1011
1012 if(isalpha(character))
1013 {
1014 if(to_upper)
1015 {
1016 if(islower(character))
1018 from_integer(toupper(character), constant_value.type());
1019 }
1020 else
1021 {
1022 if(isupper(character))
1024 from_integer(tolower(character), constant_value.type());
1025 }
1026 }
1027 }
1028
1030 from_integer(operands.size(), length_type);
1031
1033 const array_exprt new_char_array(std::move(operands), new_char_array_type);
1034
1036 state,
1038 to_ssa_expr(f_l1.arguments().at(0)),
1040 to_ssa_expr(f_l1.arguments().at(1)),
1042
1043 return true;
1044}
1045
1047 statet &state,
1048 symex_assignt &symex_assign,
1050{
1051 const auto &f_type = f_l1.function_type();
1052 const auto &length_type = f_type.domain().at(0);
1053 const auto &char_type = to_pointer_type(f_type.domain().at(1)).base_type();
1054
1055 const refined_string_exprt &s = to_string_expr(f_l1.arguments().at(2));
1056 const auto s_data_opt = try_evaluate_constant_string(state, s.content());
1057
1058 if(!s_data_opt)
1059 return false;
1060
1061 auto &new_data = f_l1.arguments().at(4);
1062 auto &old_data = f_l1.arguments().at(3);
1063
1066
1067 // Two main ways to perform a replace: characters or strings.
1068 bool is_single_character = new_data.type().id() == ID_unsignedbv &&
1069 old_data.type().id() == ID_unsignedbv;
1071 {
1072 const auto new_char_pointer = try_evaluate_constant(state, new_data);
1073 const auto old_char_pointer = try_evaluate_constant(state, old_data);
1074
1076 {
1077 return {};
1078 }
1079
1080 characters_to_find.emplace_back(old_char_pointer->get());
1081 characters_to_replace.emplace_back(new_char_pointer->get());
1082 }
1083 else
1084 {
1087
1088 const auto new_char_array_opt =
1090
1091 const auto old_char_array_opt =
1093
1095 {
1096 return {};
1097 }
1098
1099 characters_to_find = old_char_array_opt->get().operands();
1100 characters_to_replace = new_char_array_opt->get().operands();
1101 }
1102
1103 // Copy data, then do initial search for a replace sequence.
1105 auto found_pattern = std::search(
1106 existing_data.operands().begin(),
1107 existing_data.operands().end(),
1108 characters_to_find.begin(),
1109 characters_to_find.end());
1110
1111 // If we've found a match, proceed to perform a replace on all instances.
1112 while(found_pattern != existing_data.operands().end())
1113 {
1114 // Find the difference between our first/last match iterator.
1116
1117 // Erase them.
1119
1120 // Insert our replacement characters, then move the iterator to the end of
1121 // our new sequence.
1122 found_pattern = existing_data.operands().insert(
1124 characters_to_replace.begin(),
1125 characters_to_replace.end()) +
1126 characters_to_replace.size();
1127
1128 // Then search from there for any additional matches.
1129 found_pattern = std::search(
1131 existing_data.operands().end(),
1132 characters_to_find.begin(),
1133 characters_to_find.end());
1134 }
1135
1137 from_integer(existing_data.operands().size(), length_type);
1138
1141 std::move(existing_data.operands()), new_char_array_type);
1142
1144 state,
1146 to_ssa_expr(f_l1.arguments().at(0)),
1148 to_ssa_expr(f_l1.arguments().at(1)),
1150
1151 return true;
1152}
1153
1155 statet &state,
1156 symex_assignt &symex_assign,
1158{
1159 const auto &f_type = f_l1.function_type();
1160 const auto &length_type = f_type.domain().at(0);
1161 const auto &char_type = to_pointer_type(f_type.domain().at(1)).base_type();
1162
1163 const refined_string_exprt &s = to_string_expr(f_l1.arguments().at(2));
1164 const auto s_data_opt = try_evaluate_constant_string(state, s.content());
1165
1166 if(!s_data_opt)
1167 return false;
1168
1169 auto is_not_whitespace = [](const exprt &expr) {
1170 auto character = numeric_cast_v<unsigned int>(to_constant_expr(expr));
1171 return character > ' ';
1172 };
1173
1174 // Note the points where a trim would trim too.
1175 auto &operands = s_data_opt->get().operands();
1176 auto end_iter =
1177 std::find_if(operands.rbegin(), operands.rend(), is_not_whitespace);
1178 auto start_iter =
1179 std::find_if(operands.begin(), operands.end(), is_not_whitespace);
1180
1181 // Then copy in the string with leading/trailing whitespace removed.
1182 // Note: if start_iter == operands.end it means the entire string is
1183 // whitespace, so we'll trim it to be empty anyway.
1185 if(start_iter != operands.end())
1187
1189 from_integer(new_operands.size(), length_type);
1190
1193 std::move(new_operands), new_char_array_type);
1194
1196 state,
1198 to_ssa_expr(f_l1.arguments().at(0)),
1200 to_ssa_expr(f_l1.arguments().at(1)),
1202
1203 return true;
1204}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
const integer_bitvector_typet & to_integer_bitvector_type(const typet &type)
Cast a typet to an integer_bitvector_typet.
bitvector_typet char_type()
Definition c_types.cpp:106
bitvector_typet c_index_type()
Definition c_types.cpp:16
Operator to return the address of an object.
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
Array constructor from list of elements.
Definition std_expr.h:1621
Arrays with given size.
Definition std_types.h:807
framet & top()
Definition call_stack.h:17
A constant literal expression.
Definition std_expr.h:3118
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
Expression in which some part is missing and can be substituted for another expression.
Base class for all expressions.
Definition expr.h:56
std::vector< exprt > operandst
Definition expr.h:58
typet & type()
Return the type of the expression.
Definition expr.h:84
exprt apply(const namespacet &ns, goto_symex_statet &state, exprt expr, bool write) const
Turn an expression expr into a field-sensitive SSA expression.
bool is_divisible(const ssa_exprt &expr, bool disjoined_fields_only) const
Determine whether expr would translate to an atomic SSA expression (returns false) or a composite obj...
bool hidden_function
Definition frame.h:40
Application of (mathematical) function.
unsigned atomic_section_id
Threads.
Definition goto_state.h:76
sharing_mapt< irep_idt, exprt > propagation
Definition goto_state.h:71
value_sett value_set
Uses level 1 names, and is used to do dereferencing.
Definition goto_state.h:51
Central data structure: state.
call_stackt & call_stack()
exprt l2_rename_rvalues(exprt lvalue, const namespacet &ns)
renamedt< exprt, level > rename(exprt expr, const namespacet &ns)
Rewrites symbol expressions in exprt, applying a suffix to each symbol reflecting its most recent ver...
symbol_tablet symbol_table
contains symbols that are minted during symbolic execution, such as dynamically created objects etc.
field_sensitivityt field_sensitivity
symex_targett::sourcet source
std::vector< threadt > threads
virtual void symex_assume(statet &state, const exprt &cond)
Symbolically execute an ASSUME instruction or simulate such an execution for a synthetic assumption.
virtual void symex_atomic_begin(statet &state)
Symbolically execute an ATOMIC_BEGIN instruction.
irep_idt language_mode
language_mode: ID_java, ID_C or another language identifier if we know the source language in use,...
Definition goto_symex.h:242
bool constant_propagate_delete_char_at(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate deleting a character from a string.
bool constant_propagate_set_char_at(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate setting the char at the given index.
bool constant_propagate_assignment_with_side_effects(statet &state, symex_assignt &symex_assign, const exprt &lhs, const exprt &rhs)
Attempt to constant propagate side effects of the assignment (if any)
bool constant_propagate_delete(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate deleting a substring from a string.
static std::optional< std::reference_wrapper< const constant_exprt > > try_evaluate_constant(const statet &state, const exprt &expr)
void constant_propagate_empty_string(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Create an empty string constant.
symex_target_equationt & target
The equation that this execution is building up.
Definition goto_symex.h:267
bool constant_propagate_case_change(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1, bool to_upper)
Attempt to constant propagate case changes, both upper and lower.
virtual void symex_allocate(statet &state, const exprt &lhs, const side_effect_exprt &code)
Symbolically execute an assignment instruction that has an allocate on the right hand side.
bool constant_propagate_integer_to_string(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate converting an integer to a string.
exprt clean_expr(exprt expr, statet &state, bool write)
Clean up an expression.
bool constant_propagate_trim(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate trim operations.
shadow_memoryt shadow_memory
Shadow memory instrumentation API.
Definition goto_symex.h:840
virtual void symex_va_start(statet &, const exprt &lhs, const side_effect_exprt &)
namespacet ns
Initialized just before symbolic execution begins, to point to both outer_symbol_table and the symbol...
Definition goto_symex.h:259
virtual void do_simplify(exprt &expr, const value_sett &value_set)
void symex_assign(statet &state, const exprt &lhs, const exprt &rhs)
Symbolically execute an ASSIGN instruction or simulate such an execution for a synthetic assignment.
const symbolt & get_new_string_data_symbol(statet &state, symex_assignt &symex_assign, const std::string &aux_symbol_name, const ssa_exprt &char_array, const array_exprt &new_char_array)
Installs a new symbol in the symbol table to represent the given character array, and assigns the cha...
void associate_array_to_pointer(statet &state, symex_assignt &symex_assign, const array_exprt &new_char_array, const address_of_exprt &string_data)
Generate array to pointer association primitive.
virtual void symex_cpp_new(statet &state, const exprt &lhs, const side_effect_exprt &code)
Handles side effects of type 'new' for C++ and 'new array' for C++ and Java language modes.
bool constant_propagate_set_length(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate setting the length of a string.
messaget log
The messaget to write log messages to.
Definition goto_symex.h:279
const symex_configt symex_config
The configuration to use for this symbolic execution.
Definition goto_symex.h:186
bool constant_propagate_string_substring(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate getting a substring of a string.
bool constant_propagate_replace(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant proagate character replacement.
bool constant_propagate_string_concat(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate string concatenation.
virtual void symex_atomic_end(statet &state)
Symbolically execute an ATOMIC_END instruction.
void assign_string_constant(statet &state, symex_assignt &symex_assign, const ssa_exprt &length, const constant_exprt &new_length, const ssa_exprt &char_array, const array_exprt &new_char_array)
Assign constant string length and string data given by a char array to given ssa variables.
std::optional< std::reference_wrapper< const array_exprt > > try_evaluate_constant_string(const statet &state, const exprt &content)
Array index operator.
Definition std_expr.h:1470
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition irep.cpp:482
const irep_idt & id() const
Definition irep.h:388
mstreamt & debug() const
Definition message.h:421
void conditional_output(mstreamt &mstream, const std::function< void(mstreamt &)> &output_generator) const
Generate output to message_stream using output_generator if the configured verbosity is at least as h...
Definition message.cpp:139
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
const exprt & content() const
An expression containing a side effect.
Definition std_code.h:1450
Expression providing an SSA-renamed symbol of expressions.
Definition ssa_expr.h:17
Expression to hold a symbol (variable)
Definition std_expr.h:131
bool has_symbol(const irep_idt &name) const
Check whether a symbol exists in the symbol table.
const symbolt & lookup_ref(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
Symbol table entry.
Definition symbol.h:28
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition symbol.cpp:121
Functor for symex assignment.
State type in value_set_domaint, used in value-set analysis and goto-symex.
Definition value_set.h:43
int isalpha(int c)
Definition ctype.c:9
int islower(int c)
Definition ctype.c:34
int toupper(int c)
Definition ctype.c:134
int tolower(int c)
Definition ctype.c:109
int isupper(int c)
Definition ctype.c:90
Expression skeleton.
symbolt & get_fresh_aux_symbol(const typet &type, const std::string &name_prefix, const std::string &basename_prefix, const source_locationt &source_location, const irep_idt &symbol_mode, const namespacet &ns, symbol_table_baset &symbol_table)
Installs a fresh-named symbol with respect to the given namespace ns with the requested name pattern ...
Fresh auxiliary symbol creation.
static std::string get_alnum_string(const array_exprt &char_array)
Maps the given array expression containing constant characters to a string containing only alphanumer...
Symbolic Execution.
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
API to expression classes for 'mathematical' expressions.
const function_application_exprt & to_function_application_expr(const exprt &expr)
Cast an exprt to a function_application_exprt.
Mathematical types.
const mathematical_function_typet & to_mathematical_function_type(const typet &type)
Cast a typet to a mathematical_function_typet.
const std::string integer2string(const mp_integer &n, unsigned base)
Definition mp_arith.cpp:103
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Pointer Logic.
std::optional< std::reference_wrapper< const array_exprt > > try_get_string_data_array(const exprt &content, const namespacet &ns)
Get char sequence from content field of a refined string expression.
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:525
#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 PRECONDITION(CONDITION)
Definition invariant.h:463
#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
bool is_ssa_expr(const exprt &expr)
Definition ssa_expr.h:125
const ssa_exprt & to_ssa_expr(const exprt &expr)
Cast a generic exprt to an ssa_exprt.
Definition ssa_expr.h:145
side_effect_exprt & to_side_effect_expr(exprt &expr)
Definition std_code.h:1506
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 array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:888
String expressions for the string solver.
refined_string_exprt & to_string_expr(exprt &expr)
std::string escape_non_alnum(const std::string &to_escape)
Replace non-alphanumeric characters with _xx escapes, where xx are hex digits.
goto_programt::const_targett pc
Symbolic Execution of assignments.