Skip to content

Commit b73f968

Browse files
committed
Malloc should fail on too large allocations
via goto-checker with a dedicated cmdl option and a property that acknowledges pointer-width and object-size.
1 parent be84cd1 commit b73f968

File tree

9 files changed

+107
-2
lines changed

9 files changed

+107
-2
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <assert.h>
2+
#include <stdint.h>
3+
#include <stdlib.h>
4+
5+
int main()
6+
{
7+
size_t pointer_width = sizeof(void *) * 8;
8+
size_t object_bits = 8; // by default
9+
size_t cbmc_max_alloc_size = ((size_t)1 << (pointer_width - object_bits)) - 1;
10+
int *p = malloc(cbmc_max_alloc_size); // try to allocate exactly the max
11+
12+
return 0;
13+
}
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-size-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[malloc.max_allocation_check.\d+\] line \d+ malloc_size < 2 \^ \(pointer_width - object_size\) in ALLOCATE\(malloc_size, 0 != 0\): SUCCESS$
7+
^VERIFICATION SUCCESSFUL$
8+
--
9+
^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 <stdint.h>
3+
#include <stdlib.h>
4+
5+
int main()
6+
{
7+
size_t pointer_width = sizeof(void *) * 8;
8+
size_t object_bits = 8; // by default
9+
size_t cbmc_max_alloc_size = ((size_t)1 << (pointer_width - object_bits)) - 1;
10+
// try to allocate the smallest violating amount
11+
int *p = malloc(cbmc_max_alloc_size + 1);
12+
13+
return 0;
14+
}
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-size-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[malloc.max_allocation_check.\d+\] line \d+ malloc_size < 2 \^ \(pointer_width - object_size\) in ALLOCATE\(malloc_size, 0 != 0\): FAILURE$
7+
^VERIFICATION FAILED$
8+
--
9+
^warning: ignoring
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <assert.h>
2+
#include <stdint.h>
3+
#include <stdlib.h>
4+
5+
int main()
6+
{
7+
int *p = malloc(SIZE_MAX);
8+
assert(p);
9+
10+
return 0;
11+
}
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-size-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[malloc.max_allocation_check.\d+\] line \d+ malloc_size < 2 \^ \(pointer_width - object_size\) in ALLOCATE\(malloc_size, 0 != 0\): FAILURE$
7+
^VERIFICATION FAILED$
8+
--
9+
^warning: ignoring
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <assert.h>
2+
#include <stdint.h>
3+
#include <stdlib.h>
4+
5+
int main()
6+
{
7+
int *p = malloc(SIZE_MAX);
8+
assert(p);
9+
10+
return 0;
11+
}

src/analyses/goto_check.cpp

Lines changed: 26 additions & 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+
enable_malloc_size_check = _options.get_bool_option("malloc-size-check");
7576
}
7677

7778
typedef goto_functionst::goto_functiont goto_functiont;
@@ -238,6 +239,7 @@ class goto_checkt
238239
bool enable_assertions;
239240
bool enable_built_in_assertions;
240241
bool enable_assumptions;
242+
bool enable_malloc_size_check;
241243

242244
typedef optionst::value_listt error_labelst;
243245
error_labelst error_labels;
@@ -1941,6 +1943,30 @@ void goto_checkt::goto_check(
19411943
if(rw_ok_cond.has_value())
19421944
rhs = *rw_ok_cond;
19431945
}
1946+
1947+
if(enable_malloc_size_check && code_assign.rhs().id() == ID_side_effect)
1948+
{
1949+
const auto &rhs_side_effect = to_side_effect_expr(code_assign.rhs());
1950+
if(rhs_side_effect.get_statement() == ID_allocate)
1951+
{
1952+
const auto &alloc_size_type = rhs_side_effect.op0().type();
1953+
const auto pointer_bits =
1954+
from_integer(config.ansi_c.pointer_width, alloc_size_type);
1955+
const auto object_bits =
1956+
from_integer(config.bv_encoding.object_bits, alloc_size_type);
1957+
const auto max_alloc_size =
1958+
binary_exprt{from_integer(2, alloc_size_type),
1959+
ID_power,
1960+
minus_exprt{pointer_bits, object_bits}};
1961+
add_guarded_property(
1962+
binary_relation_exprt{rhs_side_effect.op0(), ID_lt, max_alloc_size},
1963+
"malloc_size < 2 ^ (pointer_width - object_size)",
1964+
"max allocation check",
1965+
i.code.source_location(),
1966+
code_assign.rhs(),
1967+
guardt{true_exprt{}, guard_manager});
1968+
}
1969+
}
19441970
}
19451971
else if(i.is_function_call())
19461972
{

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-size-check)"
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-size-check check that CBMC can represent the allocated object of requested size" /* NOLINT(whitespace/line_length) */ \
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-size-check", cmdline.isset("malloc-size-check"))
7477

7578
#endif // CPROVER_ANALYSES_GOTO_CHECK_H

0 commit comments

Comments
 (0)