Skip to content

Commit fb0601b

Browse files
committed
[TPDE] Avoid ValueAssignment leaks
Avoid leaking large ValueAssignments when compilation fails by allocating all assignments through the bump allocator, which will take care of freeing the allocation in all cases. To avoid excessive memory usage, all ValueAssignment allocations are now recycled in free lists. Additionally, modify AddressSanitizer options to abort on errors to avoid hiding the leak behind "not" in the compilation failure case.
1 parent 669de34 commit fb0601b

File tree

6 files changed

+33
-15
lines changed

6 files changed

+33
-15
lines changed

tpde-llvm/test/diagnostics/incompatible.ll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,11 @@ define void @f_v4i64_2(<4 x i64>) {
126126
define void @f_v4i64_3([2 x <4 x i64>]) {
127127
ret void
128128
}
129+
130+
; CHECK: type with incompatible layout at function/call: [2 x <4 x i25>]
131+
; CHECK-NEXT: unsupported type: [2 x <4 x i25>]
132+
; CHECK-NEXT: Failed to compile function f_call_v4i25_2
133+
define void @f_call_v4i25_2(ptr %f) {
134+
call void %f([2 x <4 x i25>] zeroinitializer)
135+
ret void
136+
}

tpde-llvm/test/diagnostics/large-types.ll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,13 @@ define void @f_sa40000i8a40000i8(ptr %p) {
2828
store {[40000 x i8], [40000 x i8]} %l, ptr %p
2929
ret void
3030
}
31+
32+
; CHECK: Failed to compile instruction store atomic [40000 x i8] %l
33+
; CHECK: Failed to compile function f_atomic_a40000i8
34+
; Note: check that large value assignment doesn't leak.
35+
define void @f_atomic_a40000i8(ptr %p) {
36+
%l = load [40000 x i8], ptr %p
37+
store atomic [40000 x i8] %l, ptr %p monotonic, align 1
38+
store atomic [40000 x i8] %l, ptr %p monotonic, align 1
39+
ret void
40+
}

tpde-llvm/test/lit.cfg.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
# Tweak the PATH to include the tools dir and TPDE binaries.
1919
llvm_config.with_environment('PATH', config.llvm_tools_dir, append_path=True)
2020
llvm_config.with_environment('PATH', config.tpde_llvm_bin_dir, append_path=True)
21+
# Abort on ASan errors so that also tests running with "not" fail.
22+
llvm_config.with_environment('ASAN_OPTIONS', "abort_on_error=1", append_path=True)
2123
config.substitutions.append(('tpde-llc', 'tpde-llc --regular-exit'))
2224
config.substitutions.append(('%objdump', 'llvm-objdump -d -r --no-show-raw-insn --symbolize-operands --no-addresses --x86-asm-syntax=intel -'))
2325

tpde/include/tpde/ValueAssignment.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ class AssignmentAllocator {
9393
// Free list 2 holds twice as much as free list 1. Etc.
9494
static constexpr size_t SlabSize = 16 * 1024;
9595

96-
static constexpr u32 NumFreeLists = 2;
96+
// TODO: define a sensible limit on the maximum number of parts and reduce the
97+
// number of free lists. Currently the limit is a little under 2**31; limiting
98+
// the number to e.g. 2**16 would allow halving the number of free lists,
99+
// where most are unused in the vast majority of cases.
100+
static constexpr u32 NumFreeLists = 29;
97101
static constexpr u32 FirstPartOff = offsetof(ValueAssignment, parts);
98102

99103
public:

tpde/src/ValueAssignment.cpp

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include "tpde/ValueAssignment.hpp"
55

6+
#include <limits>
7+
68
namespace tpde {
79

810
namespace {
@@ -23,6 +25,7 @@ AssignmentAllocInfo::AssignmentAllocInfo(u32 part_count) noexcept {
2325
alloc_size = VASize;
2426
free_list_idx = 0;
2527
if (part_count > AssignmentAllocator::NumPartsIncluded) {
28+
assert(part_count < (std::numeric_limits<u32>::max() - VASize) / PartSize);
2629
size += (part_count - AssignmentAllocator::NumPartsIncluded) * PartSize;
2730
// Round size to next power of two.
2831
static_assert((VASize & (VASize - 1)) == 0,
@@ -40,11 +43,6 @@ ValueAssignment *
4043
bool skip_free_list) noexcept {
4144
AssignmentAllocInfo aai(part_count);
4245

43-
if (aai.free_list_idx >= fixed_free_lists.size()) [[unlikely]] {
44-
auto *alloc = new std::byte[aai.size];
45-
return new (reinterpret_cast<ValueAssignment *>(alloc)) ValueAssignment{};
46-
}
47-
4846
if (!skip_free_list) {
4947
auto &free_list = fixed_free_lists[aai.free_list_idx];
5048
if (auto *assignment = free_list) {
@@ -54,22 +52,16 @@ ValueAssignment *
5452
}
5553
}
5654

57-
assert(aai.alloc_size < SlabSize);
5855
auto *buf = alloc.allocate(aai.alloc_size, alignof(ValueAssignment));
5956
return new (reinterpret_cast<ValueAssignment *>(buf)) ValueAssignment{};
6057
}
6158

6259
void AssignmentAllocator::deallocate_slow(
6360
ValueAssignment *assignment) noexcept {
6461
AssignmentAllocInfo aai(assignment->part_count);
65-
if (aai.free_list_idx < fixed_free_lists.size()) [[likely]] {
66-
assignment->next_free_list_entry = fixed_free_lists[aai.free_list_idx];
67-
fixed_free_lists[aai.free_list_idx] = assignment;
68-
util::poison_memory_region(assignment, aai.size);
69-
} else {
70-
assignment->~ValueAssignment();
71-
delete[] reinterpret_cast<std::byte *>(assignment);
72-
}
62+
assignment->next_free_list_entry = fixed_free_lists[aai.free_list_idx];
63+
fixed_free_lists[aai.free_list_idx] = assignment;
64+
util::poison_memory_region(assignment, aai.size);
7365
}
7466

7567
} // namespace tpde

tpde/test/filetest/lit.cfg.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,7 @@
1818
# Tweak the PATH to include the tools dir.
1919
llvm_config.with_environment('PATH', config.llvm_tools_dir, append_path=True)
2020
llvm_config.with_environment('PATH', config.tpde_obj_root, append_path=True)
21+
# Abort on ASan errors so that also tests running with "not" fail.
22+
llvm_config.with_environment('ASAN_OPTIONS', "abort_on_error=1", append_path=True)
2123
config.substitutions.append(("%tpde_test", "tpde_test"))
2224
config.substitutions.append(('%objdump', 'llvm-objdump -d -r --no-show-raw-insn --symbolize-operands --no-addresses --x86-asm-syntax=intel -'))

0 commit comments

Comments
 (0)