Fix(FrameInfo): Improve robustness of frame info history management (#9496)

Address potential issues in FrameInfoImpl and FrameInfoManager:
 - Modify FrameInfoManager::beginFrame to handle cases where the 
   circular queue is full and the oldest frame is not yet ready, 
   logging a warning and skipping the frame. 
   This prevents potential use-after-free or data corruption by 
   ensuring only ready frames are removed from the history.

FIXES=[466081317]
This commit is contained in:
Mathias Agopian
2025-12-08 15:28:58 -08:00
committed by GitHub
parent ae3d98fb47
commit 2e31dc20e4
2 changed files with 17 additions and 31 deletions

View File

@@ -101,11 +101,22 @@ void FrameInfoManager::beginFrame(FSwapChain* swapChain, DriverApi& driver,
auto& history = mFrameTimeHistory;
// don't exceed the capacity, drop the oldest entry
if (UTILS_LIKELY(history.size() == history.capacity())) {
if (!mDisableGpuFrameComplete) {
assert_invariant(history.back().fence);
driver.destroyFence(std::move(history.back().fence));
FrameInfoImpl& frameInfo = history.back();
if (frameInfo.ready.load(std::memory_order_relaxed)) {
if (!mDisableGpuFrameComplete) {
assert_invariant(frameInfo.fence);
driver.destroyFence(std::move(frameInfo.fence));
}
history.pop_back();
} else {
// This is a big problem, we ran out of space in the circular queue and that entry
// hasn't been processed yet. Because the code below keeps a reference to the
// front element of the queue, we can't pop/push. Our only option is to not record
// a new entry for this frame, which will create a false skipped frame in the
// data.
LOG(WARNING) << "FrameInfo's circular queue is full, but the latest item hasn't "
" been processed yet. Skipping this frame, id = " << frameId;
}
history.pop_back();
}
// create a new entry

View File

@@ -95,33 +95,8 @@ struct FrameInfoImpl : public details::FrameInfo {
assert_invariant(!fence);
}
FrameInfoImpl(FrameInfoImpl&& rhs) noexcept :
details::FrameInfo(rhs),
frameId(rhs.frameId),
beginFrame(rhs.beginFrame),
endFrame(rhs.endFrame),
backendBeginFrame(rhs.backendBeginFrame),
backendEndFrame(rhs.backendEndFrame),
gpuFrameComplete(rhs.gpuFrameComplete),
vsync(rhs.vsync),
fence(rhs.fence),
ready(rhs.ready.load())
{
}
FrameInfoImpl& operator=(FrameInfoImpl&& rhs) noexcept {
details::FrameInfo::operator=(rhs);
frameId = rhs.frameId;
beginFrame = rhs.beginFrame;
endFrame = rhs.endFrame;
backendBeginFrame = rhs.backendBeginFrame;
backendEndFrame = rhs.backendEndFrame;
gpuFrameComplete = rhs.gpuFrameComplete;
vsync = rhs.vsync;
fence = rhs.fence;
ready.store(rhs.ready.load());
return *this;
}
FrameInfoImpl(FrameInfoImpl& rhs) noexcept = delete;
FrameInfoImpl& operator=(FrameInfoImpl& rhs) noexcept = delete;
};
template<typename T, size_t CAPACITY>