Gauge: FIX CoolingLoopConnection AV -- guard the databinding-trap raw reads
BT_DEV_GAUGES crashed a few ticks in: CoolingLoopConnection::Update (btl4gau2.cpp) walks the 1995 binary's plug->link->subsystem chain via raw +8 offsets, but our reconstructed subsystem layout is not byte-identical, so an intermediate 'link' comes out non-null-but-garbage and *(link+8) AVs. Fires the moment a mech's coolant loop goes active (source+0x134==1) -- so it would crash the REAL POD too, not just the dev composite; the brief earlier gauge runs just never activated the loop. Pre-existing (byte-identical across the BT411 merge), not a merge regression. Guard each raw deref (BTPtrReadable via VirtualQuery) so an invalid chain resolves to the authentic 'no source' branch (0) instead of faulting. [T3] -- proper fix is named Plug/Link accessors in a complete-type TU; logged in the KB. Verified: BT_DEV_GAUGES now survives coolant-loop activation and the full cockpit MFD suite renders (Heat / weapon-status MFDs / radar / Comm pilotList). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -127,6 +127,33 @@ static void *AttributePointerOf(void *subsystem, const char *name)
|
||||
return p;
|
||||
}
|
||||
|
||||
//
|
||||
// BT412 DATABINDING GUARD [T3]: is `p` a readable committed address? The
|
||||
// plug->link->subsystem chain below walks raw +8 offsets recovered from the
|
||||
// 1995 binary, but our reconstructed subsystem layout is NOT byte-identical,
|
||||
// so an intermediate "link" can come out non-null-but-garbage -- dereferencing
|
||||
// it AVs (observed: CoolingLoopConnection::Update crash the moment a mech's
|
||||
// coolant loop goes active, on the pod AND the dev composite). A readable-page
|
||||
// check makes an invalid link resolve to the authentic "no source" branch (0)
|
||||
// instead of faulting. Proper fix (follow-up): route through named Plug/Link
|
||||
// accessors in a complete-type TU instead of raw +8 reads.
|
||||
//
|
||||
static bool BTPtrReadable(const void *p)
|
||||
{
|
||||
if (p == 0)
|
||||
return false;
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (VirtualQuery(p, &mbi, sizeof(mbi)) == 0)
|
||||
return false;
|
||||
if (mbi.State != MEM_COMMIT)
|
||||
return false;
|
||||
const DWORD readable = PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE_READ
|
||||
| PAGE_EXECUTE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY;
|
||||
if ((mbi.Protect & readable) == 0)
|
||||
return false;
|
||||
return (mbi.Protect & PAGE_GUARD) == 0;
|
||||
}
|
||||
|
||||
//
|
||||
// FUN_00417ab4 -- SubsystemConnection::Resolve: follow the plug's bound link to the
|
||||
// resolved subsystem. The link is `*(plug+8)`; the resolved subsystem is
|
||||
@@ -136,10 +163,10 @@ static void *AttributePointerOf(void *subsystem, const char *name)
|
||||
//
|
||||
static void *ResolveLink(void *plug)
|
||||
{
|
||||
if (plug == 0)
|
||||
if (!BTPtrReadable((char *)plug + 8))
|
||||
return 0;
|
||||
void *link = *(void **)((char *)plug + 8);
|
||||
if (link == 0)
|
||||
if (!BTPtrReadable((char *)link + 8)) // [T3] guard: layout-mismatch garbage link
|
||||
return 0;
|
||||
return *(void **)((char *)link + 8);
|
||||
}
|
||||
@@ -204,13 +231,17 @@ public:
|
||||
void Update() // @004c31a0
|
||||
{
|
||||
void *resolved = 0;
|
||||
if (source != 0 && *(int *)((char *)source + 0x134) == 1)
|
||||
// [T3] guard the raw +0x134 / +0x1d4 reads against the layout mismatch
|
||||
// (see BTPtrReadable above) -- an invalid chain reads "no source" (0).
|
||||
if (BTPtrReadable((char *)source + 0x134) &&
|
||||
*(int *)((char *)source + 0x134) == 1)
|
||||
{
|
||||
void *linked = FindLinkedSubsystem(source, 3);
|
||||
if (linked != 0)
|
||||
resolved = ResolveLink(linked);
|
||||
}
|
||||
*destination = (resolved == 0) ? 0 : *(int *)((char *)resolved + 0x1d4);
|
||||
*destination = (resolved != 0 && BTPtrReadable((char *)resolved + 0x1d4))
|
||||
? *(int *)((char *)resolved + 0x1d4) : 0;
|
||||
}
|
||||
protected:
|
||||
void *source; // @0x10 this[4]
|
||||
|
||||
Reference in New Issue
Block a user