[Fix] (MG_Impl, MG_Pipe): outlive the exit handlers - a frontend object destroyed by __run_exit_handlers reached the slot allocator, the resource tracker and the applier after their own destructors had run

This commit is contained in:
Swung0x48
2026-09-08 07:33:16 -04:00
committed by swung0x48
parent c20e2f2b67
commit d54ec57a5d
3 changed files with 20 additions and 5 deletions
+5 -2
View File
@@ -552,8 +552,11 @@ namespace MobileGL::MG_Pipe {
// The monolith's one resource tracker, beside the state tracker, the CSO cache and the
// set-hash suppressor.
inline MGPipeResourceTracker& MGPipeResourceTrackerInstance() {
static MGPipeResourceTracker tracker;
return tracker;
// NEVER DESTROYED, for MGPipeSlots()' reason (SlotAllocator.cpp): ~BufferObject reads
// and writes this tracker, and the objects that own the last reference to a
// BufferObject outlive every function-local static.
static MGPipeResourceTracker* tracker = new MGPipeResourceTracker();
return *tracker;
}
// ---------------------------------------------------------------------------------
+10 -2
View File
@@ -168,7 +168,15 @@ namespace MobileGL::MG_Pipe {
}
MGPipeSlotAllocator& MGPipeSlots() {
static MGPipeSlotAllocator allocator;
return allocator;
// NEVER DESTROYED, deliberately (one allocation for the life of the process). A
// frontend object's destructor reaches this allocator - ~BufferObject through
// MGPipeEmitResourceDestroyAndFree, ~VertexArrayObject through the death notice - and
// MG_Backend/MGPipe/PipeInputs.h's gPipeInputs holds SharedPtrs to those objects at
// namespace scope, so they are destroyed by __run_exit_handlers AFTER this
// function-local static would have been. A destroyed allocator then answers
// FindByLifetimeId out of a freed hash table and Free() writes into freed vectors -
// an exit-time heap corruption whose fatality depends only on the allocator's layout.
static MGPipeSlotAllocator* allocator = new MGPipeSlotAllocator();
return *allocator;
}
} // namespace MobileGL::MG_Pipe
+5 -1
View File
@@ -377,7 +377,11 @@ namespace MobileGL::MG_Pipe {
static_assert(kCapabilityCount <= 64,
"ResidualValueBlock::CapabilityBits is a Uint64; 35 bits fit, 65 would not");
MGPipeApplierState g_applier{};
// A REFERENCE TO A NEVER-DESTROYED BLOCK, for MGPipeSlots()' reason
// (MG_Impl/Pipe/SlotAllocator.cpp): resource_destroy and delete_vertex_elements are
// raised from ~BufferObject / ~VertexArrayObject, and those objects are released by
// exit handlers that run after this translation unit's own globals are gone.
MGPipeApplierState& g_applier = *new MGPipeApplierState{};
// The installed handle-shaped resource table. Null until a backend registers one,
// which is what makes the client half landable on its own: with nothing here every