Skip to content

Commit d97765e

Browse files
committed
Add malloc-may-fail option to goto-checker
and hard-code appropriate assertion inside our `stdlib.c`.
1 parent 4682d07 commit d97765e

File tree

8 files changed

+45
-15
lines changed

8 files changed

+45
-15
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <stdlib.h>
2+
3+
int main()
4+
{
5+
char *p = malloc(100); // may fail, since malloc may fail
6+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
--malloc-may-fail
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[malloc.assertion.\d+\] line \d+ malloc may fail: FAILURE$
7+
^VERIFICATION FAILED$
8+
--
9+
^warning: ignoring

src/analyses/goto_check.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class goto_checkt
7272
enable_built_in_assertions=_options.get_bool_option("built-in-assertions");
7373
enable_assumptions=_options.get_bool_option("assumptions");
7474
error_labels=_options.get_list_option("error-label");
75+
config.ansi_c.malloc_may_fail = _options.get_bool_option("malloc-may-fail");
7576
}
7677

7778
typedef goto_functionst::goto_functiont goto_functiont;

src/analyses/goto_check.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ void goto_check(
3838
"(div-by-zero-check)(enum-range-check)(signed-overflow-check)(unsigned-" \
3939
"overflow-check)" \
4040
"(pointer-overflow-check)(conversion-check)(undefined-shift-check)" \
41-
"(float-overflow-check)(nan-check)(no-built-in-assertions)"
41+
"(float-overflow-check)(nan-check)(no-built-in-assertions)" \
42+
"(malloc-may-fail)"
4243

4344
// clang-format off
4445
#define HELP_GOTO_CHECK \
@@ -55,6 +56,7 @@ void goto_check(
5556
" --nan-check check floating-point for NaN\n" \
5657
" --no-built-in-assertions ignore assertions in built-in library\n" \
5758
" --enum-range-check checks that all enum type expressions have values in the enum range\n" /* NOLINT(whitespace/line_length) */ \
59+
" --malloc-may-fail enable failures for malloc calls\n" \
5860
// clang-format on
5961

6062
#define PARSE_OPTIONS_GOTO_CHECK(cmdline, options) \
@@ -70,6 +72,7 @@ void goto_check(
7072
options.set_option("undefined-shift-check", cmdline.isset("undefined-shift-check")); /* NOLINT(whitespace/line_length) */ \
7173
options.set_option("float-overflow-check", cmdline.isset("float-overflow-check")); /* NOLINT(whitespace/line_length) */ \
7274
options.set_option("nan-check", cmdline.isset("nan-check")); \
73-
options.set_option("built-in-assertions", !cmdline.isset("no-built-in-assertions")) /* NOLINT(whitespace/line_length) */
75+
options.set_option("built-in-assertions", !cmdline.isset("no-built-in-assertions")); /* NOLINT(whitespace/line_length) */ \
76+
options.set_option("malloc-may-fail", cmdline.isset("malloc-may-fail"))
7477

7578
#endif // CPROVER_ANALYSES_GOTO_CHECK_H

src/ansi-c/ansi_c_internal_additions.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ void ansi_c_internal_additions(std::string &code)
155155
"void *" CPROVER_PREFIX "allocate("
156156
CPROVER_PREFIX "size_t size, " CPROVER_PREFIX "bool zero);\n"
157157
"const void *" CPROVER_PREFIX "alloca_object = 0;\n"
158+
CPROVER_PREFIX "bool " CPROVER_PREFIX "malloc_may_fail = " + (config.ansi_c.malloc_may_fail ? "1" : "0") + ";\n"
158159

159160
// this is ANSI-C
160161
"extern " CPROVER_PREFIX "thread_local const char __func__["

src/ansi-c/library/cprover.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ extern const void *__CPROVER_malloc_object;
1616
extern __CPROVER_size_t __CPROVER_malloc_size;
1717
extern _Bool __CPROVER_malloc_is_new_array;
1818
extern const void *__CPROVER_memory_leak;
19+
extern _Bool __CPROVER_malloc_may_fail;
1920

2021
void __CPROVER_assume(__CPROVER_bool assumption) __attribute__((__noreturn__));
2122
void __CPROVER_assert(__CPROVER_bool assertion, const char *description);

src/ansi-c/library/stdlib.c

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -115,23 +115,31 @@ inline void *malloc(__CPROVER_size_t malloc_size)
115115
// realistically, malloc may return NULL,
116116
// and __CPROVER_allocate doesn't, but no one cares
117117
__CPROVER_HIDE:;
118-
void *malloc_res;
119-
malloc_res = __CPROVER_allocate(malloc_size, 0);
120118

121-
// make sure it's not recorded as deallocated
122-
__CPROVER_deallocated=(malloc_res==__CPROVER_deallocated)?0:__CPROVER_deallocated;
119+
__CPROVER_assert(
120+
__CPROVER_malloc_may_fail != (__CPROVER_bool)0, "malloc may fail");
123121

124-
// record the object size for non-determistic bounds checking
125-
__CPROVER_bool record_malloc=__VERIFIER_nondet___CPROVER_bool();
126-
__CPROVER_malloc_object=record_malloc?malloc_res:__CPROVER_malloc_object;
127-
__CPROVER_malloc_size=record_malloc?malloc_size:__CPROVER_malloc_size;
128-
__CPROVER_malloc_is_new_array=record_malloc?0:__CPROVER_malloc_is_new_array;
122+
void *malloc_res;
123+
malloc_res = __CPROVER_allocate(malloc_size, 0);
129124

130-
// detect memory leaks
131-
__CPROVER_bool record_may_leak=__VERIFIER_nondet___CPROVER_bool();
132-
__CPROVER_memory_leak=record_may_leak?malloc_res:__CPROVER_memory_leak;
125+
// make sure it's not recorded as deallocated
126+
__CPROVER_deallocated =
127+
(malloc_res == __CPROVER_deallocated) ? 0 : __CPROVER_deallocated;
133128

134-
return malloc_res;
129+
// record the object size for non-determistic bounds checking
130+
__CPROVER_bool record_malloc = __VERIFIER_nondet___CPROVER_bool();
131+
__CPROVER_malloc_object =
132+
record_malloc ? malloc_res : __CPROVER_malloc_object;
133+
__CPROVER_malloc_size = record_malloc ? malloc_size : __CPROVER_malloc_size;
134+
__CPROVER_malloc_is_new_array =
135+
record_malloc ? 0 : __CPROVER_malloc_is_new_array;
136+
137+
// detect memory leaks
138+
__CPROVER_bool record_may_leak = __VERIFIER_nondet___CPROVER_bool();
139+
__CPROVER_memory_leak =
140+
record_may_leak ? malloc_res : __CPROVER_memory_leak;
141+
142+
return malloc_res;
135143
}
136144

137145
/* FUNCTION: __builtin_alloca */

src/util/config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class configt
129129
libt lib;
130130

131131
bool string_abstraction;
132+
bool malloc_may_fail = false;
132133

133134
static const std::size_t default_object_bits=8;
134135
} ansi_c;

0 commit comments

Comments
 (0)