Crash "TimeSpan overflowed" on floating object spawn (Stopwatch ticks used as milliseconds)

Derrick Mehaffy shared this bug 3 hours ago
Submitted

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

  1. 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.
  2. Load any world and drop an item, or destroy a block with items in it.
  3. 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.

Leave a Comment
 
Attach a file