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