Skip to content

Commit 51b5618

Browse files
authored
Merge pull request #5298 from thk123/fix-max-alloc-size
Fix max malloc size
2 parents 7c6fb9c + 448ff24 commit 51b5618

File tree

4 files changed

+85
-2
lines changed

4 files changed

+85
-2
lines changed

src/ansi-c/ansi_c_internal_additions.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Author: Daniel Kroening, kroening@kroening.com
88

99
#include "ansi_c_internal_additions.h"
1010

11+
#include <limits>
12+
1113
#include <util/c_types.h>
1214
#include <util/config.h>
1315

@@ -120,6 +122,34 @@ static std::string architecture_string(T value, const char *s)
120122
std::string(s) + "=" + std::to_string(value) + ";\n";
121123
}
122124

125+
/// The maximum allocation size is determined by the number of bits that
126+
/// are left in the pointer of width \p pointer_width.
127+
///
128+
/// The allocation size cannot exceed the number represented by the (signed)
129+
/// offset, otherwise it would not be possible to store a pointer into a
130+
/// valid bit of memory. Therefore, the max allocation size is
131+
/// 2^(offset_bits - 1), where the offset bits is the number of bits left in the
132+
/// pointer after the object bits.
133+
///
134+
/// The offset must be signed, as a pointer can point to the end of the memory
135+
/// block, and needs to be able to point back to the start.
136+
/// \param pointer_width: The width of the pointer
137+
/// \param object_bits : The number of bits used to represent the ID
138+
/// \return The size in bytes of the maximum allocation supported.
139+
static mp_integer
140+
max_malloc_size(std::size_t pointer_width, std::size_t object_bits)
141+
{
142+
PRECONDITION(pointer_width >= 1);
143+
PRECONDITION(object_bits < pointer_width);
144+
PRECONDITION(object_bits >= 1);
145+
const auto offset_bits = pointer_width - object_bits;
146+
// We require the offset to be able to express upto allocation_size - 1,
147+
// but also down to -allocation_size, therefore the size is allowable
148+
// is number of bits, less the signed bit.
149+
const auto bits_for_positive_offset = offset_bits - 1;
150+
return ((mp_integer)1) << (mp_integer)bits_for_positive_offset;
151+
}
152+
123153
void ansi_c_internal_additions(std::string &code)
124154
{
125155
// clang-format off
@@ -162,8 +192,8 @@ void ansi_c_internal_additions(std::string &code)
162192
"int " CPROVER_PREFIX "malloc_failure_mode_assert_then_assume="+
163193
std::to_string(config.ansi_c.malloc_failure_mode_assert_then_assume)+";\n"
164194
CPROVER_PREFIX "size_t " CPROVER_PREFIX "max_malloc_size="+
165-
std::to_string(1 << (config.ansi_c.pointer_width -
166-
config.bv_encoding.object_bits - 1))+";\n"
195+
integer2string(max_malloc_size(config.ansi_c.pointer_width, config
196+
.bv_encoding.object_bits))+";\n"
167197

168198
// this is ANSI-C
169199
"extern " CPROVER_PREFIX "thread_local const char __func__["

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ SRC += analyses/ai/ai.cpp \
1414
analyses/does_remove_const/does_expr_lose_const.cpp \
1515
analyses/does_remove_const/does_type_preserve_const_correctness.cpp \
1616
analyses/does_remove_const/is_type_at_least_as_const_as.cpp \
17+
ansi-c/max_malloc_size.cpp \
1718
big-int/big-int.cpp \
1819
compound_block_locations.cpp \
1920
get_goto_model_from_c_test.cpp \

unit/ansi-c/max_malloc_size.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*******************************************************************\
2+
3+
Module: Unit test for max_malloc_size
4+
5+
Author: Thomas Kiley
6+
7+
\*******************************************************************/
8+
9+
#include <ansi-c/ansi_c_internal_additions.cpp>
10+
#include <testing-utils/use_catch.h>
11+
12+
TEST_CASE(
13+
"max_malloc_size",
14+
"[core][ansi-c][ansi_c_internal_additions][max_malloc_size]")
15+
{
16+
cbmc_invariants_should_throwt throw_invariants;
17+
18+
SECTION("Too many bits for pointer ID")
19+
{
20+
REQUIRE_THROWS_AS(max_malloc_size(4, 4), invariant_failedt);
21+
REQUIRE_THROWS_AS(max_malloc_size(4, 5), invariant_failedt);
22+
}
23+
24+
SECTION("Not enough bits for pointer ID")
25+
{
26+
REQUIRE_THROWS_AS(max_malloc_size(4, 0), invariant_failedt);
27+
}
28+
29+
SECTION("Not enough bits in the pointer")
30+
{
31+
REQUIRE_THROWS_AS(max_malloc_size(0, 0), invariant_failedt);
32+
}
33+
34+
SECTION("Max allocation size overflow")
35+
{
36+
}
37+
38+
SECTION("Valid allocation size configurations")
39+
{
40+
// The one bit offset can be used to store 0, or -1, so we can allocate
41+
// a single bit
42+
REQUIRE(max_malloc_size(4, 3) == 1);
43+
// Here we use 4 bits for the object ID, leaving 3 for the offset
44+
REQUIRE(max_malloc_size(8, 4) == 8);
45+
REQUIRE(max_malloc_size(128, 64) == 9223372036854775808ull /*2^63*/);
46+
REQUIRE(
47+
max_malloc_size(128, 63) == string2integer("18446744073709551616"
48+
/*2^64*/));
49+
}
50+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
testing-utils
2+
ansi-c

0 commit comments

Comments
 (0)