Skip to content

Commit 81d8eb1

Browse files
authored
Merge pull request #3455 from danpoe/feature/nondet-function-argument-targets
Generate function bodies that nondet havoc the function arguments [blocks: #3457]
2 parents 77237a6 + ade4e66 commit 81d8eb1

File tree

21 files changed

+396
-194
lines changed

21 files changed

+396
-194
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
void func(int *p);
5+
6+
void main()
7+
{
8+
int *p;
9+
p = NULL;
10+
11+
func(p);
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.c
3+
--generate-function-body func --generate-function-body-options havoc,params:p --pointer-check
4+
^SIGNAL=0$
5+
^EXIT=0$
6+
--
7+
^warning: ignoring
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
void func(int *p);
5+
6+
void main()
7+
{
8+
int i;
9+
i = 0;
10+
11+
func(&i);
12+
13+
assert(i == 0);
14+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--generate-function-body func --generate-function-body-options havoc,params:p
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
\[main.assertion.1\] line \d+ assertion i == 0: FAILURE
7+
--
8+
^warning: ignoring
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
typedef struct st1
5+
{
6+
struct st2 *to_st2;
7+
int data;
8+
} st1_t;
9+
10+
typedef struct st2
11+
{
12+
struct st1 *to_st1;
13+
int data;
14+
} st2_t;
15+
16+
st1_t dummy1;
17+
st2_t dummy2;
18+
19+
void func(st1_t *p);
20+
21+
void main()
22+
{
23+
st1_t st;
24+
25+
func(&st);
26+
27+
assert(st.to_st2 != NULL);
28+
assert(st.to_st2->to_st1 != NULL);
29+
assert(st.to_st2->to_st1->to_st2 == NULL);
30+
31+
assert(st.to_st2 != &dummy2);
32+
assert(st.to_st2->to_st1 != &dummy1);
33+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--generate-function-body func --generate-function-body-options 'havoc,params:p' --min-null-tree-depth 10 --max-nondet-tree-depth 3 --pointer-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
VERIFICATION SUCCESSFUL
7+
--
8+
^warning: ignoring
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
typedef struct st
5+
{
6+
int data;
7+
} st_t;
8+
9+
void func(st_t *p);
10+
11+
void main()
12+
{
13+
st_t st;
14+
st.data = 0;
15+
16+
func(&st);
17+
18+
assert(st.data == 0);
19+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--generate-function-body func --generate-function-body-options havoc,params:p
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
\[main.assertion.1\] line \d+ assertion st.data == 0: FAILURE
7+
--
8+
^warning: ignoring
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
typedef struct st
5+
{
6+
struct st *next;
7+
struct st *prev;
8+
int data;
9+
} st_t;
10+
11+
st_t dummy;
12+
13+
void func(st_t *p);
14+
15+
void main()
16+
{
17+
st_t st;
18+
19+
func(&st);
20+
21+
assert(st.prev != NULL);
22+
assert(st.prev != &dummy);
23+
24+
assert(st.next != NULL);
25+
assert(st.next != &dummy);
26+
27+
assert(st.prev->prev == NULL);
28+
assert(st.prev->next == NULL);
29+
assert(st.next->prev == NULL);
30+
assert(st.next->next == NULL);
31+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--generate-function-body func --generate-function-body-options havoc,params:p --min-null-tree-depth 10 --max-nondet-tree-depth 2 --pointer-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
VERIFICATION SUCCESSFUL
7+
--
8+
^warning: ignoring
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
typedef struct st
5+
{
6+
struct st *next;
7+
int data;
8+
} st_t;
9+
10+
st_t dummy;
11+
12+
void func(st_t *p);
13+
14+
void main()
15+
{
16+
st_t st;
17+
18+
func(&st);
19+
20+
assert(st.next != NULL);
21+
assert(st.next->next != NULL);
22+
assert(st.next->next->next == NULL);
23+
24+
assert(st.next != &dummy);
25+
assert(st.next->next != &dummy);
26+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--generate-function-body func --generate-function-body-options havoc,params:p --min-null-tree-depth 10 --max-nondet-tree-depth 3
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
VERIFICATION SUCCESSFUL
7+
--
8+
^warning: ignoring

src/ansi-c/ansi_c_entry_point.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ exprt::operandst build_function_environment(
4242
base_name,
4343
p.type(),
4444
p.source_location(),
45-
object_factory_parameters);
45+
object_factory_parameters,
46+
lifetimet::AUTOMATIC_LOCAL);
4647
}
4748

4849
return main_arguments;

src/ansi-c/c_nondet_symbol_factory.cpp

Lines changed: 27 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -25,79 +25,29 @@ Author: Diffblue Ltd.
2525

2626
#include <goto-programs/goto_functions.h>
2727

28-
class symbol_factoryt
29-
{
30-
symbol_tablet &symbol_table;
31-
const source_locationt &loc;
32-
namespacet ns;
33-
const c_object_factory_parameterst &object_factory_params;
34-
35-
allocate_objectst allocate_objects;
36-
37-
typedef std::set<irep_idt> recursion_sett;
38-
39-
public:
40-
symbol_factoryt(
41-
symbol_tablet &_symbol_table,
42-
const source_locationt &loc,
43-
const c_object_factory_parameterst &object_factory_params)
44-
: symbol_table(_symbol_table),
45-
loc(loc),
46-
ns(_symbol_table),
47-
object_factory_params(object_factory_params),
48-
allocate_objects(ID_C, loc, loc.get_function(), symbol_table)
49-
{}
50-
51-
void gen_nondet_init(
52-
code_blockt &assignments,
53-
const exprt &expr,
54-
const std::size_t depth = 0,
55-
recursion_sett recursion_set = recursion_sett());
56-
57-
void add_created_symbol(const symbolt *symbol_ptr)
58-
{
59-
allocate_objects.add_created_symbol(symbol_ptr);
60-
}
61-
62-
void declare_created_symbols(code_blockt &init_code)
63-
{
64-
allocate_objects.declare_created_symbols(init_code);
65-
}
66-
67-
void mark_created_symbols_as_input(code_blockt &init_code)
68-
{
69-
allocate_objects.mark_created_symbols_as_input(init_code);
70-
}
71-
72-
private:
73-
/// Generate initialisation code for each array element
74-
/// \param assignments: The code block to add code to
75-
/// \param expr: An expression of array type
76-
/// \param depth: The struct recursion depth
77-
/// \param recursion_set: The struct recursion set
78-
/// \see gen_nondet_init For the meaning of the last 2 parameters
79-
void gen_nondet_array_init(
80-
code_blockt &assignments,
81-
const exprt &expr,
82-
std::size_t depth,
83-
const recursion_sett &recursion_set);
84-
};
85-
8628
/// Creates a nondet for expr, including calling itself recursively to make
8729
/// appropriate symbols to point to if expr is a pointer.
8830
/// \param assignments: The code block to add code to
8931
/// \param expr: The expression which we are generating a non-determinate value
9032
/// for
91-
/// \param depth: number of pointers followed so far during initialisation
92-
/// \param recursion_set: names of structs seen so far on current pointer chain
33+
/// \param depth number of pointers followed so far during initialisation
34+
/// \param recursion_set names of structs seen so far on current pointer chain
35+
/// \param assign_const Indicates whether const objects should be nondet
36+
/// initialized
9337
void symbol_factoryt::gen_nondet_init(
9438
code_blockt &assignments,
9539
const exprt &expr,
9640
const std::size_t depth,
97-
recursion_sett recursion_set)
41+
recursion_sett recursion_set,
42+
const bool assign_const)
9843
{
9944
const typet &type = expr.type();
10045

46+
if(!assign_const && expr.type().get_bool(ID_C_constant))
47+
{
48+
return;
49+
}
50+
10151
if(type.id()==ID_pointer)
10252
{
10353
// dereferenced type
@@ -120,10 +70,10 @@ void symbol_factoryt::gen_nondet_init(
12070

12171
code_blockt non_null_inst;
12272

123-
exprt init_expr = allocate_objects.allocate_automatic_local_object(
124-
non_null_inst, expr, subtype);
73+
exprt init_expr =
74+
allocate_objects.allocate_object(non_null_inst, expr, subtype, lifetime);
12575

126-
gen_nondet_init(non_null_inst, init_expr, depth + 1, recursion_set);
76+
gen_nondet_init(non_null_inst, init_expr, depth + 1, recursion_set, true);
12777

12878
if(depth < object_factory_params.min_null_tree_depth)
12979
{
@@ -165,12 +115,18 @@ void symbol_factoryt::gen_nondet_init(
165115
for(const auto &component : struct_type.components())
166116
{
167117
const typet &component_type = component.type();
118+
119+
if(!assign_const && component_type.get_bool(ID_C_constant))
120+
{
121+
continue;
122+
}
123+
168124
const irep_idt name = component.get_name();
169125

170126
member_exprt me(expr, name, component_type);
171127
me.add_source_location() = loc;
172128

173-
gen_nondet_init(assignments, me, depth, recursion_set);
129+
gen_nondet_init(assignments, me, depth, recursion_set, assign_const);
174130
}
175131
}
176132
else if(type.id() == ID_array)
@@ -221,14 +177,17 @@ void symbol_factoryt::gen_nondet_array_init(
221177
/// \param loc: The location to assign to generated code
222178
/// \param object_factory_parameters: configuration parameters for the object
223179
/// factory
180+
/// \param lifetime: Lifetime of the allocated object (AUTOMATIC_LOCAL,
181+
/// STATIC_GLOBAL, or DYNAMIC)
224182
/// \return Returns the symbol_exprt for the symbol created
225183
symbol_exprt c_nondet_symbol_factory(
226184
code_blockt &init_code,
227185
symbol_tablet &symbol_table,
228186
const irep_idt base_name,
229187
const typet &type,
230188
const source_locationt &loc,
231-
const c_object_factory_parameterst &object_factory_parameters)
189+
const c_object_factory_parameterst &object_factory_parameters,
190+
const lifetimet lifetime)
232191
{
233192
irep_idt identifier=id2string(goto_functionst::entry_point())+
234193
"::"+id2string(base_name);
@@ -247,7 +206,8 @@ symbol_exprt c_nondet_symbol_factory(
247206
bool moving_symbol_failed=symbol_table.move(main_symbol, main_symbol_ptr);
248207
CHECK_RETURN(!moving_symbol_failed);
249208

250-
symbol_factoryt state(symbol_table, loc, object_factory_parameters);
209+
symbol_factoryt state(symbol_table, loc, object_factory_parameters, lifetime);
210+
251211
code_blockt assignments;
252212
state.gen_nondet_init(assignments, main_symbol_expr);
253213

0 commit comments

Comments
 (0)