Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix enum-range check for LHSs #8544

Merged
merged 1 commit into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions regression/cbmc/enum_is_in_range/enum_lhs.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
typedef enum my_enum
enum my_enum
{
A = 1,
B = 2
Expand All @@ -8,10 +8,10 @@ int my_array[10];
int main()
{
// should fail
(enum my_enumt)3;
(enum my_enum)3;

// should fail
my_array[(enum my_enumt)4] = 10;
my_array[(enum my_enum)4] = 10;

return 0;
}
7 changes: 2 additions & 5 deletions regression/cbmc/enum_is_in_range/enum_lhs.desc
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
KNOWNBUG
CORE
enum_lhs.c
--enum-range-check
^\[main\.enum-range-check\.2\] line 14 enum range check in \(my_enumt\)4: FAILURE$
^\[main\.enum-range-check\.2\] line 14 enum range check in \(enum my_enum\)4: FAILURE$
^EXIT=10$
^SIGNAL=0$
--
--
The conversion to enum on the LHS should fail the enum-range check, but
doesn't.

78 changes: 38 additions & 40 deletions src/ansi-c/goto-conversion/goto_check_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,13 @@
/// guard.
/// \param expr: the expression to be checked
/// \param guard: the condition for when the check should be made
void check_rec(const exprt &expr, const guardt &guard);
/// \param is_assigned: the expression is assigned to
void check_rec(const exprt &expr, const guardt &guard, bool is_assigned);

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

Check warning on line 166 in src/ansi-c/goto-conversion/goto_check_c.cpp

View check run for this annotation

Codecov / codecov/patch

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

Added line #L166 was not covered by tests

struct conditiont
{
Expand All @@ -183,7 +185,7 @@
void float_div_by_zero_check(const div_exprt &, const guardt &);
void mod_by_zero_check(const mod_exprt &, const guardt &);
void mod_overflow_check(const mod_exprt &, const guardt &);
void enum_range_check(const exprt &, const guardt &);
void enum_range_check(const exprt &, const guardt &, bool is_assigned);
void undefined_shift_check(const shift_exprt &, const guardt &);
void pointer_rel_check(const binary_exprt &, const guardt &);
void pointer_overflow_check(const exprt &, const guardt &);
Expand Down Expand Up @@ -537,11 +539,17 @@
guard);
}

void goto_check_ct::enum_range_check(const exprt &expr, const guardt &guard)
void goto_check_ct::enum_range_check(
const exprt &expr,

Check warning on line 543 in src/ansi-c/goto-conversion/goto_check_c.cpp

View check run for this annotation

Codecov / codecov/patch

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

Added line #L543 was not covered by tests
const guardt &guard,
bool is_assigned)
{
if(!enable_enum_range_check)
return;

if(is_assigned)
return; // not in range yet

// we might be looking at a lowered enum_is_in_range_exprt, skip over these
const auto &pragmas = expr.source_location().get_pragmas();
for(const auto &d : pragmas)
Expand Down Expand Up @@ -1807,13 +1815,13 @@

if(expr.id() == ID_dereference)
{
check_rec(to_dereference_expr(expr).pointer(), guard);
check_rec(to_dereference_expr(expr).pointer(), guard, false);
}
else if(expr.id() == ID_index)
{
const index_exprt &index_expr = to_index_expr(expr);
check_rec_address(index_expr.array(), guard);
check_rec(index_expr.index(), guard);
check_rec(index_expr.index(), guard, false);
}
else
{
Expand Down Expand Up @@ -1843,7 +1851,7 @@
return guard(implication(conjunction(constraints), expr));
};

check_rec(op, new_guard);
check_rec(op, new_guard, false);

constraints.push_back(expr.id() == ID_or ? boolean_negate(op) : op);
}
Expand All @@ -1855,20 +1863,20 @@
if_expr.cond().is_boolean(),
"first argument of if must be boolean, but got " + if_expr.cond().pretty());

check_rec(if_expr.cond(), guard);
check_rec(if_expr.cond(), guard, false);

{
auto new_guard = [&guard, &if_expr](exprt expr) {
return guard(implication(if_expr.cond(), std::move(expr)));
};
check_rec(if_expr.true_case(), new_guard);
check_rec(if_expr.true_case(), new_guard, false);
}

{
auto new_guard = [&guard, &if_expr](exprt expr) {
return guard(implication(not_exprt(if_expr.cond()), std::move(expr)));
};
check_rec(if_expr.false_case(), new_guard);
check_rec(if_expr.false_case(), new_guard, false);
}
}

Expand All @@ -1878,7 +1886,7 @@
{
const dereference_exprt &deref = to_dereference_expr(member.struct_op());

check_rec(deref.pointer(), guard);
check_rec(deref.pointer(), guard, false);

// avoid building the following expressions when pointer_validity_check
// would return immediately anyway
Expand Down Expand Up @@ -1969,7 +1977,10 @@
}
}

void goto_check_ct::check_rec(const exprt &expr, const guardt &guard)
void goto_check_ct::check_rec(
const exprt &expr,

Check warning on line 1981 in src/ansi-c/goto-conversion/goto_check_c.cpp

View check run for this annotation

Codecov / codecov/patch

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

Added line #L1981 was not covered by tests
const guardt &guard,
bool is_assigned)

Check warning on line 1983 in src/ansi-c/goto-conversion/goto_check_c.cpp

View check run for this annotation

Codecov / codecov/patch

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

Added line #L1983 was not covered by tests
{
if(expr.id() == ID_exists || expr.id() == ID_forall)
{
Expand All @@ -1980,7 +1991,7 @@
return guard(forall_exprt(quantifier_expr.symbol(), expr));
};

check_rec(quantifier_expr.where(), new_guard);
check_rec(quantifier_expr.where(), new_guard, false);
return;
}
else if(expr.id() == ID_address_of)
Expand All @@ -2007,10 +2018,10 @@
}

for(const auto &op : expr.operands())
check_rec(op, guard);
check_rec(op, guard, false);

if(expr.type().id() == ID_c_enum_tag)
enum_range_check(expr, guard);
enum_range_check(expr, guard, is_assigned);

if(expr.id() == ID_index)
{
Expand Down Expand Up @@ -2059,9 +2070,9 @@
}
}

void goto_check_ct::check(const exprt &expr)
void goto_check_ct::check(const exprt &expr, bool is_assigned)
{
check_rec(expr, identity);
check_rec(expr, identity, is_assigned);

Check warning on line 2075 in src/ansi-c/goto-conversion/goto_check_c.cpp

View check run for this annotation

Codecov / codecov/patch

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

Added line #L2075 was not covered by tests
}

void goto_check_ct::memory_leak_check(const irep_idt &function_id)
Expand Down Expand Up @@ -2151,7 +2162,7 @@

if(i.has_condition())
{
check(i.condition());
check(i.condition(), false);
}

// magic ERROR label?
Expand Down Expand Up @@ -2184,45 +2195,32 @@

if(statement == ID_expression)
{
check(code);
check(code, false);
}
else if(statement == ID_printf)
{
for(const auto &op : code.operands())
check(op);
check(op, false);
}
}
else if(i.is_assign())
{
const exprt &assign_lhs = i.assign_lhs();
const exprt &assign_rhs = i.assign_rhs();

// Disable enum range checks for left-hand sides as their values are yet
// to be set (by this assignment).
{
flag_overridet resetter(i.source_location());
resetter.disable_flag(enable_enum_range_check, "enum_range_check");
check(assign_lhs);
}

check(assign_rhs);
check(assign_lhs, true);
check(assign_rhs, false);

// the LHS might invalidate any assertion
invalidate(assign_lhs);
}
else if(i.is_function_call())
{
// Disable enum range checks for left-hand sides as their values are yet
// to be set (by this function call).
{
flag_overridet resetter(i.source_location());
resetter.disable_flag(enable_enum_range_check, "enum_range_check");
check(i.call_lhs());
}
check(i.call_function());
check(i.call_lhs(), true);
check(i.call_function(), false);

for(const auto &arg : i.call_arguments())
check(arg);
check(arg, false);

check_shadow_memory_api_calls(i);

Expand All @@ -2231,7 +2229,7 @@
}
else if(i.is_set_return_value())
{
check(i.return_value());
check(i.return_value(), false);
// the return value invalidate any assertion
invalidate(i.return_value());
}
Expand Down Expand Up @@ -2342,7 +2340,7 @@
{
const exprt &expr = i.call_arguments()[0];
PRECONDITION(expr.type().id() == ID_pointer);
check(dereference_exprt(expr));
check(dereference_exprt(expr), false);
}
}

Expand Down
Loading