BT410 5.3.46: the Reservoir crash solved -- *State names must be StateIndicators
The linker map named the faulting function: the crash address minus the CODE base (0x410000) looked up in btl4opt.map's Publics-by-Value landed inside AudioStateWatcher::AudioStateWatcher +0x2D. AudioStateWatcher is AudioWatcherOf<StateIndicator> and its ctor immediately runs Cast_Object(StateIndicator*, attributePointer)->AddAudioWatcher(this). So every authored *State name must be published as a StateIndicator -- AlarmIndicator counts, it derives from one -- and pointing one at a plain int sends that member call through garbage. That explains both earlier failures: the AlarmIndicator attempt was the right type but was tested with other bugs still in the batch, and the plain-int attempt was simply the wrong type and crashed further along. Published as state objects: Reservoir/ReservoirState -> reservoirAlarm, Generator/GeneratorState -> stateAlarm, plus new StateIndicator members for Condenser/CondenserState and Torso/MotionState. StateIndicator has no Initialize(); the default ctor suffices because the watcher only needs the object to exist. Verified on the pod rig: no crash, ladder advanced to ReportLeak. Technique worth keeping: on an extender fault, subtract 0x410000 from the dumped address and look it up in btl4opt.map -- it names the engine function, and for this family of work that names the watcher class and hence the required member type. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -880,7 +880,6 @@ Condenser::Condenser(
|
||||
// each condenser its share of the total valve opening.
|
||||
//
|
||||
valveState = 1;
|
||||
condenserState = 0; // staged: bound by an authored watcher
|
||||
coolantFlowScale = 0.0f;
|
||||
refrigerationFactor = subsystem_resource->refrigerationFactor;
|
||||
massScale = refrigerationFactor;
|
||||
|
||||
@@ -511,7 +511,15 @@
|
||||
// member goes at the END of the CLASS (never into the resource
|
||||
// struct above, which is a wire format).
|
||||
//
|
||||
int condenserState; // authored watcher: CondenserN/CondenserState
|
||||
//
|
||||
// MUST BE A StateIndicator. The authored watcher for a *State
|
||||
// name is an AudioStateWatcher, which is AudioWatcherOf<StateIndicator>
|
||||
// and whose ctor immediately runs
|
||||
// Cast_Object(StateIndicator*, attributePointer)->AddAudioWatcher(this)
|
||||
// (AUDWTHR.CPP:891). Point it at a plain int and that call goes
|
||||
// through garbage -- the pod dies on the extender.
|
||||
//
|
||||
StateIndicator condenserState; // authored watcher
|
||||
};
|
||||
|
||||
//###########################################################################
|
||||
|
||||
@@ -596,7 +596,7 @@ const Generator::IndexEntry
|
||||
ATTRIBUTE_ENTRY(Generator, OutputVoltage, outputVoltage),
|
||||
ATTRIBUTE_ENTRY(Generator, RatedVoltage, ratedVoltage),
|
||||
ATTRIBUTE_ENTRY(Generator, GeneratorNumber, generatorNumber),
|
||||
ATTRIBUTE_ENTRY(Generator, GeneratorState, generatorState)
|
||||
ATTRIBUTE_ENTRY(Generator, GeneratorState, stateAlarm)
|
||||
};
|
||||
|
||||
Generator::AttributeIndexSet
|
||||
@@ -640,7 +640,6 @@ Generator::Generator(
|
||||
startTimer = startTime;
|
||||
stateAlarm.SetLevel(GeneratorReady);
|
||||
generatorOn = 1;
|
||||
generatorState = 0; // staged
|
||||
shortRecoveryTime = subsystem_resource->shortRecoveryTime;
|
||||
shortTimer = shortRecoveryTime;
|
||||
|
||||
|
||||
@@ -479,7 +479,6 @@
|
||||
Scalar shortRecoveryTime;
|
||||
Scalar shortTimer;
|
||||
AlarmIndicator stateAlarm;
|
||||
int generatorState; // authored watcher: plain int, see RESERVR.HPP
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -48,11 +48,24 @@ Reservoir::MessageHandlerSet
|
||||
HeatSink::MessageHandlers
|
||||
);
|
||||
|
||||
const Reservoir::IndexEntry
|
||||
Reservoir::AttributePointers[]=
|
||||
{
|
||||
ATTRIBUTE_ENTRY(Reservoir, ReservoirState, reservoirAlarm)
|
||||
};
|
||||
|
||||
Reservoir::AttributeIndexSet
|
||||
Reservoir::AttributeIndex(
|
||||
ELEMENTS(Reservoir::AttributePointers),
|
||||
Reservoir::AttributePointers,
|
||||
HeatSink::AttributeIndex
|
||||
);
|
||||
|
||||
Reservoir::SharedData
|
||||
Reservoir::DefaultData(
|
||||
Reservoir::ClassDerivations,
|
||||
Reservoir::MessageHandlers,
|
||||
HeatSink::AttributeIndex,
|
||||
Reservoir::AttributeIndex,
|
||||
Subsystem::StateCount
|
||||
);
|
||||
|
||||
|
||||
@@ -111,6 +111,15 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Local Data. The inject flag is the reservoir alarm's level (1 = flushing).
|
||||
//
|
||||
public:
|
||||
enum {
|
||||
ReservoirStateAttributeID = HeatSink::NextAttributeID,
|
||||
NextAttributeID
|
||||
};
|
||||
|
||||
static const IndexEntry AttributePointers[];
|
||||
static AttributeIndexSet AttributeIndex;
|
||||
|
||||
protected:
|
||||
AlarmIndicator reservoirAlarm;
|
||||
Scalar coolantSquirtMass;
|
||||
|
||||
@@ -67,7 +67,6 @@ Torso::Torso(
|
||||
Check(owner);
|
||||
Check_Pointer(r);
|
||||
|
||||
motionState = 0; // staged: no gait state feed yet
|
||||
isDamagedCopy = (owner->GetInstance() == Entity::ReplicantInstance);
|
||||
|
||||
statusFlags = 0;
|
||||
|
||||
@@ -159,7 +159,15 @@
|
||||
Scalar currentElevation;
|
||||
Scalar analogElevationAxis;
|
||||
Scalar analogTwistAxis;
|
||||
int motionState; // staged: authored watcher Torso/MotionState
|
||||
//
|
||||
// MUST BE A StateIndicator. The authored watcher for a *State
|
||||
// name is an AudioStateWatcher, which is AudioWatcherOf<StateIndicator>
|
||||
// and whose ctor immediately runs
|
||||
// Cast_Object(StateIndicator*, attributePointer)->AddAudioWatcher(this)
|
||||
// (AUDWTHR.CPP:891). Point it at a plain int and that call goes
|
||||
// through garbage -- the pod dies on the extender.
|
||||
//
|
||||
StateIndicator motionState; // authored watcher
|
||||
//
|
||||
// Twist/elevation dynamics accumulators advanced by TorsoSimulation.
|
||||
// Reserved until the per-frame sim is reconstructed (phase 5).
|
||||
|
||||
@@ -354,6 +354,34 @@ the AttributeIndexSet::Build uninitialised-slot signature, so the next step
|
||||
is to dump Reservoir's built index set and compare it against a class whose
|
||||
publication works (Condenser is the control: same base, plain int, no crash).
|
||||
|
||||
STATE: Reservoir is REVERTED, the tree is green (clean Fail at ReservoirState,
|
||||
no crash), and the ladder is blocked there until this is understood. Do not
|
||||
"fix" it by publishing the name some other way without re-running the bisect.
|
||||
SOLVED. The linker map named the faulting function outright:
|
||||
|
||||
tlink32 -m writes build410/btl4opt.map; the crash address minus the CODE
|
||||
base (0x410000) is the map offset, and "Publics by Value" gives the
|
||||
enclosing symbol. 0x3B4AD landed inside
|
||||
AudioStateWatcher::AudioStateWatcher(PlugStream*,Entity*) +0x2D.
|
||||
|
||||
AudioStateWatcher is AudioWatcherOf<StateIndicator> and its ctor runs
|
||||
|
||||
Cast_Object(StateIndicator*, attributePointer)->AddAudioWatcher(this)
|
||||
(AUDWTHR.CPP:891)
|
||||
|
||||
immediately. So every authored *State name MUST be published as a
|
||||
StateIndicator (AlarmIndicator counts -- it derives from one). Point it at a
|
||||
plain int and that member call goes through garbage and the pod dies on the
|
||||
extender. That is why BOTH earlier attempts failed: the AlarmIndicator try
|
||||
was right in type but was tested while other bugs were still in the batch,
|
||||
and the "plain int" try was wrong in type and merely crashed further along.
|
||||
|
||||
Fixed by publishing state objects: Reservoir/ReservoirState -> reservoirAlarm,
|
||||
Generator/GeneratorState -> stateAlarm, and NEW StateIndicator members for
|
||||
Condenser/CondenserState and Torso/MotionState. Note StateIndicator has no
|
||||
Initialize() -- it takes its count in the ctor, and the default ctor is
|
||||
enough here because the watcher only needs the object to exist (the socket it
|
||||
attaches to is a member). Verified on the pod: no crash, ladder advanced to
|
||||
ReportLeak.
|
||||
|
||||
THE REUSABLE TECHNIQUE: when the pod dies with an extender fault, take the
|
||||
address out of the dump, subtract 0x410000, and look it up in
|
||||
btl4opt.map. It names the exact engine function -- which, for this family of
|
||||
work, names the watcher class and therefore the required member type.
|
||||
|
||||
Reference in New Issue
Block a user