Skip to content

fix(memory): PoolAllocator::Free and Clear use C-style cast without placement new — UB per C++ object model #682

Description

@JeanPhilippeKernel

Summary

PoolAllocator::Free() and PoolAllocator::Clear() reinterpret raw memory as a PoolFreeNode via a C-style cast and write through the resulting pointer without constructing the object via placement new. This is undefined behaviour under the C++ object model.

Location

ZEngine/ZEngine/Core/Memory/Allocator.cpp:268Free():

PoolFreeNode* node = (PoolFreeNode*) ptr;
node->Next = head;

ZEngine/ZEngine/Core/Memory/Allocator.cpp:282Clear():

PoolFreeNode* node = (PoolFreeNode*) ptr;
node->Next = head;

Detail

Writing through a pointer cast from raw memory where no object of that type has been constructed is UB per [basic.life] — the object's lifetime has not begun. The compiler is permitted to assume no aliasing and eliminate or reorder such writes.

In practice every compiler generates correct code for trivially-copyable PoolFreeNode on x86-64 / ARM64. But the UB is latent and may be exposed by aggressive LTO, sanitizers (UBSAN will flag it), or future compiler versions.

Fix

Use placement new to start the object's lifetime before writing:

// Free():
auto* node = ::new (ptr) PoolFreeNode{head};
head = node;

// Clear():
auto* node = ::new (&memory[i * chunk_size]) PoolFreeNode{head};
head = node;

PoolFreeNode is trivially destructible so no matching destroy call is needed.

Impact

Low practical risk on current toolchain; UBSAN will flag it. Alignment: the chunk is guaranteed >= sizeof(PoolFreeNode) and aligned to the pool's alignment — so only the lifetime issue remains.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions