question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Calling Simulation.Timestep(0) sometimes causes access violations

See original GitHub issue

As per subject - it’s not always the case, but on my machine the code below will crash every time. Reducing the number of cubes, or removing the call to Reset (so the cubes don’t have any angular velocity) will stop it crashing as well, but of course neither of those things seems suspicious 😃

As it happens, the call to Timestep(0) doesn’t actually crash, but it does seem to cause future calls to Timestep (with non-zero parameters) to crash, presumably due to having corrupted something that screws things up next time around.

(As it happens - the reason I ended up calling Timestep with a zero parameter is that the game framework I’m using calls my Update callback with a zero parameter after a window is created, I assume as a “initialise stuff but don’t actually advance anything” signal. I’ll filter those updates out in my code of course, but assuming it is a Bepuphysics bug, it’d obviously be preferable for Timestep(0) to just return without doing anything - or maybe throw an exception on the grounds a zero step is invalid?)

using BepuPhysics;
using BepuPhysics.Collidables;
using BepuPhysics.CollisionDetection;
using BepuPhysics.Constraints;
using BepuUtilities.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace PhysFrame {
  //Note: also needs the NarrowPhaseCallbacks and PoseIntegratorCallbacks from the demos. No changes needed to those definitions, just copy them in unaltered.


    class Test {
        private Simulation _sim;
        private BodyReference[] _cubePhys;

        public Test() {

            var bufferPool = new BufferPool();
            _sim = Simulation.Create(
                bufferPool,
                new NarrowPhaseCallbacks(),
                new PoseIntegratorCallbacks(new System.Numerics.Vector3(0, 0, -10))
            );

            var theCube = new Box(10, 10, 10);
            theCube.ComputeInertia(1000, out var diceInertia);
            var cubeShape = _sim.Shapes.Add(theCube);

            _cubePhys = new BodyReference[16];
            foreach (int i in Enumerable.Range(0, _cubePhys.Length)) {
                var cubePhys = _sim.Bodies.Add(
                    BodyDescription.CreateDynamic(
                        new System.Numerics.Vector3(i * 12, 0, 60),
                        diceInertia,
                        new CollidableDescription(cubeShape, 0.1f),
                        new BodyActivityDescription(0.01f)
                    )
                );
                _cubePhys[i] = new BodyReference(cubePhys, _sim.Bodies);
            }
            Reset();
        }

        private Random _r = new Random();

        public void Reset() {
            foreach (int i in Enumerable.Range(0, _cubePhys.Length)) {
                _cubePhys[i].Pose.Orientation =
                    System.Numerics.Quaternion.CreateFromYawPitchRoll(
                    (float)(Math.PI * _r.NextDouble()),
                    (float)(Math.PI * _r.NextDouble()),
                    (float)(Math.PI * _r.NextDouble())
                );
                _cubePhys[i].Pose.Position = new System.Numerics.Vector3(12 * i, 0, 60f);
                _cubePhys[i].Velocity = new BodyVelocity(
                    System.Numerics.Vector3.Zero,
                    new System.Numerics.Vector3(
                        (float)_r.NextDouble() * 2,
                        (float)_r.NextDouble() * 2,
                        (float)_r.NextDouble() * 2
                    )
                );
                _cubePhys[i].Awake = true;
            }
        }

        public void Step(float s) {
            _sim.Timestep(s);
            //System.Diagnostics.Debug.WriteLine(seconds);
        }

    }


    class Program {
        static void Main(string[] args) {
            Test t = new Test();
            t.Reset();
            t.Step(0); // <-- Removing this line stops the access violation
            foreach (int _ in Enumerable.Range(0, 240)) {
                t.Step(1f / 60f);
            }
        }
    }

}

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
RossNordbycommented, Aug 23, 2020

0 timestep is indeed invalid and will cause a NaNsplosion, and without debug asserts enabled nansplosions tend to cause a fatal error in the broad phase.

Note that using a variable length timestep, like the ‘dt’ provided by a game loop, will not work well even without the 0 length timesteps. High variance will introduce instability. The time step duration should be approximately constant. A common strategy is to accumulate time until enough has elapsed to warrant a fixed length timestep: https://gafferongames.com/post/fix_your_timestep/

Slow, gradual changes in timestep duration can work okay, and one-off big changes can work (especially if you use Simulation.Solver.ScaleAccumulatedImpulses), but constant jumping up and down pretty much guarantees trouble.

I will look into improving the error handling, though.

0reactions
RossNordbycommented, Aug 24, 2020

if this is known, then why not just if(timeStep==0) return;

0 being passed as a timestep duration is a strong signal that there is a bug (like in the original issue). Timestep durations must be tightly controlled by the application to ensure stability, and a value of 0 implies the application is not doing so. Rather than shrugging off a likely error and failing later in a more indirect way, it fails fast. Or at least now it does with the recent commit.

The one valid use case for 0 duration would be pausing the simulation, but that is trivially doable otherwise. It didn’t seem like a good tradeoff with losing a bit of validation. (It would indeed be easy to calculate, though 😛)

Read more comments on GitHub >

github_iconTop Results From Across the Web

simulation causes bug : System Access Violation
I've been working with a BackgroundWorker that is kicked into gear often and regularly. It needs to make use of its own RichTextbox...
Read more >
Failed Solve Error after Writing and Reading through COM ...
I am using Python and the COM interface to read and store all circuit data, analyze circuit conditions within a time step and...
Read more >
LTspice error: timestep too small
"Time step too small" is usually the consequence of a "shock" or discontinuity on your models. It indicates that the solver could not...
Read more >
udf problem - Forums
(ACCESS VIOLATIONS) occur due to wrong handling of the data. For single phase problem the data structure in fluent looks like this
Read more >
c++ - Access violation exception when calling a method
If memory access violation happens only when Studio fails to show method address, then it could be caused by missing debug information. You ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found