Crash "TimeSpan overflowed" on floating object spawn (Stopwatch ticks used as milliseconds)
Game version: 2.4.0.95
Description
The game crashes with "System.ArgumentOutOfRangeException: TimeSpan overflowed because the duration is too long." when a floating object is spawned. In my case, an explosion destroyed a block that held items.
The crash is in FloatingObjectTrashRemovalSessionComponent, in the local function OnFloatingObjectAdded (registered in OnEntityAddedOrRemoved). It records the spawn time as:
_collectedEntities.Add(entity.DEntity, TimeSpan.FromMilliseconds(Stopwatch.GetTimestamp(), 0L));
Stopwatch.GetTimestamp() returns ticks at Stopwatch.Frequency, not milliseconds. The result therefore depends on the timer frequency and the machine's uptime:
- At 10 MHz (typical Windows QPC), it overflows after ~2.9 years of uptime.
- At 1 GHz (.NET's frequency on Linux, and possible elsewhere), it overflows after ~10.7 days of uptime.
After that, every floating-object spawn crashes the game: dropping items, grinding, and destroyed blocks spilling their inventory. Dedicated servers with long uptimes are the most exposed.
Stack trace (top)
System.ArgumentOutOfRangeException: TimeSpan overflowed because the duration is too long. at System.TimeSpan.FromMilliseconds(Int64 milliseconds, Int64 microseconds) at Keen.Game2.Simulation.GameSystems.TrashRemoval.FloatingObjectTrashRemovalSessionComponent.<OnEntityAddedOrRemoved>g__OnFloatingObjectAdded|7_0(FloatingObjectTrashRemovalSessionComponent thiz, Entity entity) at Keen.VRage.Core.Game.Systems.Session.AddEntityToSceneCore(Entity entity) at Keen.VRage.Core.Game.Systems.Session.AddEntityBundleToScene(ReadOnlySpan`1 entities) at Keen.VRage.Core.Game.Systems.SimpleEntitySpawnerSessionComponent.SpawnEntity(EntityObjectBuilder entityOB, DEntityBuilder entityData) at Keen.Game2.Simulation.GameSystems.FloatingObjects.FloatingObjectSpawnerSessionComponent.SpawnItem(Parameters parameters) at Keen.Game2.Simulation.WorldObjects.Items.InventoryComponent.SpawnItems(Int32& spawnDistance, Int32& dirIndex) at Keen.Game2.Simulation.WorldObjects.CubeBlocks.CubeBlockComponent.SpawnItems() at Keen.Game2.Simulation.WorldObjects.CubeBlocks.CubeBlockComponent.CubeBlockDestroyer.Destroy(...) at Keen.Game2.Simulation.GameSystems.Explosions.ExplosionsServerSessionComponent.ApplyExplosionAsync(ExplosionHit explosion)
Steps to reproduce
- Run the game on a machine where Stopwatch.GetTimestamp() exceeds ~9.22e14. For example, a Linux host up more than ~10.7 days. I hit it running natively on Linux via the community Pulsar loader; the crash is entirely in vanilla code.
- Load any world and drop an item, or destroy a block with items in it.
- The game crashes.
Confirmed in the running game: Stopwatch.Frequency = 1000000000 and Stopwatch.GetTimestamp() = 2592149681567598, so TimeSpan.FromMilliseconds(Stopwatch.GetTimestamp(), 0) throws the same exception.
Suggested fix
The value is only used for ordering in FloatingObjectsTrashRemoval (oldest first), so any of these is a one-line fix:
- TimeSpan.FromTicks(Stopwatch.GetTimestamp()), which is monotonic and fine for ordering, or
- Stopwatch.GetElapsedTime(0) / a session-time value, for real units, or
- storing the raw long timestamp.
I have the same bug
Replies have been locked on this page!