Skip to content

Commit 49ad1bd

Browse files
authored
Merge pull request #974 from tautschnig/fix-assert-encoding
Do not generate redundant if statements in assert expansions
2 parents 16e9599 + 4122a28 commit 49ad1bd

File tree

8 files changed

+85
-11
lines changed

8 files changed

+85
-11
lines changed

regression/cbmc/simple_assert/main.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <assert.h>
2+
3+
int main(int argc, char *argv[])
4+
{
5+
int x = 5;
6+
assert(x == 5);
7+
8+
return 0;
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
main.c
3+
--cover location
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main\.coverage\.1\] .* function main block 1: SATISFIED$
7+
(1 of 1|3 of 3) covered \(100\.0%\)$
8+
--
9+
^warning: ignoring
10+
^CONVERSION ERROR$
11+
^\[main\.coverage\..\] .* function main block .: FAILED$
12+
--
13+
On Windows/Visual Studio, "assert" does not introduce any branching.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <assert.h>
2+
3+
int main(int argc, char *argv[])
4+
{
5+
assert(0);
6+
return 0;
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--dump-c
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
8+
^[[:space:]]*IF

src/goto-programs/goto_clean_expr.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,13 +260,19 @@ void goto_convertt::clean_expr(
260260
// preserve the expressions for possible later checks
261261
if(if_expr.true_case().is_not_nil())
262262
{
263-
code_expressiont code_expression(if_expr.true_case());
263+
// add a (void) type cast so that is_skip catches it in case the
264+
// expression is just a constant
265+
code_expressiont code_expression(
266+
typecast_exprt(if_expr.true_case(), empty_typet()));
264267
convert(code_expression, tmp_true);
265268
}
266269

267270
if(if_expr.false_case().is_not_nil())
268271
{
269-
code_expressiont code_expression(if_expr.false_case());
272+
// add a (void) type cast so that is_skip catches it in case the
273+
// expression is just a constant
274+
code_expressiont code_expression(
275+
typecast_exprt(if_expr.false_case(), empty_typet()));
270276
convert(code_expression, tmp_false);
271277
}
272278

src/goto-programs/goto_convert.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,12 @@ Author: Daniel Kroening, [email protected]
2626

2727
#include "goto_convert_class.h"
2828
#include "destructor.h"
29+
#include "remove_skip.h"
2930

3031
static bool is_empty(const goto_programt &goto_program)
3132
{
3233
forall_goto_program_instructions(it, goto_program)
33-
if(!it->is_skip() ||
34-
!it->labels.empty() ||
35-
!it->code.is_nil())
34+
if(!is_skip(goto_program, it))
3635
return false;
3736

3837
return true;
@@ -1723,6 +1722,11 @@ void goto_convertt::generate_ifthenelse(
17231722
true_case.instructions.back().guard=boolean_negate(guard);
17241723
dest.destructive_append(true_case);
17251724
true_case.instructions.clear();
1725+
if(
1726+
is_empty(false_case) ||
1727+
(is_size_one(false_case) &&
1728+
is_skip(false_case, false_case.instructions.begin())))
1729+
return;
17261730
}
17271731

17281732
// similarly, do guarded assertions directly
@@ -1736,6 +1740,28 @@ void goto_convertt::generate_ifthenelse(
17361740
false_case.instructions.back().guard=guard;
17371741
dest.destructive_append(false_case);
17381742
false_case.instructions.clear();
1743+
if(
1744+
is_empty(true_case) ||
1745+
(is_size_one(true_case) &&
1746+
is_skip(true_case, true_case.instructions.begin())))
1747+
return;
1748+
}
1749+
1750+
// a special case for C libraries that use
1751+
// (void)((cond) || (assert(0),0))
1752+
if(
1753+
is_empty(false_case) && true_case.instructions.size() == 2 &&
1754+
true_case.instructions.front().is_assert() &&
1755+
true_case.instructions.front().guard.is_false() &&
1756+
true_case.instructions.front().labels.empty() &&
1757+
true_case.instructions.back().labels.empty())
1758+
{
1759+
true_case.instructions.front().guard = boolean_negate(guard);
1760+
true_case.instructions.erase(--true_case.instructions.end());
1761+
dest.destructive_append(true_case);
1762+
true_case.instructions.clear();
1763+
1764+
return;
17391765
}
17401766

17411767
// Flip around if no 'true' case code.

src/goto-programs/remove_skip.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Author: Daniel Kroening, [email protected]
1212
#include "remove_skip.h"
1313
#include "goto_model.h"
1414

15-
static bool is_skip(goto_programt::instructionst::iterator it)
15+
bool is_skip(const goto_programt &body, goto_programt::const_targett it)
1616
{
1717
// we won't remove labelled statements
1818
// (think about error labels or the like)
@@ -28,9 +28,12 @@ static bool is_skip(goto_programt::instructionst::iterator it)
2828
if(it->guard.is_false())
2929
return true;
3030

31-
goto_programt::instructionst::iterator next_it=it;
31+
goto_programt::const_targett next_it = it;
3232
next_it++;
3333

34+
if(next_it == body.instructions.end())
35+
return false;
36+
3437
// A branch to the next instruction is a skip
3538
// We also require the guard to be 'true'
3639
return it->guard.is_true() &&
@@ -92,7 +95,7 @@ void remove_skip(goto_programt &goto_program)
9295
// for collecting labels
9396
std::list<irep_idt> labels;
9497

95-
while(is_skip(it))
98+
while(is_skip(goto_program, it))
9699
{
97100
// don't remove the last skip statement,
98101
// it could be a target
@@ -144,9 +147,10 @@ void remove_skip(goto_programt &goto_program)
144147
// remove the last skip statement unless it's a target
145148
goto_program.compute_incoming_edges();
146149

147-
if(!goto_program.instructions.empty() &&
148-
is_skip(--goto_program.instructions.end()) &&
149-
!goto_program.instructions.back().is_target())
150+
if(
151+
!goto_program.instructions.empty() &&
152+
is_skip(goto_program, --goto_program.instructions.end()) &&
153+
!goto_program.instructions.back().is_target())
150154
goto_program.instructions.pop_back();
151155
}
152156
while(goto_program.instructions.size()<old_size);

src/goto-programs/remove_skip.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Author: Daniel Kroening, [email protected]
1616

1717
class goto_modelt;
1818

19+
bool is_skip(const goto_programt &, goto_programt::const_targett);
1920
void remove_skip(goto_programt &);
2021
void remove_skip(goto_functionst &);
2122
void remove_skip(goto_modelt &);

0 commit comments

Comments
 (0)