Skip to content

Commit 34e8aff

Browse files
authored
[Support] Recycler: Enforce minimum allocation size (#121425)
Recycler uses reinterpret_cast to an internal structure of size 8. Invalid write occurs if Recycler is used for objects with sizes less than 8.
1 parent 41ebbed commit 34e8aff

File tree

3 files changed

+49
-0
lines changed

3 files changed

+49
-0
lines changed

llvm/include/llvm/Support/Recycler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ class Recycler {
8585
"Recycler allocation alignment is less than object align!");
8686
static_assert(sizeof(SubClass) <= Size,
8787
"Recycler allocation size is less than object size!");
88+
static_assert(Size >= sizeof(FreeNode) &&
89+
"Recycler size must be at least sizeof(FreeNode)");
8890
return FreeList ? reinterpret_cast<SubClass *>(pop_val())
8991
: static_cast<SubClass *>(Allocator.Allocate(Size, Align));
9092
}

llvm/unittests/Support/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ add_llvm_unittest(SupportTests
6969
PerThreadBumpPtrAllocatorTest.cpp
7070
ProcessTest.cpp
7171
ProgramTest.cpp
72+
RecyclerTest.cpp
7273
RegexTest.cpp
7374
ReverseIterationTest.cpp
7475
ReplaceFileTest.cpp
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===--- unittest/Support/RecyclerTest.cpp --------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/Support/Recycler.h"
10+
#include "llvm/Support/AllocatorBase.h"
11+
#include "gtest/gtest.h"
12+
13+
using namespace llvm;
14+
15+
namespace {
16+
17+
struct Object1 {
18+
char Data[1];
19+
};
20+
21+
class DecoratedMallocAllocator : public MallocAllocator {
22+
public:
23+
int DeallocCount = 0;
24+
25+
template <typename T> void Deallocate(T *Ptr) {
26+
DeallocCount++;
27+
MallocAllocator::Deallocate(Ptr);
28+
}
29+
};
30+
31+
TEST(RecyclerTest, RecycleAllocation) {
32+
DecoratedMallocAllocator Allocator;
33+
// Recycler needs size to be atleast 8 bytes.
34+
Recycler<Object1, 8, 8> R;
35+
Object1 *A1 = R.Allocate(Allocator);
36+
Object1 *A2 = R.Allocate(Allocator);
37+
R.Deallocate(Allocator, A2);
38+
Object1 *A3 = R.Allocate(Allocator);
39+
EXPECT_EQ(A2, A3); // reuse the deallocated object.
40+
R.Deallocate(Allocator, A1);
41+
R.Deallocate(Allocator, A3);
42+
R.clear(Allocator); // Should deallocate A1 and A3.
43+
EXPECT_EQ(Allocator.DeallocCount, 2);
44+
}
45+
46+
} // end anonymous namespace

0 commit comments

Comments
 (0)