@@ -13,66 +13,61 @@ Author: Diffblue Ltd
13
13
14
14
#include < util/expr_iterator.h>
15
15
#include < util/format_expr.h>
16
+ #include < util/base_type.h>
16
17
17
- // / If `expr` is of the form `x != nullptr`, return x. Otherwise return null
18
- static const exprt *get_null_checked_expr (const exprt &expr)
19
- {
20
- if (expr.id () == ID_notequal)
21
- {
22
- const exprt *op0 = &expr.op0 (), *op1 = &expr.op1 ();
23
- if (op0->type ().id () == ID_pointer &&
24
- *op0 == null_pointer_exprt (to_pointer_type (op0->type ())))
25
- {
26
- std::swap (op0, op1);
27
- }
28
-
29
- if (op1->type ().id () == ID_pointer &&
30
- *op1 == null_pointer_exprt (to_pointer_type (op1->type ())))
31
- {
32
- while (op0->id () == ID_typecast)
33
- op0 = &op0->op0 ();
34
- return op0;
35
- }
36
- }
37
-
38
- return nullptr ;
39
- }
40
-
41
- // / Return structure for `get_conditional_checked_expr`
18
+ // / Return structure for `get_null_checked_expr` and
19
+ // / `get_conditional_checked_expr`
42
20
struct goto_null_checkt
43
21
{
44
- // / If true, the given GOTO tests that a pointer expression is non-null on the
45
- // / taken branch; otherwise, on the not-taken branch.
22
+ // / If true, the given GOTO/ASSUME tests that a pointer expression is non-null
23
+ // / on the taken branch or passing case; otherwise, on the not-taken branch
24
+ // / or on failure.
46
25
bool checked_when_taken;
47
26
48
27
// / Null-tested pointer expression
49
28
exprt checked_expr;
50
29
};
51
30
52
- // / Check if a GOTO guard expression tests if a pointer is null
53
- // / \param goto_guard : expression to check
31
+ // / Check if `expr` tests if a pointer is null
32
+ // / \param expr : expression to check
54
33
// / \return a `goto_null_checkt` indicating what expression is tested and
55
34
// / whether the check applies on the taken or not-taken branch, or an empty
56
35
// / optionalt if this isn't a null check.
57
- static optionalt<goto_null_checkt>
58
- get_conditional_checked_expr (const exprt &goto_guard)
36
+ static optionalt<goto_null_checkt> get_null_checked_expr (const exprt &expr)
59
37
{
60
- exprt normalized_guard = goto_guard ;
38
+ exprt normalized_expr = expr ;
61
39
bool checked_when_taken = true ;
62
- while (normalized_guard .id () == ID_not || normalized_guard .id () == ID_equal)
40
+ while (normalized_expr .id () == ID_not || normalized_expr .id () == ID_equal)
63
41
{
64
- if (normalized_guard .id () == ID_not)
65
- normalized_guard = normalized_guard .op0 ();
42
+ if (normalized_expr .id () == ID_not)
43
+ normalized_expr = normalized_expr .op0 ();
66
44
else
67
- normalized_guard .id (ID_notequal);
45
+ normalized_expr .id (ID_notequal);
68
46
checked_when_taken = !checked_when_taken;
69
47
}
70
48
71
- const exprt *checked_expr = get_null_checked_expr (normalized_guard);
72
- if (!checked_expr)
73
- return {};
74
- else
75
- return goto_null_checkt { checked_when_taken, *checked_expr };
49
+ if (normalized_expr.id () == ID_notequal)
50
+ {
51
+ const exprt *op0 = &normalized_expr.op0 (), *op1 = &normalized_expr.op1 ();
52
+ while (op0->id () == ID_typecast)
53
+ op0 = &op0->op0 ();
54
+ while (op1->id () == ID_typecast)
55
+ op1 = &op1->op0 ();
56
+
57
+ if (op0->type ().id () == ID_pointer &&
58
+ *op0 == null_pointer_exprt (to_pointer_type (op0->type ())))
59
+ {
60
+ std::swap (op0, op1);
61
+ }
62
+
63
+ if (op1->type ().id () == ID_pointer &&
64
+ *op1 == null_pointer_exprt (to_pointer_type (op1->type ())))
65
+ {
66
+ return { { checked_when_taken, *op0 } };
67
+ }
68
+ }
69
+
70
+ return {};
76
71
}
77
72
78
73
// / Compute safe dereference expressions for a given GOTO program. This
@@ -82,7 +77,8 @@ get_conditional_checked_expr(const exprt &goto_guard)
82
77
// / \param goto_program: program to analyse
83
78
void local_safe_pointerst::operator ()(const goto_programt &goto_program)
84
79
{
85
- std::set<exprt> checked_expressions;
80
+ std::set<exprt, base_type_comparet> checked_expressions (
81
+ base_type_comparet{ns});
86
82
87
83
for (const auto &instruction : goto_program.instructions )
88
84
{
@@ -91,11 +87,23 @@ void local_safe_pointerst::operator()(const goto_programt &goto_program)
91
87
checked_expressions.clear ();
92
88
// Retrieve working set for forward GOTOs:
93
89
else if (instruction.is_target ())
94
- checked_expressions = non_null_expressions[instruction.location_number ];
90
+ {
91
+ auto findit = non_null_expressions.find (instruction.location_number );
92
+ if (findit != non_null_expressions.end ())
93
+ checked_expressions = findit->second ;
94
+ else
95
+ {
96
+ checked_expressions =
97
+ std::set<exprt, base_type_comparet>(base_type_comparet{ns});
98
+ }
99
+ }
95
100
96
101
// Save the working set at this program point:
97
102
if (!checked_expressions.empty ())
98
- non_null_expressions[instruction.location_number ] = checked_expressions;
103
+ {
104
+ non_null_expressions.emplace (
105
+ instruction.location_number , checked_expressions);
106
+ }
99
107
100
108
switch (instruction.type )
101
109
{
@@ -113,35 +121,44 @@ void local_safe_pointerst::operator()(const goto_programt &goto_program)
113
121
114
122
// Possible checks:
115
123
case ASSUME:
124
+ if (auto assume_check = get_null_checked_expr (instruction.guard ))
116
125
{
117
- const exprt *checked_expr;
118
- if ((checked_expr = get_null_checked_expr (instruction.guard )) != nullptr )
119
- {
120
- checked_expressions.insert (*checked_expr);
121
- }
122
- break ;
126
+ if (assume_check->checked_when_taken )
127
+ checked_expressions.insert (assume_check->checked_expr );
123
128
}
124
129
130
+ break ;
131
+
125
132
case GOTO:
126
133
if (!instruction.is_backwards_goto ())
127
134
{
128
- if (auto conditional_check =
129
- get_conditional_checked_expr (instruction.guard ))
130
- {
131
- auto &taken_checked_expressions =
132
- non_null_expressions[instruction.get_target ()->location_number ];
133
- taken_checked_expressions = checked_expressions;
135
+ // Copy current state to GOTO target:
134
136
135
- if (conditional_check->checked_when_taken )
136
- taken_checked_expressions.insert (conditional_check->checked_expr );
137
- else
138
- checked_expressions.insert (conditional_check->checked_expr );
137
+ auto target_emplace_result =
138
+ non_null_expressions.emplace (
139
+ instruction.get_target ()->location_number , checked_expressions);
139
140
140
- break ;
141
+ // If the target already has a state entry then it is a control-flow
142
+ // merge point and everything will be assumed maybe-null in any case.
143
+ if (target_emplace_result.second )
144
+ {
145
+ if (auto conditional_check = get_null_checked_expr (instruction.guard ))
146
+ {
147
+ // Add the GOTO condition to either the target or current state,
148
+ // as appropriate:
149
+ if (conditional_check->checked_when_taken )
150
+ {
151
+ target_emplace_result.first ->second .insert (
152
+ conditional_check->checked_expr );
153
+ }
154
+ else
155
+ checked_expressions.insert (conditional_check->checked_expr );
156
+ }
141
157
}
142
- // Otherwise fall through to...
143
158
}
144
159
160
+ break ;
161
+
145
162
default :
146
163
// Pessimistically assume all other instructions might overwrite any
147
164
// pointer with a possibly-null value.
@@ -157,7 +174,7 @@ void local_safe_pointerst::operator()(const goto_programt &goto_program)
157
174
// / operator())
158
175
// / \param ns: global namespace
159
176
void local_safe_pointerst::output (
160
- std::ostream &out, const goto_programt &goto_program, const namespacet &ns )
177
+ std::ostream &out, const goto_programt &goto_program)
161
178
{
162
179
forall_goto_program_instructions (i_it, goto_program)
163
180
{
@@ -199,7 +216,7 @@ void local_safe_pointerst::output(
199
216
// / operator())
200
217
// / \param ns: global namespace
201
218
void local_safe_pointerst::output_safe_dereferences (
202
- std::ostream &out, const goto_programt &goto_program, const namespacet &ns )
219
+ std::ostream &out, const goto_programt &goto_program)
203
220
{
204
221
forall_goto_program_instructions (i_it, goto_program)
205
222
{
@@ -251,3 +268,12 @@ bool local_safe_pointerst::is_non_null_at_program_point(
251
268
tocheck = &tocheck->op0 ();
252
269
return findit->second .count (*tocheck) != 0 ;
253
270
}
271
+
272
+ bool local_safe_pointerst::base_type_comparet::operator ()(
273
+ const exprt &e1 , const exprt &e2 ) const
274
+ {
275
+ if (base_type_eq (e1 , e2 , ns))
276
+ return false ;
277
+ else
278
+ return e1 < e2 ;
279
+ }
0 commit comments