@@ -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
{
@@ -114,26 +122,35 @@ void local_safe_pointerst::operator()(const goto_programt &goto_program)
114
122
// Possible checks:
115
123
case ASSUME:
116
124
{
117
- const exprt *checked_expr;
118
- if ((checked_expr = get_null_checked_expr (instruction.guard )) != nullptr )
125
+ if (auto assume_check = get_null_checked_expr (instruction.guard ))
119
126
{
120
- checked_expressions.insert (*checked_expr);
127
+ if (assume_check->checked_when_taken )
128
+ checked_expressions.insert (assume_check->checked_expr );
121
129
}
122
130
break ;
123
131
}
124
132
125
133
case GOTO:
126
134
if (!instruction.is_backwards_goto ())
127
135
{
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;
136
+ // Copy current state to GOTO target:
137
+
138
+ auto target_emplace_result =
139
+ non_null_expressions.emplace (
140
+ instruction.get_target ()->location_number , checked_expressions);
141
+ INVARIANT (
142
+ target_emplace_result.second ,
143
+ " this is a forward analysis; target should not be visited yet" );
134
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:
135
149
if (conditional_check->checked_when_taken )
136
- taken_checked_expressions.insert (conditional_check->checked_expr );
150
+ {gh
151
+ target_emplace_result.first ->second .insert (
152
+ conditional_check->checked_expr );
153
+ }
137
154
else
138
155
checked_expressions.insert (conditional_check->checked_expr );
139
156
@@ -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