Fix MxDSBuffer leak

This commit is contained in:
Christian Semmler 2025-08-15 21:55:44 -07:00
parent 2f2446af87
commit 933c5bb1a4
No known key found for this signature in database
GPG Key ID: 086DAA1360BEEE5C
2 changed files with 35 additions and 3 deletions

View File

@ -91,6 +91,12 @@ class MxDSBuffer : public MxCore {
void SetUnk30(MxDSStreamingAction* p_unk0x30) { m_unk0x30 = p_unk0x30; }
void SetSourceBuffer(MxDSBuffer* p_sourceBuffer)
{
m_sourceBuffer = p_sourceBuffer;
m_sourceBuffer->AddRef(NULL);
}
// SYNTHETIC: LEGO1 0x100c6510
// SYNTHETIC: BETA10 0x10158530
// MxDSBuffer::`scalar deleting destructor'
@ -107,6 +113,7 @@ class MxDSBuffer : public MxCore {
MxU32 m_writeOffset; // 0x28
MxU32 m_bytesRemaining; // 0x2c
MxDSStreamingAction* m_unk0x30; // 0x30
MxDSBuffer* m_sourceBuffer;
};
#endif // MXDSBUFFER_H

View File

@ -28,6 +28,7 @@ MxDSBuffer::MxDSBuffer()
m_bytesRemaining = 0;
m_mode = e_preallocated;
m_unk0x30 = 0;
m_sourceBuffer = NULL;
}
// FUNCTION: LEGO1 0x100c6530
@ -36,6 +37,10 @@ MxDSBuffer::~MxDSBuffer()
{
assert(m_referenceCount == 0);
if (m_sourceBuffer) {
m_sourceBuffer->ReleaseRef(NULL);
}
if (m_pBuffer != NULL) {
switch (m_mode) {
case e_allocate:
@ -267,6 +272,28 @@ MxResult MxDSBuffer::ParseChunk(
return FAILURE;
}
// START FIX: Ref-Counting Backpressure for Split Chunks
//
// PROBLEM: When a `DS_CHUNK_SPLIT` is found, the temporary `MxStreamChunk`
// header that holds a reference to the source buffer is immediately
// destroyed. This prematurely releases the reference, causing the source
// buffer's ref-count to drop to zero.
//
// EFFECT: The source buffer is freed immediately instead of being kept
// alive on the m_list0x74 "keep-alive" list. This breaks the natural
// ref-counting backpressure mechanism, as the controller is blind to the
// downstream workload and keeps reading new data from the stream at full
// speed, eventually leading to a memory leak.
//
// SOLUTION: We explicitly link the new reassembly buffer to the original
// source buffer. We then add an artificial reference to the source buffer.
// This reference is designed to be released by the reassembly buffer's
// destructor, ensuring the source buffer is kept alive for the correct
// duration and that the backpressure system functions as intended.
if (p_header->GetBuffer()) {
buffer->SetSourceBuffer(p_header->GetBuffer());
}
MxU16* flags = MxStreamChunk::IntoFlags(buffer->GetBuffer());
*flags = p_header->GetChunkFlags() & ~DS_CHUNK_SPLIT;
@ -409,9 +436,7 @@ MxU8 MxDSBuffer::ReleaseRef(MxDSChunk*)
// FUNCTION: LEGO1 0x100c6ee0
void MxDSBuffer::AddRef(MxDSChunk* p_chunk)
{
if (p_chunk) {
m_referenceCount++;
}
m_referenceCount++;
}
// FUNCTION: LEGO1 0x100c6ef0