Skip to content

Commit f9a7807

Browse files
authored
Merge pull request #8544 from diffblue/goto-check-c-is-assigned
fix enum-range check for LHSs
2 parents b71084c + 53454fd commit f9a7807

File tree

3 files changed

+43
-48
lines changed

3 files changed

+43
-48
lines changed
+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
typedef enum my_enum
1+
enum my_enum
22
{
33
A = 1,
44
B = 2
@@ -8,10 +8,10 @@ int my_array[10];
88
int main()
99
{
1010
// should fail
11-
(enum my_enumt)3;
11+
(enum my_enum)3;
1212

1313
// should fail
14-
my_array[(enum my_enumt)4] = 10;
14+
my_array[(enum my_enum)4] = 10;
1515

1616
return 0;
1717
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
KNOWNBUG
1+
CORE
22
enum_lhs.c
33
--enum-range-check
4-
^\[main\.enum-range-check\.2\] line 14 enum range check in \(my_enumt\)4: FAILURE$
4+
^\[main\.enum-range-check\.2\] line 14 enum range check in \(enum my_enum\)4: FAILURE$
55
^EXIT=10$
66
^SIGNAL=0$
77
--
88
--
9-
The conversion to enum on the LHS should fail the enum-range check, but
10-
doesn't.
11-

src/ansi-c/goto-conversion/goto_check_c.cpp

+38-40
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,13 @@ class goto_check_ct
157157
/// guard.
158158
/// \param expr: the expression to be checked
159159
/// \param guard: the condition for when the check should be made
160-
void check_rec(const exprt &expr, const guardt &guard);
160+
/// \param is_assigned: the expression is assigned to
161+
void check_rec(const exprt &expr, const guardt &guard, bool is_assigned);
161162

162163
/// Initiate the recursively analysis of \p expr with its `guard' set to TRUE.
163164
/// \param expr: the expression to be checked
164-
void check(const exprt &expr);
165+
/// \param is_assigned: the expression is assigned to
166+
void check(const exprt &expr, bool is_assigned);
165167

166168
struct conditiont
167169
{
@@ -183,7 +185,7 @@ class goto_check_ct
183185
void float_div_by_zero_check(const div_exprt &, const guardt &);
184186
void mod_by_zero_check(const mod_exprt &, const guardt &);
185187
void mod_overflow_check(const mod_exprt &, const guardt &);
186-
void enum_range_check(const exprt &, const guardt &);
188+
void enum_range_check(const exprt &, const guardt &, bool is_assigned);
187189
void undefined_shift_check(const shift_exprt &, const guardt &);
188190
void pointer_rel_check(const binary_exprt &, const guardt &);
189191
void pointer_overflow_check(const exprt &, const guardt &);
@@ -537,11 +539,17 @@ void goto_check_ct::float_div_by_zero_check(
537539
guard);
538540
}
539541

540-
void goto_check_ct::enum_range_check(const exprt &expr, const guardt &guard)
542+
void goto_check_ct::enum_range_check(
543+
const exprt &expr,
544+
const guardt &guard,
545+
bool is_assigned)
541546
{
542547
if(!enable_enum_range_check)
543548
return;
544549

550+
if(is_assigned)
551+
return; // not in range yet
552+
545553
// we might be looking at a lowered enum_is_in_range_exprt, skip over these
546554
const auto &pragmas = expr.source_location().get_pragmas();
547555
for(const auto &d : pragmas)
@@ -1807,13 +1815,13 @@ void goto_check_ct::check_rec_address(const exprt &expr, const guardt &guard)
18071815

18081816
if(expr.id() == ID_dereference)
18091817
{
1810-
check_rec(to_dereference_expr(expr).pointer(), guard);
1818+
check_rec(to_dereference_expr(expr).pointer(), guard, false);
18111819
}
18121820
else if(expr.id() == ID_index)
18131821
{
18141822
const index_exprt &index_expr = to_index_expr(expr);
18151823
check_rec_address(index_expr.array(), guard);
1816-
check_rec(index_expr.index(), guard);
1824+
check_rec(index_expr.index(), guard, false);
18171825
}
18181826
else
18191827
{
@@ -1843,7 +1851,7 @@ void goto_check_ct::check_rec_logical_op(const exprt &expr, const guardt &guard)
18431851
return guard(implication(conjunction(constraints), expr));
18441852
};
18451853

1846-
check_rec(op, new_guard);
1854+
check_rec(op, new_guard, false);
18471855

18481856
constraints.push_back(expr.id() == ID_or ? boolean_negate(op) : op);
18491857
}
@@ -1855,20 +1863,20 @@ void goto_check_ct::check_rec_if(const if_exprt &if_expr, const guardt &guard)
18551863
if_expr.cond().is_boolean(),
18561864
"first argument of if must be boolean, but got " + if_expr.cond().pretty());
18571865

1858-
check_rec(if_expr.cond(), guard);
1866+
check_rec(if_expr.cond(), guard, false);
18591867

18601868
{
18611869
auto new_guard = [&guard, &if_expr](exprt expr) {
18621870
return guard(implication(if_expr.cond(), std::move(expr)));
18631871
};
1864-
check_rec(if_expr.true_case(), new_guard);
1872+
check_rec(if_expr.true_case(), new_guard, false);
18651873
}
18661874

18671875
{
18681876
auto new_guard = [&guard, &if_expr](exprt expr) {
18691877
return guard(implication(not_exprt(if_expr.cond()), std::move(expr)));
18701878
};
1871-
check_rec(if_expr.false_case(), new_guard);
1879+
check_rec(if_expr.false_case(), new_guard, false);
18721880
}
18731881
}
18741882

@@ -1878,7 +1886,7 @@ bool goto_check_ct::check_rec_member(
18781886
{
18791887
const dereference_exprt &deref = to_dereference_expr(member.struct_op());
18801888

1881-
check_rec(deref.pointer(), guard);
1889+
check_rec(deref.pointer(), guard, false);
18821890

18831891
// avoid building the following expressions when pointer_validity_check
18841892
// would return immediately anyway
@@ -1969,7 +1977,10 @@ void goto_check_ct::check_rec_arithmetic_op(
19691977
}
19701978
}
19711979

1972-
void goto_check_ct::check_rec(const exprt &expr, const guardt &guard)
1980+
void goto_check_ct::check_rec(
1981+
const exprt &expr,
1982+
const guardt &guard,
1983+
bool is_assigned)
19731984
{
19741985
if(expr.id() == ID_exists || expr.id() == ID_forall)
19751986
{
@@ -1980,7 +1991,7 @@ void goto_check_ct::check_rec(const exprt &expr, const guardt &guard)
19801991
return guard(forall_exprt(quantifier_expr.symbol(), expr));
19811992
};
19821993

1983-
check_rec(quantifier_expr.where(), new_guard);
1994+
check_rec(quantifier_expr.where(), new_guard, false);
19841995
return;
19851996
}
19861997
else if(expr.id() == ID_address_of)
@@ -2007,10 +2018,10 @@ void goto_check_ct::check_rec(const exprt &expr, const guardt &guard)
20072018
}
20082019

20092020
for(const auto &op : expr.operands())
2010-
check_rec(op, guard);
2021+
check_rec(op, guard, false);
20112022

20122023
if(expr.type().id() == ID_c_enum_tag)
2013-
enum_range_check(expr, guard);
2024+
enum_range_check(expr, guard, is_assigned);
20142025

20152026
if(expr.id() == ID_index)
20162027
{
@@ -2059,9 +2070,9 @@ void goto_check_ct::check_rec(const exprt &expr, const guardt &guard)
20592070
}
20602071
}
20612072

2062-
void goto_check_ct::check(const exprt &expr)
2073+
void goto_check_ct::check(const exprt &expr, bool is_assigned)
20632074
{
2064-
check_rec(expr, identity);
2075+
check_rec(expr, identity, is_assigned);
20652076
}
20662077

20672078
void goto_check_ct::memory_leak_check(const irep_idt &function_id)
@@ -2151,7 +2162,7 @@ void goto_check_ct::goto_check(
21512162

21522163
if(i.has_condition())
21532164
{
2154-
check(i.condition());
2165+
check(i.condition(), false);
21552166
}
21562167

21572168
// magic ERROR label?
@@ -2184,45 +2195,32 @@ void goto_check_ct::goto_check(
21842195

21852196
if(statement == ID_expression)
21862197
{
2187-
check(code);
2198+
check(code, false);
21882199
}
21892200
else if(statement == ID_printf)
21902201
{
21912202
for(const auto &op : code.operands())
2192-
check(op);
2203+
check(op, false);
21932204
}
21942205
}
21952206
else if(i.is_assign())
21962207
{
21972208
const exprt &assign_lhs = i.assign_lhs();
21982209
const exprt &assign_rhs = i.assign_rhs();
21992210

2200-
// Disable enum range checks for left-hand sides as their values are yet
2201-
// to be set (by this assignment).
2202-
{
2203-
flag_overridet resetter(i.source_location());
2204-
resetter.disable_flag(enable_enum_range_check, "enum_range_check");
2205-
check(assign_lhs);
2206-
}
2207-
2208-
check(assign_rhs);
2211+
check(assign_lhs, true);
2212+
check(assign_rhs, false);
22092213

22102214
// the LHS might invalidate any assertion
22112215
invalidate(assign_lhs);
22122216
}
22132217
else if(i.is_function_call())
22142218
{
2215-
// Disable enum range checks for left-hand sides as their values are yet
2216-
// to be set (by this function call).
2217-
{
2218-
flag_overridet resetter(i.source_location());
2219-
resetter.disable_flag(enable_enum_range_check, "enum_range_check");
2220-
check(i.call_lhs());
2221-
}
2222-
check(i.call_function());
2219+
check(i.call_lhs(), true);
2220+
check(i.call_function(), false);
22232221

22242222
for(const auto &arg : i.call_arguments())
2225-
check(arg);
2223+
check(arg, false);
22262224

22272225
check_shadow_memory_api_calls(i);
22282226

@@ -2231,7 +2229,7 @@ void goto_check_ct::goto_check(
22312229
}
22322230
else if(i.is_set_return_value())
22332231
{
2234-
check(i.return_value());
2232+
check(i.return_value(), false);
22352233
// the return value invalidate any assertion
22362234
invalidate(i.return_value());
22372235
}
@@ -2342,7 +2340,7 @@ void goto_check_ct::check_shadow_memory_api_calls(
23422340
{
23432341
const exprt &expr = i.call_arguments()[0];
23442342
PRECONDITION(expr.type().id() == ID_pointer);
2345-
check(dereference_exprt(expr));
2343+
check(dereference_exprt(expr), false);
23462344
}
23472345
}
23482346

0 commit comments

Comments
 (0)