@@ -13,66 +13,61 @@ Author: Diffblue Ltd
1313
1414#include < util/expr_iterator.h>
1515#include < util/format_expr.h>
16+ #include < util/base_type.h>
1617
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`
4220struct goto_null_checkt
4321{
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.
4625 bool checked_when_taken;
4726
4827 // / Null-tested pointer expression
4928 exprt checked_expr;
5029};
5130
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
5433// / \return a `goto_null_checkt` indicating what expression is tested and
5534// / whether the check applies on the taken or not-taken branch, or an empty
5635// / 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)
5937{
60- exprt normalized_guard = goto_guard ;
38+ exprt normalized_expr = expr ;
6139 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)
6341 {
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 ();
6644 else
67- normalized_guard .id (ID_notequal);
45+ normalized_expr .id (ID_notequal);
6846 checked_when_taken = !checked_when_taken;
6947 }
7048
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 {};
7671}
7772
7873// / Compute safe dereference expressions for a given GOTO program. This
@@ -82,7 +77,8 @@ get_conditional_checked_expr(const exprt &goto_guard)
8277// / \param goto_program: program to analyse
8378void local_safe_pointerst::operator ()(const goto_programt &goto_program)
8479{
85- std::set<exprt> checked_expressions;
80+ std::set<exprt, base_type_comparet> checked_expressions (
81+ base_type_comparet{ns});
8682
8783 for (const auto &instruction : goto_program.instructions )
8884 {
@@ -91,11 +87,23 @@ void local_safe_pointerst::operator()(const goto_programt &goto_program)
9187 checked_expressions.clear ();
9288 // Retrieve working set for forward GOTOs:
9389 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+ }
95100
96101 // Save the working set at this program point:
97102 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+ }
99107
100108 switch (instruction.type )
101109 {
@@ -114,26 +122,35 @@ void local_safe_pointerst::operator()(const goto_programt &goto_program)
114122 // Possible checks:
115123 case ASSUME:
116124 {
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 ))
119126 {
120- checked_expressions.insert (*checked_expr);
127+ if (assume_check->checked_when_taken )
128+ checked_expressions.insert (assume_check->checked_expr );
121129 }
122130 break ;
123131 }
124132
125133 case GOTO:
126134 if (!instruction.is_backwards_goto ())
127135 {
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" );
134144
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:
135149 if (conditional_check->checked_when_taken )
136- taken_checked_expressions.insert (conditional_check->checked_expr );
150+ {
151+ target_emplace_result.first ->second .insert (
152+ conditional_check->checked_expr );
153+ }
137154 else
138155 checked_expressions.insert (conditional_check->checked_expr );
139156
@@ -157,7 +174,7 @@ void local_safe_pointerst::operator()(const goto_programt &goto_program)
157174// / operator())
158175// / \param ns: global namespace
159176void 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)
161178{
162179 forall_goto_program_instructions (i_it, goto_program)
163180 {
@@ -199,7 +216,7 @@ void local_safe_pointerst::output(
199216// / operator())
200217// / \param ns: global namespace
201218void 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)
203220{
204221 forall_goto_program_instructions (i_it, goto_program)
205222 {
@@ -251,3 +268,12 @@ bool local_safe_pointerst::is_non_null_at_program_point(
251268 tocheck = &tocheck->op0 ();
252269 return findit->second .count (*tocheck) != 0 ;
253270}
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