Skip to content

Commit 8edaf8e

Browse files
committed
C library: atexit
atexit introduces function calls that may affect the verification outcome.
1 parent dcdf046 commit 8edaf8e

File tree

21 files changed

+134
-35
lines changed

21 files changed

+134
-35
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 cleanup()
5+
{
6+
assert(0);
7+
}
8+
9+
int main()
10+
{
11+
atexit(cleanup);
12+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--pointer-check --bounds-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--
8+
^warning: ignoring
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
void cleanup()
5+
{
6+
assert(0);
7+
}
8+
9+
int main()
10+
{
11+
atexit(cleanup);
12+
exit(0);
13+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--pointer-check --bounds-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--
8+
^warning: ignoring

regression/cbmc-library/posix_memalign-02/test.desc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ main.c
66
^VERIFICATION FAILED$
77
\[main.precondition_instance.1\] .* memcpy src/dst overlap: FAILURE
88
\[main.precondition_instance.3\] .* memcpy destination region writeable: FAILURE
9+
\*\* 2 of 24 failed
910
--
1011
^warning: ignoring

regression/cbmc-library/pthread_cond_wait-01/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ main.c
33
--bounds-check
44
^EXIT=10$
55
^SIGNAL=0$
6-
^\*\* 1 of 2 failed
6+
^\*\* 1 of 4 failed
77
^VERIFICATION FAILED$
88
--
99
^warning: ignoring

regression/cbmc/Pointer_byte_extract5/no-simplify.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ main.i
44
^EXIT=10$
55
^SIGNAL=0$
66
array\.List dynamic object upper bound in p->List\[2\]: FAILURE
7-
\*\* 1 of 11 failed
7+
\*\* 1 of 18 failed
88
--
99
^warning: ignoring
1010
--

regression/cbmc/array-cell-sensitivity2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ main::1::array!0@1#3 = with\(main::1::array!0@1#2, 1, main::argc!0@1#1\)
66
^EXIT=0$
77
^SIGNAL=0$
88
--
9-
\[\[[0-9]+\]\]
9+
array.*\[\[[0-9]+\]\]
1010
--
1111
This checks that arrays of uncertain size are always treated as aggregates and
1212
are not expanded into individual cell symbols (which use the [[index]] notation

regression/cbmc/array_constraints1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ main.c
44
^EXIT=10$
55
^SIGNAL=0$
66
^VERIFICATION FAILED$
7-
^\*\* 2 of 14
7+
^\*\* 2 of 24
88
--
99
^warning: ignoring

regression/cbmc/memory_allocation2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ main.c
55
^SIGNAL=0$
66
^\[main\.array_bounds\.[1-5]\] .*: SUCCESS$
77
^\[main\.array_bounds\.[67]\] line 38 array.buffer (dynamic object )?upper bound in buffers\[\(signed long (long )?int\)0\]->buffer\[\(signed long (long )?int\)100\]: FAILURE$
8-
^\*\* 1 of 6 failed
8+
^\*\* 2 of 9 failed
99
^VERIFICATION FAILED$
1010
--
1111
^warning: ignoring

regression/cbmc/multiple-goto-traces/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ activate-multi-line-match
55
^EXIT=10$
66
^SIGNAL=0$
77
VERIFICATION FAILED
8-
Trace for main\.assertion\.1:(\n.*){22} assertion 4 \!= argc(\n.*){5}Trace for main\.assertion\.3:(\n.*){36} assertion argc != 4(\n.*){5}Trace for main\.assertion\.4:(\n.*){50} assertion argc \+ 1 != 5
8+
Trace for main\.assertion\.1:(\n.*){150} assertion 4 \!= argc(\n.*){5}Trace for main\.assertion\.3:(\n.*){164} assertion argc != 4(\n.*){5}Trace for main\.assertion\.4:(\n.*){178} assertion argc \+ 1 != 5
99
\*\* 3 of 4 failed
1010
--
1111
^warning: ignoring

regression/cbmc/pragma_cprover1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ CORE
22
main.c
33
--signed-overflow-check --bounds-check
44
line 14 array 'y' upper bound in y\[\(signed long( long)? int\)1\]: FAILURE$
5-
^\*\* 1 of 1 failed
5+
^\*\* 1 of 4 failed
66
^VERIFICATION FAILED$
77
^EXIT=10$
88
^SIGNAL=0$

regression/cbmc/pragma_cprover2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ main.c
33
--signed-overflow-check
44
^\[main.overflow\.1\] line 21 arithmetic overflow on signed \+ in n \+ n: FAILURE$
55
^\[main.overflow\.2\] line 22 arithmetic overflow on signed \+ in x \+ n: FAILURE$
6-
^\*\* 2 of 2 failed
6+
^\*\* 2 of 3 failed
77
^VERIFICATION FAILED$
88
^EXIT=10$
99
^SIGNAL=0$

regression/cbmc/switch8/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ main.c
1313
^\[main\.pointer_dereference\.4\] line 42 dereference failure: dead object in \*p: FAILURE$
1414
^\[main\.assertion\.4\] line 49 assertion e == 42: FAILURE$
1515
^\[main\.assertion\.5\] line 51 assertion f == 42: FAILURE$
16-
^\*\* 4 of 10 failed
16+
^\*\* 4 of 18 failed
1717
^VERIFICATION FAILED$
1818
--
1919
^warning: ignoring

regression/cbmc/union12/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ main.c
44
^EXIT=10$
55
^SIGNAL=0$
66
^\[main\.assertion\.2\] line 20 should fail: FAILURE$
7-
^\*\* 1 of 15 failed
7+
^\*\* 1 of 25 failed
88
^VERIFICATION FAILED$
99
--
1010
^warning: ignoring

src/analyses/goto_check_c.cpp

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,6 +2213,28 @@ void goto_check_ct::goto_check(
22132213
i.turn_into_skip();
22142214
did_something = true;
22152215
}
2216+
2217+
if(enable_memory_leak_check && function_identifier == "exit")
2218+
{
2219+
const symbolt &leak = ns.lookup(CPROVER_PREFIX "memory_leak");
2220+
const symbol_exprt leak_expr = leak.symbol_expr();
2221+
2222+
// add self-assignment to get helpful counterexample output
2223+
new_code.add(goto_programt::make_assignment(leak_expr, leak_expr));
2224+
2225+
source_locationt source_location;
2226+
source_location.set_function(function_identifier);
2227+
2228+
equal_exprt eq(
2229+
leak_expr, null_pointer_exprt(to_pointer_type(leak.type)));
2230+
add_guarded_property(
2231+
eq,
2232+
"dynamically allocated memory never freed",
2233+
"memory-leak",
2234+
source_location,
2235+
eq,
2236+
identity);
2237+
}
22162238
}
22172239
else if(i.is_dead())
22182240
{
@@ -2262,29 +2284,6 @@ void goto_check_ct::goto_check(
22622284
}
22632285
else if(i.is_end_function())
22642286
{
2265-
if(
2266-
function_identifier == goto_functionst::entry_point() &&
2267-
enable_memory_leak_check)
2268-
{
2269-
const symbolt &leak = ns.lookup(CPROVER_PREFIX "memory_leak");
2270-
const symbol_exprt leak_expr = leak.symbol_expr();
2271-
2272-
// add self-assignment to get helpful counterexample output
2273-
new_code.add(goto_programt::make_assignment(leak_expr, leak_expr));
2274-
2275-
source_locationt source_location;
2276-
source_location.set_function(function_identifier);
2277-
2278-
equal_exprt eq(
2279-
leak_expr, null_pointer_exprt(to_pointer_type(leak.type)));
2280-
add_guarded_property(
2281-
eq,
2282-
"dynamically allocated memory never freed",
2283-
"memory-leak",
2284-
source_location,
2285-
eq,
2286-
identity);
2287-
}
22882287
}
22892288

22902289
for(auto &instruction : new_code.instructions)

src/ansi-c/ansi_c_entry_point.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ bool generate_ansi_c_start_function(
242242
const code_typet::parameterst &parameters=
243243
to_code_type(symbol.type).parameters();
244244

245+
const namespacet ns(symbol_table);
246+
245247
if(symbol.name==ID_main)
246248
{
247249
if(parameters.empty())
@@ -250,8 +252,6 @@ bool generate_ansi_c_start_function(
250252
}
251253
else if(parameters.size()==2 || parameters.size()==3)
252254
{
253-
namespacet ns(symbol_table);
254-
255255
{
256256
symbolt argc_symbol;
257257

@@ -498,8 +498,23 @@ bool generate_ansi_c_start_function(
498498
parameters, init_code, symbol_table, object_factory_parameters);
499499
}
500500

501+
exprt return_value = call_main.lhs();
501502
init_code.add(std::move(call_main));
502503

504+
const symbolt &exit_symbol = ns.lookup("exit");
505+
const typet &arg_type = to_code_type(exit_symbol.type).parameters()[0].type();
506+
code_function_callt call_exit{exit_symbol.symbol_expr()};
507+
if(return_value.is_not_nil())
508+
{
509+
call_exit.arguments().push_back(
510+
typecast_exprt::conditional_cast(return_value, arg_type));
511+
}
512+
else
513+
call_exit.arguments().push_back(from_integer(0, arg_type));
514+
call_exit.add_source_location() = symbol.location;
515+
call_exit.function().add_source_location() = symbol.location;
516+
init_code.add(std::move(call_exit));
517+
503518
// TODO: add read/modified (recursively in call graph) globals as INPUT/OUTPUT
504519

505520
record_function_outputs(symbol, init_code, symbol_table);

src/ansi-c/ansi_c_internal_additions.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ void ansi_c_internal_additions(std::string &code)
186186
id2string(rounding_mode_identifier()) + '='+
187187
std::to_string(config.ansi_c.rounding_mode)+";\n"
188188

189+
// atexit
190+
"void exit(int);\n"
191+
189192
// pipes, write, read, close
190193
"struct " CPROVER_PREFIX "pipet {\n"
191194
" _Bool widowed;\n"

src/ansi-c/library/stdlib.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,20 @@ inline long long int __builtin_llabs(long long int i) { return __CPROVER_llabs(i
3232

3333
#undef exit
3434

35+
__CPROVER_thread_local void (*__CPROVER_atexit_table[32])(void);
36+
__CPROVER_thread_local int __CPROVER_atexit_table_use = 0;
37+
3538
inline void exit(int status)
3639
{
40+
__CPROVER_HIDE:;
3741
(void)status;
42+
43+
while(__CPROVER_atexit_table_use > 0)
44+
{
45+
--__CPROVER_atexit_table_use;
46+
__CPROVER_atexit_table[__CPROVER_atexit_table_use]();
47+
}
48+
3849
__CPROVER_assume(0);
3950
#ifdef LIBRARY_CHECK
4051
__builtin_unreachable();
@@ -604,3 +615,28 @@ __CPROVER_HIDE:;
604615
__CPROVER_assume(result >= 0);
605616
return result;
606617
}
618+
619+
/* FUNCTION: atexit */
620+
621+
#ifndef __CPROVER_ERRNO_H_INCLUDED
622+
# include <errno.h>
623+
# define __CPROVER_ERRNO_H_INCLUDED
624+
#endif
625+
626+
#ifndef LIBRARY_CHECK
627+
__CPROVER_thread_local void (*__CPROVER_atexit_table[32])(void);
628+
__CPROVER_thread_local int __CPROVER_atexit_table_use = 0;
629+
#endif
630+
631+
int atexit(void (*function)(void))
632+
{
633+
__CPROVER_HIDE:;
634+
if(__CPROVER_atexit_table_use >= 32)
635+
{
636+
errno = ENOMEM;
637+
return -1;
638+
}
639+
640+
__CPROVER_atexit_table[__CPROVER_atexit_table_use++] = function;
641+
return 0;
642+
}

src/cpp/cpp_internal_additions.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ void cpp_internal_additions(std::ostream &out)
8989
out << "int " << rounding_mode_identifier() << " = "
9090
<< std::to_string(config.ansi_c.rounding_mode) << ';' << '\n';
9191

92+
// atexit
93+
out << "void exit(int);" << '\n';
94+
9295
// pipes, write, read, close
9396
out << "struct " CPROVER_PREFIX "pipet {\n"
9497
<< " bool widowed;\n"

src/linking/remove_internal_symbols.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ void remove_internal_symbols(
127127
special.insert("__placement_new_array");
128128
special.insert("__delete");
129129
special.insert("__delete_array");
130+
special.insert("exit");
130131

131132
for(symbol_tablet::symbolst::const_iterator
132133
it=symbol_table.symbols.begin();

0 commit comments

Comments
 (0)