Skip to content

Commit 1a0c9da

Browse files
committed
Track deallocated/dead in an array
This enables tracking of all deallocations and all dead objects, and thereby use of deallocated/dead_object predicates within assumptions.
1 parent bb08494 commit 1a0c9da

File tree

14 files changed

+58
-63
lines changed

14 files changed

+58
-63
lines changed

regression/cbmc/array_of_bool_as_bitvec/test-smt2-outfile.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
CORE broken-smt-backend
22
main.c
33
--smt2 --outfile -
4-
\(= \(select array_of\.2 i\) \(ite false #b1 #b0\)\)
4+
\(= \(select array_of\.\d+ i\) \(ite false #b1 #b0\)\)
55
\(= \(select array\.3 \(\(_ zero_extend 32\) \|main::1::idx!0@1#1\|\)\) #b1\)
66
\(= \(select array\.3 \(_ bv\d+ 64\)\) \(ite false #b1 #b0\)\)
77
^EXIT=0$
88
^SIGNAL=0$
99
--
10-
\(= \(select array_of\.2 i\) false\)
10+
\(= \(select array_of\.\d+ i\) false\)
1111
\(= \(select array\.3 \(\(_ zero_extend 32\) \|main::1::idx!0@1#1\|\)\) #b1 #b0\)
1212
\(= \(select array\.3 \(_ bv\d+ 64\)\) false\)
1313
--

regression/cbmc/pointer-extra-checks/test.desc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ main.c
1010
^\[main.pointer_dereference.5\] .* dereference failure: pointer outside dynamic object bounds in \*r: SUCCESS$
1111
^\[main.pointer_dereference.6\] .* dereference failure: pointer NULL in \*s: FAILURE$
1212
^\[main.pointer_dereference.7\] .* dereference failure: pointer invalid in \*s: FAILURE$
13-
^\[main.pointer_dereference.8\] .* dereference failure: deallocated dynamic object in \*s: FAILURE$
1413
^\[main.pointer_dereference.9\] .* dereference failure: dead object in \*s: FAILURE$
1514
^\[main.pointer_dereference.10\] .* dereference failure: pointer outside object bounds in \*s: FAILURE$
1615
^\[main.pointer_dereference.11\] .* dereference failure: invalid integer address in \*s: FAILURE$

regression/cbmc/r_w_ok10/main.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <stdlib.h>
2+
3+
int main()
4+
{
5+
int *p = malloc(sizeof(int));
6+
free(p);
7+
__CPROVER_assume(__CPROVER_r_ok(p, sizeof(int)));
8+
__CPROVER_assert(0, "should be unreachable");
9+
}

regression/cbmc/r_w_ok10/test.desc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
4+
VERIFICATION SUCCESSFUL
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring
9+
--
10+
This test checks that __CPROVER_r_ok can safely be used in assumptions.

regression/cbmc/realloc-should-not-free-on-failure-to-allocate/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE
22
test.c
33
--malloc-may-fail --malloc-fail-null
4-
^\[main.precondition_instance.\d+] line \d+ double free: SUCCESS$
4+
^\[(free.precondition|main.precondition_instance).\d+] line \d+ double free: SUCCESS$
55
^VERIFICATION SUCCESSFUL$
66
^EXIT=0$
77
^SIGNAL=0$

src/ansi-c/ansi_c_internal_additions.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,10 @@ void ansi_c_internal_additions(std::string &code)
171171
CPROVER_PREFIX "constant_infinity_uint];\n"
172172

173173
// malloc
174-
"const void *" CPROVER_PREFIX "deallocated=0;\n"
175-
"const void *" CPROVER_PREFIX "dead_object=0;\n"
174+
CPROVER_PREFIX "bool " CPROVER_PREFIX "deallocated["
175+
CPROVER_PREFIX "constant_infinity_uint];\n"
176+
CPROVER_PREFIX "bool " CPROVER_PREFIX "dead_object["
177+
CPROVER_PREFIX "constant_infinity_uint];\n"
176178
"const void *" CPROVER_PREFIX "new_object=0;\n" // for C++
177179
CPROVER_PREFIX "bool " CPROVER_PREFIX "malloc_is_new_array=0;\n" // for C++
178180
"const void *" CPROVER_PREFIX "memory_leak=0;\n"

src/ansi-c/goto_check_c.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2176,16 +2176,10 @@ void goto_check_ct::goto_check(
21762176
if(local_bitvector_analysis->dirty(variable))
21772177
{
21782178
// need to mark the dead variable as dead
2179-
exprt lhs = ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
2180-
exprt address_of_expr = typecast_exprt::conditional_cast(
2181-
address_of_exprt(variable), lhs.type());
2182-
if_exprt rhs(
2183-
side_effect_expr_nondett(bool_typet(), i.source_location()),
2184-
std::move(address_of_expr),
2185-
lhs);
2179+
exprt lhs = dead_object(address_of_exprt{variable}, ns);
21862180
goto_programt::targett t =
21872181
new_code.add(goto_programt::make_assignment(
2188-
std::move(lhs), std::move(rhs), i.source_location()));
2182+
std::move(lhs), true_exprt{}, i.source_location()));
21892183
t->code_nonconst().add_source_location() = i.source_location();
21902184
}
21912185
}

src/ansi-c/library/cprover.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ typedef __typeof__(sizeof(int)) __CPROVER_size_t;
1919
typedef signed long long __CPROVER_ssize_t;
2020

2121
void *__CPROVER_allocate(__CPROVER_size_t size, __CPROVER_bool zero);
22-
extern const void *__CPROVER_deallocated;
22+
extern __CPROVER_bool __CPROVER_deallocated[];
2323
extern const void *__CPROVER_new_object;
2424
extern __CPROVER_bool __CPROVER_malloc_is_new_array;
2525
extern const void *__CPROVER_memory_leak;

src/ansi-c/library/mman.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,7 @@ int munmap(void *addr, __CPROVER_size_t length)
112112
{
113113
(void)length;
114114

115-
if(__VERIFIER_nondet___CPROVER_bool())
116-
__CPROVER_deallocated = addr;
115+
__CPROVER_deallocated[__CPROVER_POINTER_OBJECT(addr)] = 1;
117116

118117
return 0;
119118
}
@@ -126,8 +125,7 @@ int _munmap(void *addr, __CPROVER_size_t length)
126125
{
127126
(void)length;
128127

129-
if(__VERIFIER_nondet___CPROVER_bool())
130-
__CPROVER_deallocated = addr;
128+
__CPROVER_deallocated[__CPROVER_POINTER_OBJECT(addr)] = 1;
131129

132130
return 0;
133131
}

src/ansi-c/library/stdlib.c

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,6 @@ __CPROVER_HIDE:;
112112
// and __CPROVER_allocate doesn't, but no one cares
113113
malloc_res = __CPROVER_allocate(alloc_size, 1);
114114

115-
// make sure it's not recorded as deallocated
116-
__CPROVER_deallocated =
117-
(malloc_res == __CPROVER_deallocated) ? 0 : __CPROVER_deallocated;
118-
119115
// record the object size for non-determistic bounds checking
120116
__CPROVER_bool record_malloc = __VERIFIER_nondet___CPROVER_bool();
121117
__CPROVER_malloc_is_new_array =
@@ -174,10 +170,6 @@ __CPROVER_HIDE:;
174170
void *malloc_res;
175171
malloc_res = __CPROVER_allocate(malloc_size, 0);
176172

177-
// make sure it's not recorded as deallocated
178-
__CPROVER_deallocated =
179-
(malloc_res == __CPROVER_deallocated) ? 0 : __CPROVER_deallocated;
180-
181173
// record the object size for non-determistic bounds checking
182174
__CPROVER_bool record_malloc = __VERIFIER_nondet___CPROVER_bool();
183175
__CPROVER_malloc_is_new_array =
@@ -205,9 +197,6 @@ inline void *__builtin_alloca(__CPROVER_size_t alloca_size)
205197
void *res;
206198
res = __CPROVER_allocate(alloca_size, 0);
207199

208-
// make sure it's not recorded as deallocated
209-
__CPROVER_deallocated=(res==__CPROVER_deallocated)?0:__CPROVER_deallocated;
210-
211200
// record the object size for non-determistic bounds checking
212201
__CPROVER_bool record_malloc=__VERIFIER_nondet___CPROVER_bool();
213202
__CPROVER_malloc_is_new_array=record_malloc?0:__CPROVER_malloc_is_new_array;
@@ -255,8 +244,9 @@ inline void free(void *ptr)
255244
"free argument has offset zero");
256245

257246
// catch double free
258-
__CPROVER_precondition(ptr==0 || __CPROVER_deallocated!=ptr,
259-
"double free");
247+
__CPROVER_precondition(
248+
ptr == 0 || !__CPROVER_deallocated[__CPROVER_POINTER_OBJECT(ptr)],
249+
"double free");
260250

261251
// catch people who try to use free(...) for stuff
262252
// allocated with new[]
@@ -271,9 +261,7 @@ inline void free(void *ptr)
271261

272262
if(ptr!=0)
273263
{
274-
// non-deterministically record as deallocated
275-
__CPROVER_bool record=__VERIFIER_nondet___CPROVER_bool();
276-
if(record) __CPROVER_deallocated=ptr;
264+
__CPROVER_deallocated[__CPROVER_POINTER_OBJECT(ptr)] = 1;
277265

278266
// detect memory leaks
279267
if(__CPROVER_memory_leak==ptr)

src/cpp/cpp_internal_additions.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,12 @@ void cpp_internal_additions(std::ostream &out)
8888
<< CPROVER_PREFIX "memory[__CPROVER::constant_infinity_uint];" << '\n';
8989

9090
// malloc
91-
out << "const void *" CPROVER_PREFIX "deallocated = 0;" << '\n';
92-
out << "const void *" CPROVER_PREFIX "dead_object = 0;" << '\n';
91+
out << CPROVER_PREFIX "bool "
92+
<< CPROVER_PREFIX "deallocated[__CPROVER::constant_infinity_uint];"
93+
<< '\n';
94+
out << CPROVER_PREFIX "bool "
95+
<< CPROVER_PREFIX "dead_object[__CPROVER::constant_infinity_uint];"
96+
<< '\n';
9397
out << "const void *" CPROVER_PREFIX "new_object = 0;" << '\n';
9498
out << "" CPROVER_PREFIX "bool " CPROVER_PREFIX "malloc_is_new_array = 0;"
9599
<< '\n';

src/cpp/library/new.c

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ inline void *__new(__typeof__(sizeof(int)) malloc_size)
1010
void *res;
1111
res = __CPROVER_allocate(malloc_size, 0);
1212

13-
// ensure it's not recorded as deallocated
14-
__CPROVER_deallocated=(res==__CPROVER_deallocated)?0:__CPROVER_deallocated;
15-
1613
// non-deterministically record the object for delete/delete[] checking
1714
__CPROVER_bool record_malloc=__VERIFIER_nondet___CPROVER_bool();
1815
__CPROVER_new_object = record_malloc ? res : __CPROVER_new_object;
@@ -37,9 +34,6 @@ inline void *__new_array(__CPROVER_size_t count, __CPROVER_size_t size)
3734
void *res;
3835
res = __CPROVER_allocate(size*count, 0);
3936

40-
// ensure it's not recorded as deallocated
41-
__CPROVER_deallocated=(res==__CPROVER_deallocated)?0:__CPROVER_deallocated;
42-
4337
// non-deterministically record the object for delete/delete[] checking
4438
__CPROVER_bool record_malloc=__VERIFIER_nondet___CPROVER_bool();
4539
__CPROVER_new_object = record_malloc ? res : __CPROVER_new_object;
@@ -77,7 +71,9 @@ inline void __delete(void *ptr)
7771
"delete argument must have offset zero");
7872

7973
// catch double delete
80-
__CPROVER_precondition(ptr==0 || __CPROVER_deallocated!=ptr, "double delete");
74+
__CPROVER_precondition(
75+
ptr == 0 || !__CPROVER_deallocated[__CPROVER_POINTER_OBJECT(ptr)],
76+
"double delete");
8177

8278
// catch people who call delete for objects allocated with new[]
8379
__CPROVER_precondition(
@@ -88,9 +84,7 @@ inline void __delete(void *ptr)
8884
// This is a requirement by the standard, not generosity!
8985
if(ptr!=0)
9086
{
91-
// non-deterministically record as deallocated
92-
__CPROVER_bool record=__VERIFIER_nondet___CPROVER_bool();
93-
__CPROVER_deallocated=record?ptr:__CPROVER_deallocated;
87+
__CPROVER_deallocated[__CPROVER_POINTER_OBJECT(ptr)] = 1;
9488

9589
// detect memory leaks
9690
if(__CPROVER_memory_leak==ptr)
@@ -115,8 +109,9 @@ inline void __delete_array(void *ptr)
115109
"delete argument must have offset zero");
116110

117111
// catch double delete
118-
__CPROVER_precondition(ptr==0 || __CPROVER_deallocated!=ptr,
119-
"double delete");
112+
__CPROVER_precondition(
113+
ptr == 0 || !__CPROVER_deallocated[__CPROVER_POINTER_OBJECT(ptr)],
114+
"double delete");
120115

121116
// catch people who call delete[] for objects allocated with new
122117
__CPROVER_precondition(
@@ -125,9 +120,7 @@ inline void __delete_array(void *ptr)
125120

126121
if(ptr!=0)
127122
{
128-
// non-deterministically record as deallocated
129-
__CPROVER_bool record=__VERIFIER_nondet___CPROVER_bool();
130-
__CPROVER_deallocated=record?ptr:__CPROVER_deallocated;
123+
__CPROVER_deallocated[__CPROVER_POINTER_OBJECT(ptr)] = 1;
131124

132125
// detect memory leaks
133126
if(__CPROVER_memory_leak==ptr) __CPROVER_memory_leak=0;

src/goto-programs/builtin_functions.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Author: Daniel Kroening, [email protected]
1919
#include <util/mathematical_expr.h>
2020
#include <util/mathematical_types.h>
2121
#include <util/pointer_expr.h>
22+
#include <util/pointer_predicates.h>
2223
#include <util/prefix.h>
2324
#include <util/rational.h>
2425
#include <util/rational_tools.h>
@@ -1417,16 +1418,9 @@ void goto_convertt::do_function_call_symbol(
14171418
make_temp_symbol(new_lhs, "alloca", dest, mode);
14181419

14191420
// mark pointer to alloca result as dead
1420-
symbol_exprt dead_object_sym =
1421-
ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
1422-
exprt alloca_result =
1423-
typecast_exprt::conditional_cast(new_lhs, dead_object_sym.type());
1424-
if_exprt rhs{
1425-
side_effect_expr_nondett{bool_typet(), source_location},
1426-
std::move(alloca_result),
1427-
dead_object_sym};
1421+
exprt dead_object_expr = dead_object(new_lhs, ns);
14281422
code_assignt assign{
1429-
std::move(dead_object_sym), std::move(rhs), source_location};
1423+
std::move(dead_object_expr), true_exprt{}, source_location};
14301424
targets.destructor_stack.add(assign);
14311425
}
14321426
else

src/util/pointer_predicates.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,19 @@ exprt deallocated(const exprt &pointer, const namespacet &ns)
4545
// we check __CPROVER_deallocated!
4646
const symbolt &deallocated_symbol=ns.lookup(CPROVER_PREFIX "deallocated");
4747

48-
return same_object(pointer, deallocated_symbol.symbol_expr());
48+
return index_exprt{
49+
deallocated_symbol.symbol_expr(),
50+
typecast_exprt::conditional_cast(pointer_object(pointer), index_type())};
4951
}
5052

5153
exprt dead_object(const exprt &pointer, const namespacet &ns)
5254
{
5355
// we check __CPROVER_dead_object!
5456
const symbolt &deallocated_symbol=ns.lookup(CPROVER_PREFIX "dead_object");
5557

56-
return same_object(pointer, deallocated_symbol.symbol_expr());
58+
return index_exprt{
59+
deallocated_symbol.symbol_expr(),
60+
typecast_exprt::conditional_cast(pointer_object(pointer), index_type())};
5761
}
5862

5963
exprt good_pointer(const exprt &pointer)

0 commit comments

Comments
 (0)