simple allocation debugger
This can be enabled by using the Tracking::Debug policy, currently this just fills allocation on alloc() and free(), which is useful to help detect access to uninitialized memory and use after free. Now enabled by default in libfilament allocators on debug builds. This caught uninitialized access in the froxelizer.
This commit is contained in:
committed by
Mathias Agopian
parent
c0de0ca36d
commit
844dde4e6d
@@ -195,11 +195,8 @@ bool Froxelizer::prepare(
|
||||
assert(mLightRecords.begin());
|
||||
assert(mFroxelShardedData.begin());
|
||||
|
||||
#ifndef NDEBUG
|
||||
memset(mFroxelBufferUser.data(), 0x55, mFroxelBufferUser.sizeInBytes());
|
||||
memset(mRecordBufferUser.data(), 0xEB, mRecordBufferUser.sizeInBytes());
|
||||
memset(mFroxelShardedData.data(), 0xFD, mFroxelShardedData.sizeInBytes());
|
||||
#endif
|
||||
// initialize buffers that need to be
|
||||
memset(mLightRecords.data(),0, mLightRecords.sizeInBytes());
|
||||
|
||||
return uniformsNeedUpdating;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ using HeapAllocatorArena = utils::Arena<
|
||||
using LinearAllocatorArena = utils::Arena<
|
||||
utils::LinearAllocator,
|
||||
utils::LockingPolicy::NoLock,
|
||||
utils::TrackingPolicy::HighWatermark>;
|
||||
utils::TrackingPolicy::Debug>;
|
||||
|
||||
#else
|
||||
|
||||
|
||||
@@ -440,6 +440,7 @@ using Mutex = utils::Mutex;
|
||||
|
||||
namespace TrackingPolicy {
|
||||
|
||||
// default no-op tracker
|
||||
struct Untracked {
|
||||
Untracked() noexcept = default;
|
||||
Untracked(const char* name, size_t size) noexcept { }
|
||||
@@ -449,24 +450,16 @@ struct Untracked {
|
||||
void onRewind(void* addr) noexcept { }
|
||||
};
|
||||
|
||||
// This high watermark tracker works only with allocator that either implement
|
||||
// free(void*, size_t), or reset() / rewind()
|
||||
|
||||
// This just track the max memory usage and logs it in the destructor
|
||||
struct HighWatermark {
|
||||
HighWatermark() noexcept = default;
|
||||
HighWatermark(const char* name, size_t size) noexcept
|
||||
: mName(name), mSize(uint32_t(size)) { }
|
||||
HighWatermark(const char* name, size_t size) noexcept : mName(name), mSize(uint32_t(size)) { }
|
||||
~HighWatermark() noexcept;
|
||||
void onAlloc(void* p, size_t size, size_t alignment, size_t extra) noexcept {
|
||||
if (!mBase) { mBase = p; }
|
||||
mCurrent += uint32_t(size);
|
||||
mHighWaterMark = mCurrent > mHighWaterMark ? mCurrent : mHighWaterMark;
|
||||
}
|
||||
void onAlloc(void* p, size_t size, size_t alignment, size_t extra) noexcept;
|
||||
void onFree(void* p, size_t size) noexcept { mCurrent -= uint32_t(size); }
|
||||
void onReset() noexcept { mCurrent = 0; }
|
||||
void onRewind(void const* addr) noexcept { mCurrent = uint32_t(uintptr_t(addr) - uintptr_t(mBase)); }
|
||||
|
||||
private:
|
||||
protected:
|
||||
const char* mName = nullptr;
|
||||
void* mBase = nullptr;
|
||||
uint32_t mSize = 0;
|
||||
@@ -474,6 +467,18 @@ private:
|
||||
uint32_t mHighWaterMark = 0;
|
||||
};
|
||||
|
||||
// This just fills buffers with known values to help catch uninitialized access and use after free.
|
||||
// It also tracks the high water mark
|
||||
struct Debug : protected HighWatermark {
|
||||
Debug() noexcept = default;
|
||||
Debug(const char* name, size_t size) noexcept : HighWatermark(name, size) { }
|
||||
void onAlloc(void* p, size_t size, size_t alignment, size_t extra) noexcept;
|
||||
void onFree(void* p, size_t = 0) noexcept;
|
||||
void onReset() noexcept;
|
||||
void onRewind(void* addr) noexcept;
|
||||
};
|
||||
|
||||
|
||||
} // namespace TrackingPolicy
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -125,6 +125,15 @@ AtomicFreeList::AtomicFreeList(void* begin, void* end,
|
||||
mHead.store({ int32_t(head - mStorage), 0 });
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void TrackingPolicy::HighWatermark::onAlloc(
|
||||
void* p, size_t size, size_t alignment, size_t extra) noexcept {
|
||||
if (!mBase) { mBase = p; }
|
||||
mCurrent += uint32_t(size);
|
||||
mHighWaterMark = mCurrent > mHighWaterMark ? mCurrent : mHighWaterMark;
|
||||
}
|
||||
|
||||
TrackingPolicy::HighWatermark::~HighWatermark() noexcept {
|
||||
size_t wm = mHighWaterMark;
|
||||
size_t wmpct = wm / (mSize / 100);
|
||||
@@ -134,4 +143,29 @@ TrackingPolicy::HighWatermark::~HighWatermark() noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void TrackingPolicy::Debug::onAlloc(void* p, size_t size, size_t alignment, size_t extra) noexcept {
|
||||
memset(p, 0xeb, size);
|
||||
HighWatermark::onAlloc(p, size, alignment, extra);
|
||||
}
|
||||
|
||||
void TrackingPolicy::Debug::onFree(void* p, size_t size) noexcept {
|
||||
memset(p, 0xef, size);
|
||||
HighWatermark::onFree(p, size);
|
||||
}
|
||||
|
||||
void TrackingPolicy::Debug::onReset() noexcept {
|
||||
if (mBase) {
|
||||
memset(mBase, 0xec, mSize);
|
||||
}
|
||||
HighWatermark::onReset();
|
||||
}
|
||||
|
||||
void TrackingPolicy::Debug::onRewind(void* addr) noexcept {
|
||||
if (mBase) {
|
||||
memset(addr, 0x55, uintptr_t(mBase) + mSize - uintptr_t(addr));
|
||||
}
|
||||
HighWatermark::onRewind(addr);
|
||||
}
|
||||
|
||||
|
||||
} // namespace utils
|
||||
|
||||
Reference in New Issue
Block a user