10
10
// / Symbolic Execution
11
11
12
12
#include " goto_symex.h"
13
+ #include " goto_symex_is_constant.h"
13
14
14
15
#include < algorithm>
15
16
19
20
#include < util/pointer_offset_size.h>
20
21
#include < util/std_expr.h>
21
22
23
+ #include < pointer-analysis/value_set_dereference.h>
22
24
#include < util/simplify_expr.h>
23
25
24
26
void goto_symext::apply_goto_condition (
@@ -65,6 +67,161 @@ void goto_symext::apply_goto_condition(
65
67
}
66
68
}
67
69
70
+ // / Try to evaluate a simple pointer comparison.
71
+ // / \param operation: ID_equal or ID_not_equal
72
+ // / \param symbol_expr: The symbol expression in the condition
73
+ // / \param other_operand: The other expression in the condition - must pass
74
+ // / goto_symex_is_constant, and since it is pointer-typed it must therefore
75
+ // / be an address of expression, a typecast of an address of expression or a
76
+ // / null pointer
77
+ // / \param value_set: The value-set for looking up what the symbol can point to
78
+ // / \param language_mode: The language mode
79
+ // / \param ns: A namespace
80
+ // / \return If we were able to evaluate the condition as true or false then we
81
+ // / return that, otherwise we return an empty optionalt
82
+ static optionalt<renamedt<exprt, L2>> try_evaluate_pointer_comparison (
83
+ irep_idt operation,
84
+ const symbol_exprt &symbol_expr,
85
+ const exprt &other_operand,
86
+ const value_sett &value_set,
87
+ const irep_idt language_mode,
88
+ const namespacet &ns)
89
+ {
90
+ const constant_exprt *constant_expr =
91
+ expr_try_dynamic_cast<constant_exprt>(other_operand);
92
+
93
+ INVARIANT (
94
+ skip_typecast (other_operand).id () == ID_address_of ||
95
+ (constant_expr && constant_expr->get_value () == ID_NULL),
96
+ " An expression that passes goto_symex_is_constant and has "
97
+ " pointer-type must be an address of expression (possibly with some "
98
+ " typecasts) or a null pointer" );
99
+
100
+ const ssa_exprt *ssa_symbol_expr =
101
+ expr_try_dynamic_cast<ssa_exprt>(symbol_expr);
102
+
103
+ value_setst::valuest value_set_elements;
104
+ value_set.get_value_set (
105
+ ssa_symbol_expr->get_l1_object (), value_set_elements, ns);
106
+
107
+ bool constant_found = false ;
108
+
109
+ for (const auto &value_set_element : value_set_elements)
110
+ {
111
+ if (
112
+ value_set_element.id () == ID_unknown ||
113
+ value_set_element.id () == ID_invalid)
114
+ {
115
+ // If ID_unknown or ID_invalid are in the value-set then we can't
116
+ // conclude anything about it
117
+ return {};
118
+ }
119
+
120
+ if (!constant_found)
121
+ {
122
+ if (value_set_dereferencet::should_ignore_value (
123
+ value_set_element, false , language_mode))
124
+ {
125
+ continue ;
126
+ }
127
+
128
+ value_set_dereferencet::valuet value =
129
+ value_set_dereferencet::build_reference_to (
130
+ value_set_element, symbol_expr, ns);
131
+
132
+ if (value.pointer == other_operand)
133
+ {
134
+ constant_found = true ;
135
+ // We can't break because we have to make sure we find any instances of
136
+ // ID_unknown or ID_invalid
137
+ }
138
+ }
139
+ }
140
+
141
+ if (!constant_found)
142
+ {
143
+ // The symbol cannot possibly have the value \p other_operand because it
144
+ // isn't in the symbol's value-set
145
+ return operation == ID_equal ? make_renamed<L2>(false_exprt{})
146
+ : make_renamed<L2>(true_exprt{});
147
+ }
148
+ else if (value_set_elements.size () == 1 )
149
+ {
150
+ // The symbol must have the value \p other_operand because it is the only
151
+ // thing in the symbol's value-set
152
+ return operation == ID_equal ? make_renamed<L2>(true_exprt{})
153
+ : make_renamed<L2>(false_exprt{});
154
+ }
155
+ else
156
+ {
157
+ return {};
158
+ }
159
+ }
160
+
161
+ // / Check if we have a simple pointer comparison, and if so try to evaluate it.
162
+ // / \param renamed_expr: The L2-renamed expression to check
163
+ // / \param value_set: The value-set for looking up what the symbol can point to
164
+ // / \param language_mode: The language mode
165
+ // / \param ns: A namespace
166
+ // / \return If we were able to evaluate the condition as true or false then we
167
+ // / return that, otherwise we return an empty optionalt
168
+ static optionalt<renamedt<exprt, L2>> try_evaluate_pointer_comparison (
169
+ const renamedt<exprt, L2> &renamed_expr,
170
+ const value_sett &value_set,
171
+ const irep_idt language_mode,
172
+ const namespacet &ns)
173
+ {
174
+ const exprt &expr = renamed_expr.get ();
175
+
176
+ if (expr.id () != ID_equal && expr.id () != ID_notequal)
177
+ return {};
178
+
179
+ if (!can_cast_type<pointer_typet>(expr.op0 ().type ()))
180
+ return {};
181
+
182
+ exprt lhs = expr.op0 (), rhs = expr.op1 ();
183
+ if (can_cast_expr<symbol_exprt>(rhs))
184
+ std::swap (lhs, rhs);
185
+
186
+ const symbol_exprt *symbol_expr_lhs =
187
+ expr_try_dynamic_cast<symbol_exprt>(lhs);
188
+
189
+ if (!symbol_expr_lhs)
190
+ return {};
191
+
192
+ if (!goto_symex_is_constantt ()(rhs))
193
+ return {};
194
+
195
+ return try_evaluate_pointer_comparison (
196
+ expr.id (), *symbol_expr_lhs, rhs, value_set, language_mode, ns);
197
+ }
198
+
199
+ // / Try to evaluate pointer comparisons where they can be trivially determined
200
+ // / using the value-set. This is optional as all it does is allow symex to
201
+ // / resolve some comparisons itself and therefore create a simpler formula for
202
+ // / the SAT solver.
203
+ // / \param [in,out] condition: An L2-renamed expression with boolean type
204
+ // / \param value_set: The value-set for determining what pointer-typed symbols
205
+ // / might possibly point to
206
+ // / \param language_mode: The language mode
207
+ // / \param ns: A namespace
208
+ // / \return The possibly modified condition
209
+ static renamedt<exprt, L2> try_evaluate_pointer_comparisons (
210
+ renamedt<exprt, L2> condition,
211
+ const value_sett &value_set,
212
+ const irep_idt language_mode,
213
+ const namespacet &ns)
214
+ {
215
+ selectively_mutate (
216
+ condition,
217
+ [&value_set, &language_mode, &ns](const renamedt<exprt, L2> &expr) {
218
+ return try_evaluate_pointer_comparison (
219
+ expr, value_set, language_mode, ns);
220
+ });
221
+
222
+ return condition;
223
+ }
224
+
68
225
void goto_symext::symex_goto (statet &state)
69
226
{
70
227
const goto_programt::instructiont &instruction=*state.source .pc ;
@@ -73,6 +230,8 @@ void goto_symext::symex_goto(statet &state)
73
230
clean_expr (new_guard, state, false );
74
231
75
232
renamedt<exprt, L2> renamed_guard = state.rename (std::move (new_guard), ns);
233
+ renamed_guard = try_evaluate_pointer_comparisons (
234
+ std::move (renamed_guard), state.value_set , language_mode, ns);
76
235
if (symex_config.simplify_opt )
77
236
renamed_guard.simplify (ns);
78
237
new_guard = renamed_guard.get ();
0 commit comments