Skip to content

Commit 5b66bbb

Browse files
committed
Detect use of free() with alloca-allocated objects
As we internally use dynamic allocation, we previously did not distinguish alloca-allocated from malloc/calloc-allocated ones.
1 parent b02b2fd commit 5b66bbb

File tree

12 files changed

+39
-8
lines changed

12 files changed

+39
-8
lines changed

regression/cbmc/alloca1/main.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <stdlib.h>
2+
3+
int main()
4+
{
5+
int *p = alloca(sizeof(int));
6+
*p = 42;
7+
free(p);
8+
}

regression/cbmc/alloca1/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+
--pointer-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
free called for stack-allocated object: FAILURE$
8+
^\*\* 1 of 12 failed
9+
--
10+
^warning: ignoring

regression/cbmc/function-return-no-body1/test.desc

Lines changed: 2 additions & 2 deletions
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-
<function_call hidden="false" step_nr="18" thread="0">\n\s*<function display_name="no_body" identifier="no_body">
9-
<function_return hidden="false" step_nr="19" thread="0">\n\s*<function display_name="no_body" identifier="no_body">
8+
<function_call hidden="false" step_nr="19" thread="0">\n\s*<function display_name="no_body" identifier="no_body">
9+
<function_return hidden="false" step_nr="20" thread="0">\n\s*<function display_name="no_body" identifier="no_body">
1010
--
1111
^warning: ignoring

regression/goto-analyzer/constant_propagation_01/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ main.c
44
^EXIT=0$
55
^SIGNAL=0$
66
^Simplified: assert: 1, assume: 0, goto: 1, assigns: 5, function calls: 0$
7-
^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 12, function calls: 2$
7+
^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 13, function calls: 2$
88
--
99
^warning: ignoring

regression/goto-analyzer/constant_propagation_02/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ main.c
44
^EXIT=0$
55
^SIGNAL=0$
66
^Simplified: assert: 1, assume: 0, goto: 1, assigns: 6, function calls: 0$
7-
^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 11, function calls: 2$
7+
^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 12, function calls: 2$
88
--
99
^warning: ignoring

regression/goto-analyzer/constant_propagation_03/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ main.c
44
^EXIT=0$
55
^SIGNAL=0$
66
^Simplified: assert: 1, assume: 0, goto: 1, assigns: 6, function calls: 0$
7-
^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 11, function calls: 2$
7+
^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 12, function calls: 2$
88
--
99
^warning: ignoring

regression/goto-analyzer/constant_propagation_04/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ main.c
44
^EXIT=0$
55
^SIGNAL=0$
66
^Simplified: assert: 1, assume: 0, goto: 1, assigns: 6, function calls: 0$
7-
^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 11, function calls: 2$
7+
^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 12, function calls: 2$
88
--
99
^warning: ignoring

regression/goto-analyzer/constant_propagation_07/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ main.c
44
^EXIT=0$
55
^SIGNAL=0$
66
^Simplified: assert: 1, assume: 0, goto: 3, assigns: 11, function calls: 0$
7-
^Unmodified: assert: 0, assume: 0, goto: 1, assigns: 9, function calls: 2$
7+
^Unmodified: assert: 0, assume: 0, goto: 1, assigns: 10, function calls: 2$
88
--
99
^warning: ignoring

regression/goto-analyzer/constant_propagation_12/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ main.c
44
^EXIT=0$
55
^SIGNAL=0$
66
^Simplified: assert: 1, assume: 0, goto: 1, assigns: 5, function calls: 0$
7-
^Unmodified: assert: 0, assume: 0, goto: 1, assigns: 10, function calls: 2$
7+
^Unmodified: assert: 0, assume: 0, goto: 1, assigns: 11, function calls: 2$
88
--
99
^warning: ignoring

src/ansi-c/ansi_c_internal_additions.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ void ansi_c_internal_additions(std::string &code)
148148
"const void *" CPROVER_PREFIX "memory_leak=0;\n"
149149
"void *" CPROVER_PREFIX "allocate("
150150
CPROVER_PREFIX "size_t size, " CPROVER_PREFIX "bool zero);\n"
151+
"const void *" CPROVER_PREFIX "alloca_object = 0;\n"
151152

152153
// this is ANSI-C
153154
"extern " CPROVER_PREFIX "thread_local const char __func__["

src/ansi-c/library/stdlib.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ inline void *malloc(__CPROVER_size_t malloc_size)
128128
/* FUNCTION: __builtin_alloca */
129129

130130
__CPROVER_bool __VERIFIER_nondet___CPROVER_bool();
131+
extern void *__CPROVER_alloca_object;
131132

132133
inline void *__builtin_alloca(__CPROVER_size_t alloca_size)
133134
{
@@ -144,6 +145,10 @@ inline void *__builtin_alloca(__CPROVER_size_t alloca_size)
144145
__CPROVER_malloc_size=record_malloc?alloca_size:__CPROVER_malloc_size;
145146
__CPROVER_malloc_is_new_array=record_malloc?0:__CPROVER_malloc_is_new_array;
146147

148+
// record alloca to detect invalid free
149+
__CPROVER_bool record_alloca = __VERIFIER_nondet___CPROVER_bool();
150+
__CPROVER_alloca_object = record_alloca ? res : __CPROVER_alloca_object;
151+
147152
return res;
148153
}
149154

@@ -152,6 +157,7 @@ inline void *__builtin_alloca(__CPROVER_size_t alloca_size)
152157
#undef free
153158

154159
__CPROVER_bool __VERIFIER_nondet___CPROVER_bool();
160+
extern void *__CPROVER_alloca_object;
155161

156162
inline void free(void *ptr)
157163
{
@@ -173,6 +179,11 @@ inline void free(void *ptr)
173179
!__CPROVER_malloc_is_new_array,
174180
"free called for new[] object");
175181

182+
// catch people who try to use free(...) with alloca
183+
__CPROVER_precondition(
184+
ptr == 0 || __CPROVER_alloca_object != ptr,
185+
"free called for stack-allocated object");
186+
176187
if(ptr!=0)
177188
{
178189
// non-deterministically record as deallocated

src/cpp/cpp_internal_additions.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ void cpp_internal_additions(std::ostream &out)
8585
out << "const void *" CPROVER_PREFIX "memory_leak = 0;" << '\n';
8686
out << "void *" CPROVER_PREFIX "allocate("
8787
<< CPROVER_PREFIX "size_t size, " CPROVER_PREFIX "bool zero);" << '\n';
88+
out << "const void *" CPROVER_PREFIX "alloca_object = 0;" << '\n';
8889

8990
// auxiliaries for new/delete
9091
out << "void *__new(__CPROVER::size_t);" << '\n';

0 commit comments

Comments
 (0)