Bug fixes (#752)

* Fix overflow by alignment

* Bug fix: Ensure bytes_free is the total

The bytes freed was not added to the total, but
overrode it.  This meant it never fired. This
commit fixes that.
This commit is contained in:
Matthew Parkinson
2025-02-27 08:52:50 +00:00
committed by GitHub
parent 5f7baef755
commit 6622dc584e
3 changed files with 44 additions and 17 deletions

View File

@@ -800,7 +800,7 @@ namespace snmalloc
meta->as_key_tweak(),
domesticate);
bytes_freed = objsize * length;
bytes_freed += objsize * length;
// Update the head and the next pointer in the free list.
meta->free_queue.append_segment(

View File

@@ -129,17 +129,6 @@ namespace snmalloc
using sizeclass_compress_t = uint8_t;
constexpr SNMALLOC_FAST_PATH static size_t
aligned_size(size_t alignment, size_t size)
{
// Client responsible for checking alignment is not zero
SNMALLOC_ASSERT(alignment != 0);
// Client responsible for checking alignment is a power of two
SNMALLOC_ASSERT(bits::is_pow2(alignment));
return ((alignment - 1) | (size - 1)) + 1;
}
/**
* This structure contains the fields required for fast paths for sizeclasses.
*/
@@ -535,4 +524,43 @@ namespace snmalloc
return 1;
return bits::one_at_bit(bits::ctz(rsize));
}
constexpr SNMALLOC_FAST_PATH static size_t
aligned_size(size_t alignment, size_t size)
{
// Client responsible for checking alignment is not zero
SNMALLOC_ASSERT(alignment != 0);
// Client responsible for checking alignment is a power of two
SNMALLOC_ASSERT(bits::is_pow2(alignment));
// There are a class of corner cases to consider
// alignment = 0x8
// size = 0xfff...fff7
// for this result will be 0. This should fail an allocation, so we need to
// check for this overflow.
// However,
// alignment = 0x8
// size = 0x0
// will also result in 0, but this should be allowed to allocate.
// So we need to check for overflow, and return SIZE_MAX in this first case,
// and 0 in the second.
size_t result = ((alignment - 1) | (size - 1)) + 1;
// The following code is designed to fuse well with a subsequent
// sizeclass calculation. We use the same fast path constant to
// move the case where result==0 to the slow path, and then check for which
// case we are in.
constexpr size_t SmallSizeClassUpperBound =
sizeclass_to_size(NUM_SMALL_SIZECLASSES - 1) - 1;
if (SNMALLOC_LIKELY((result - 1) < SmallSizeClassUpperBound))
return result;
// We are in the slow path, so we need to check for overflow.
if (SNMALLOC_UNLIKELY(result == 0))
{
// Check for overflow and return the maximum size.
if (SNMALLOC_UNLIKELY(result < size))
return SIZE_MAX;
}
return result;
}
} // namespace snmalloc

View File

@@ -15,11 +15,7 @@ constexpr int SUCCESS = 0;
void check_result(size_t size, size_t align, void* p, int err, bool null)
{
bool failed = false;
EXPECT(
(errno == err) || (err == SUCCESS),
"Expected error: {} but got {}",
err,
errno);
EXPECT((errno == err), "Expected error: {} but got {}", err, errno);
if (null)
{
EXPECT(p == nullptr, "Expected null but got {}", p);
@@ -307,6 +303,9 @@ int main(int argc, char** argv)
for (size_t align = sizeof(uintptr_t); align < MAX_SMALL_SIZECLASS_SIZE * 8;
align <<= 1)
{
// Check overflow with alignment taking it round to 0.
test_memalign(1 - align, align, ENOMEM, true);
for (smallsizeclass_t sc = 0; sc < NUM_SMALL_SIZECLASSES - 6; sc++)
{
const size_t size = sizeclass_to_size(sc);