Issue Data
|
Issue #28753: While Loop may become unbound under certain conditions, resulting in destroyed save game
Bug type: Unbound While Loop
Affected code file: DLC01_TrackSystemTrack.psc Description: The OnUnload event handler relies on external call to CleanupMachine() completing properly. If this does not happen for any reason (which happened to me), the loop will become unbound and will continue to execute perpetually. Impact: The unbound loop will be baked into saves and cannot be terminated, resulting in severe script lag and other game destroying problems. All saves that are made after this bug occurs are rendered worthless. Fix: Add bounds check to the loop ;On Unload, clear and clean up everything. Event OnUnload() myDispatcher = None ; limit to 128 iterations max - prevent endless, save-destroying loop in case CleanupMachine() fails (niston-20200127) Int i = 128 While (myMachines.Length > 0 && i > 0) myMachines[0].CleanupMachine(False) ;CleanupMachine ultimately removes the machine from the array entirely, so don't increment the count. i -= 1 EndWhile ; always initialize to new array myMachines = new DLC01:DLC01_TrackSystemMachine[0] mySourceMarkers.Clear() myDoors.Clear() myDropoffPoints.Clear() myDoorsMinMaxValues.Clear() isInitialized = False EndEvent |
Related Issues: 29452
Symptoms: The log will be flooded with error messages regarding the DLC01_TrackSystemTrack script at a rate of several gigabytes per hour.
This problem was actually a bit simpler than Bethesda or your offering presented. Given than leaving the lair means the game wants the track cleared and reset, it's much simpler and safer to simply assume the whole array is to be dumped and the track status turned off.
So to that end, the code in the function should look like this now:
No loops of any kind, and if the Clear() call fails, so what. It won't get anything stuck on the stack even for a brief moment. This also preserves the function of CleanupMachine() for use elsewhere as designed - to clean up a single machine and disable the track if it's the last one in the array.
So to that end, the code in the function should look like this now:
;On Unload, clear and clean up everything. Event OnUnload() myDispatcher = None ;While (myMachines.Length > 0) ; myMachines[0].CleanupMachine(False) ; ;CleanupMachine ultimately removes the machine from the array entirely, so don't increment the count. ;EndWhile ;UFO4P 2.1.1 Bug #28753 - The above code is dangerous and can get stuck in an invalid loop. Since the intention is obviously to clear and reset the track, the following 3 lines of code will do this job safely. The contents don't matter. myMachines.Clear() isMoving = False isPaused = False mySourceMarkers.Clear() myDoors.Clear() myDropoffPoints.Clear() myDoorsMinMaxValues.Clear() isInitialized = False EndEvent
No loops of any kind, and if the Clear() call fails, so what. It won't get anything stuck on the stack even for a brief moment. This also preserves the function of CleanupMachine() for use elsewhere as designed - to clean up a single machine and disable the track if it's the last one in the array.
Comment #2 Mar 1, 2020 11:05 pm
Edited by Arthmoor on Mar 1, 2020 11:06 pm
Showing Comments 1 - 2 of 2