Skip to content

Commit 11c1808

Browse files
authored
Make smallbuddy handle larger requests correctly (#556)
* Fail more abruptly if the bounds are not exact. * Move bounding from Pool into Backend. This commit makes the rounding and the bounding occur in the same function. * Enable smallbuddyrange to handle larger requests The smallbuddy can now pass the larger requests up the range chain if it cannot satisfy it itself. * Test larger requests for meta-data.
1 parent 0ea12d9 commit 11c1808

File tree

6 files changed

+70
-20
lines changed

6 files changed

+70
-20
lines changed

src/snmalloc/aal/aal_cheri.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ namespace snmalloc
8686
}
8787

8888
void* pb = __builtin_cheri_bounds_set_exact(a.unsafe_ptr(), size);
89+
90+
SNMALLOC_ASSERT(
91+
__builtin_cheri_tag_get(pb) && "capptr_bound exactness failed.");
92+
8993
return CapPtr<T, BOut>::unsafe_from(static_cast<T*>(pb));
9094
}
9195

src/snmalloc/backend/backend.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ namespace snmalloc
3939
* does not avail itself of this degree of freedom.
4040
*/
4141
template<typename T>
42-
static capptr::Arena<void>
42+
static capptr::Alloc<void>
4343
alloc_meta_data(LocalState* local_state, size_t size)
4444
{
4545
capptr::Arena<void> p;
@@ -61,9 +61,13 @@ namespace snmalloc
6161
}
6262

6363
if (p == nullptr)
64+
{
6465
errno = ENOMEM;
66+
return nullptr;
67+
}
6568

66-
return p;
69+
return capptr_to_user_address_control(
70+
Aal::capptr_bound<void, capptr::bounds::AllocFull>(p, size));
6771
}
6872

6973
/**

src/snmalloc/backend_helpers/smallbuddyrange.h

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,22 @@ namespace snmalloc
174174
base,
175175
length,
176176
[this](CapPtr<void, ChunkBounds> base, size_t align, bool) {
177-
CapPtr<void, ChunkBounds> overflow =
178-
buddy_small
179-
.add_block(
180-
base.template as_reinterpret<FreeChunk<ChunkBounds>>(), align)
181-
.template as_reinterpret<void>();
182-
if (overflow != nullptr)
183-
parent.dealloc_range(overflow, bits::one_at_bit(MIN_CHUNK_BITS));
177+
if (align < MIN_CHUNK_SIZE)
178+
{
179+
CapPtr<void, ChunkBounds> overflow =
180+
buddy_small
181+
.add_block(
182+
base.template as_reinterpret<FreeChunk<ChunkBounds>>(),
183+
align)
184+
.template as_reinterpret<void>();
185+
if (overflow != nullptr)
186+
parent.dealloc_range(
187+
overflow, bits::one_at_bit(MIN_CHUNK_BITS));
188+
}
189+
else
190+
{
191+
parent.dealloc_range(base, align);
192+
}
184193
});
185194
}
186195

@@ -204,7 +213,8 @@ namespace snmalloc
204213

205214
CapPtr<void, ChunkBounds> alloc_range(size_t size)
206215
{
207-
SNMALLOC_ASSERT(size < MIN_CHUNK_SIZE);
216+
if (size >= MIN_CHUNK_SIZE)
217+
return parent.alloc_range(size);
208218

209219
auto result = buddy_small.remove_block(size);
210220
if (result != nullptr)
@@ -218,8 +228,6 @@ namespace snmalloc
218228

219229
CapPtr<void, ChunkBounds> alloc_range_with_leftover(size_t size)
220230
{
221-
SNMALLOC_ASSERT(size < MIN_CHUNK_SIZE);
222-
223231
auto rsize = bits::next_pow2(size);
224232

225233
auto result = alloc_range(rsize);
@@ -236,8 +244,6 @@ namespace snmalloc
236244

237245
void dealloc_range(CapPtr<void, ChunkBounds> base, size_t size)
238246
{
239-
SNMALLOC_ASSERT(size < MIN_CHUNK_SIZE);
240-
241247
add_range(base, size);
242248
}
243249
};

src/snmalloc/mem/backend_concept.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ namespace snmalloc
122122
{
123123
Backend::template alloc_meta_data<void*>(local_state, size)
124124
}
125-
->ConceptSame<capptr::Arena<void>>;
125+
->ConceptSame<capptr::Alloc<void>>;
126126
}
127127
&&requires(
128128
LocalState& local_state,

src/snmalloc/mem/pool.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,8 @@ namespace snmalloc
137137
Config::Pal::error("Failed to initialise thread local allocator.");
138138
}
139139

140-
p = capptr_to_user_address_control(
141-
Aal::capptr_bound<T, capptr::bounds::AllocFull>(
142-
capptr::Arena<T>::unsafe_from(new (raw.unsafe_ptr())
143-
T(std::forward<Args>(args)...)),
144-
sizeof(T)));
140+
p = capptr::Alloc<T>::unsafe_from(new (raw.unsafe_ptr())
141+
T(std::forward<Args>(args)...));
145142

146143
FlagLock f(pool.lock);
147144
p->list_next = pool.list;

src/test/func/pool/pool.cc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <array>
2+
#include <iostream>
13
#include <snmalloc/snmalloc.h>
24
#include <test/opt.h>
35
#include <test/setup.h>
@@ -24,6 +26,23 @@ struct PoolBEntry : Pooled<PoolBEntry>
2426

2527
using PoolB = Pool<PoolBEntry, Alloc::Config>;
2628

29+
struct PoolLargeEntry : Pooled<PoolLargeEntry>
30+
{
31+
std::array<int, 2'000'000> payload;
32+
33+
PoolLargeEntry()
34+
{
35+
printf(".");
36+
fflush(stdout);
37+
payload[0] = 1;
38+
printf("first %d\n", payload[0]);
39+
payload[1'999'999] = 1;
40+
printf("last %d\n", payload[1'999'999]);
41+
};
42+
};
43+
44+
using PoolLarge = Pool<PoolLargeEntry, Alloc::Config>;
45+
2746
void test_alloc()
2847
{
2948
auto ptr = PoolA::acquire();
@@ -116,6 +135,18 @@ void test_iterator()
116135
PoolA::release(after_iteration_ptr);
117136
}
118137

138+
void test_large()
139+
{
140+
printf(".");
141+
fflush(stdout);
142+
PoolLargeEntry* p = PoolLarge::acquire();
143+
printf(".");
144+
fflush(stdout);
145+
PoolLarge::release(p);
146+
printf(".");
147+
fflush(stdout);
148+
}
149+
119150
int main(int argc, char** argv)
120151
{
121152
setup();
@@ -128,10 +159,18 @@ int main(int argc, char** argv)
128159
#endif
129160

130161
test_alloc();
162+
std::cout << "test_alloc passed" << std::endl;
131163
test_constructor();
164+
std::cout << "test_constructor passed" << std::endl;
132165
test_alloc_many();
166+
std::cout << "test_alloc_many passed" << std::endl;
133167
test_double_alloc();
168+
std::cout << "test_double_alloc passed" << std::endl;
134169
test_different_alloc();
170+
std::cout << "test_different_alloc passed" << std::endl;
135171
test_iterator();
172+
std::cout << "test_iterator passed" << std::endl;
173+
test_large();
174+
std::cout << "test_large passed" << std::endl;
136175
return 0;
137176
}

0 commit comments

Comments
 (0)