[Bug](array-type) Fix the core dump caused by unaligned __int128 (#11020)

Fix the core dump caused by unaligned __int128 and change DEFAULT_ALIGNMENT
This commit is contained in:
Adonis Ling
2022-07-20 16:37:27 +08:00
committed by GitHub
parent a71822a74d
commit e5663f9872
7 changed files with 83 additions and 5 deletions

View File

@ -480,13 +480,15 @@ Status CollectionValue::init_collection(CollectionValue* value, const AllocateMe
Status CollectionValue::init_collection(MemPool* pool, uint64_t size, PrimitiveType child_type,
CollectionValue* value) {
return init_collection(
value, [pool](size_t size) { return pool->allocate(size); }, size, child_type);
value, [pool](size_t size) { return pool->allocate_aligned(size, 16); }, size,
child_type);
}
Status CollectionValue::init_collection(FunctionContext* context, uint64_t size,
PrimitiveType child_type, CollectionValue* value) {
return init_collection(
value, [context](size_t size) { return context->allocate(size); }, size, child_type);
value, [context](size_t size) { return context->aligned_allocate(16, size); }, size,
child_type);
}
CollectionValue CollectionValue::from_collection_val(const CollectionVal& val) {

View File

@ -82,6 +82,42 @@ public:
return reinterpret_cast<uint8_t*>(allocation) + sizeof(FreeListNode);
}
// Allocates a buffer of size.
uint8_t* aligned_allocate(int alignment, int64_t size) {
// The alignment should be a power of 2.
DCHECK(alignment > 0 && ((alignment - 1) & alignment) == 0);
// This is the typical malloc behavior. NULL is reserved for failures.
if (size == 0) {
return reinterpret_cast<uint8_t*>(alignment);
}
int padding = sizeof(FreeListNode) >= alignment ? 0 : (alignment - sizeof(FreeListNode));
size += padding;
// Do ceil(log_2(size))
int free_list_idx = BitUtil::log2(size);
DCHECK_LT(free_list_idx, NUM_LISTS);
FreeListNode* allocation = _lists[free_list_idx].next;
if (allocation == nullptr) {
// There wasn't an existing allocation of the right size, allocate a new one.
size = 1L << free_list_idx;
allocation = reinterpret_cast<FreeListNode*>(
_mem_pool->allocate_aligned(size + sizeof(FreeListNode), alignment));
} else {
// Remove this allocation from the list.
_lists[free_list_idx].next = allocation->next;
}
DCHECK(allocation != nullptr);
// Set the back node to point back to the list it came from so know where
// to add it on free().
allocation->list = &_lists[free_list_idx];
return reinterpret_cast<uint8_t*>(allocation) + sizeof(FreeListNode) + padding;
}
void free(uint8_t* ptr) {
if (ptr == NULL || reinterpret_cast<int64_t>(ptr) == 0x1) {
return;

View File

@ -104,7 +104,6 @@ public:
/// of the current chunk. Creates a new chunk if there aren't any chunks
/// with enough capacity.
uint8_t* allocate(int64_t size, Status* rst = nullptr) {
// TODO: rethink if DEFAULT_ALIGNMENT should be changed, malloc is aligned by 16.
return allocate<false>(size, DEFAULT_ALIGNMENT, rst);
}
@ -170,7 +169,10 @@ public:
MemTracker* mem_tracker() { return _mem_tracker; }
static constexpr int DEFAULT_ALIGNMENT = 8;
// The memory for __int128 should be aligned to 16 bytes.
// By the way, in 64-bit system, the address of a block returned by malloc or realloc in GNU systems
// is always a multiple of sixteen. (https://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html)
static constexpr int DEFAULT_ALIGNMENT = 16;
#if (defined(__SANITIZE_ADDRESS__) || defined(ADDRESS_SANITIZER)) && !defined(BE_TEST)
static constexpr int DEFAULT_PADDING_SIZE = 0x10;

View File

@ -49,6 +49,9 @@ public:
FreePool(MemPool*) {}
uint8_t* allocate(int byte_size) { return reinterpret_cast<uint8_t*>(malloc(byte_size)); }
uint8_t* aligned_allocate(int alignment, int byte_size) {
return reinterpret_cast<uint8_t*>(aligned_alloc(alignment, byte_size));
}
uint8_t* reallocate(uint8_t* ptr, int byte_size) {
return reinterpret_cast<uint8_t*>(realloc(ptr, byte_size));
@ -271,6 +274,17 @@ uint8_t* FunctionContext::allocate(int byte_size) {
return buffer;
}
uint8_t* FunctionContext::aligned_allocate(int alignment, int byte_size) {
uint8_t* buffer = _impl->_pool->aligned_allocate(alignment, byte_size);
_impl->_allocations[buffer] = byte_size;
if (_impl->_debug) {
memset(buffer, 0xff, byte_size);
}
return buffer;
}
uint8_t* FunctionContext::reallocate(uint8_t* ptr, int byte_size) {
_impl->_allocations.erase(ptr);
ptr = _impl->_pool->reallocate(ptr, byte_size);

View File

@ -176,6 +176,13 @@ public:
// in this object causing the query to fail.
uint8_t* allocate(int byte_size);
// Allocate and align memory for UDAs. All UDA allocations should use this if possible instead of
// malloc/new. The UDA is responsible for calling Free() on all buffers returned
// by Allocate().
// If this Allocate causes the memory limit to be exceeded, the error will be set
// in this object causing the query to fail.
uint8_t* aligned_allocate(int alignment, int byte_size);
// Reallocates 'ptr' to the new byte_size. If the currently underlying allocation
// is big enough, the original ptr will be returned. If the allocation needs to
// grow, a new allocation is made that is at least 'byte_size' and the contents

View File

@ -210,7 +210,7 @@ private:
break;
}
case TYPE_DECIMALV2: {
*val = reinterpret_cast<AnyVal*>(context->allocate(sizeof(DecimalV2Val)));
*val = reinterpret_cast<AnyVal*>(context->aligned_allocate(16, sizeof(DecimalV2Val)));
new (*val) DecimalV2Val();
if (iterator->IsNumber()) {

View File

@ -172,4 +172,21 @@ TEST(ArrayParserTest, TestDecimalArray) {
value = {data, num_items, false, nullptr};
test_array_parser(column_pb, "[2147483647.5, \"34359738368.5\"]", value);
}
TEST(ArrayParserTest, TestFreePool) {
auto column_pb = create_column_pb("ARRAY", "DECIMAL");
MemTracker tracker(1024 * 1024, "ArrayParserTest");
MemPool mem_pool(&tracker);
FunctionContext context;
ArrayUtils::prepare_context(context, mem_pool, column_pb);
int alignment = 1;
for (int i = 1; i <= 4; ++i) {
alignment <<= 1;
auto* p = context.aligned_allocate(alignment, alignment);
EXPECT_TRUE(reinterpret_cast<uint64_t>(p) % alignment == 0);
p = context.aligned_allocate(alignment, alignment);
EXPECT_TRUE(reinterpret_cast<uint64_t>(p) % alignment == 0);
}
}
} // namespace doris