Obi Official Forum
Access violation crash! - Printable Version

+- Obi Official Forum (https://obi.virtualmethodstudio.com/forum)
+-- Forum: Obi Users Category (https://obi.virtualmethodstudio.com/forum/forum-1.html)
+--- Forum: General (https://obi.virtualmethodstudio.com/forum/forum-5.html)
+--- Thread: Access violation crash! (/thread-624.html)



Access violation crash! - M. Hanssen - 18-06-2018

We have a setup with 2 rope pulley systems where some targets are spawned dynamically, get pin constraints on the rope and get detached again when hit.
We get an access violation from libOni.dll on a regular base. Sadly the issue cannot be reproduced, but happens at random.

The crash exception states:

Quote:libOni.dll caused an Access Violation (0xc0000005) in module libOni.dll at 0033:3ea5f48b.

The code we use to attach and detach pinpoint constraints is:

Code:
public override T Spawn<T>(WorldObject worldObject)
   {
       T genericSpawnedObject = base.Spawn<T>(worldObject);
       HitablePulleyWorldObject spawnedObject = genericSpawnedObject as HitablePulleyWorldObject;
       if (spawnedObject != null)
       {
           ObiPinConstraintBatch batch = (ObiPinConstraintBatch) PinConstraints.GetFirstBatch();
           if (batch != null)
           {
               PinConstraints.RemoveFromSolver(null);
               int index = GetClosestParticleIndex();
               if (index >= 0)
               {
                   batch.AddConstraint(index, spawnedObject.GetComponentInChildren<ObiCollider>(), Vector3.zero, 1);
                   spawnedObject.RopeParticleIndex = index;
                   spawnedObject.PinConstraints = PinConstraints;
               }
               PinConstraints.AddToSolver(null);
               PinConstraints.PushDataToSolver();
           }
       }
       return genericSpawnedObject;
   }

   private int GetClosestParticleIndex()
   {
       int result = -1;

       float closestDistance = float.MaxValue;

       for (int i = 0; i < Rope.invMasses.Length; i++)
       {
           if (Rope.invMasses[i] > 0)
           {
               float distance = Vector3.Distance(Rope.GetParticlePosition(i), transform.position);
               if (distance < closestDistance)
               {
                   closestDistance = distance;
                   result = i;
               }
           }
       }
       return result;
   }


Code:
private void DetachFromRope()
   {
       ObiPinConstraintBatch batch = PinConstraints.GetFirstBatch();
       if (batch != null && RopeParticleIndex < batch.ConstraintCount)
       {
           PinConstraints.RemoveFromSolver(null);
           batch.RemoveConstraint(RopeParticleIndex);
           PinConstraints.AddToSolver(null);
           PinConstraints.PushDataToSolver();
       }
       Object.Destroy(GetComponent<ObiCollider>());
   }

The .dmp file link is: https://we.tl/nJRKIzrFSm, I really hope you can help us fix this issue!


RE: Access violation crash! - josemendez - 18-06-2018

Hi,

According to the dump file, the crash happens when setting pin constraints due to an out of bounds access. There are multiple errors in your code that could lead to this:

Quote: if (batch != null && RopeParticleIndex < batch.ConstraintCount)

There's no point in comparing a particle index with the amount of constraints in a batch. They're just two different things, a rope could have few particles and many constraints or viceversa.

Quote:batch.RemoveConstraint(RopeParticleIndex);

You are passing a particle index, when you should be passing a constraint index. Since no range checks are performed in Obi, this results in undefined behavior (including the possibility of a crash) as warned in the documentation.

If you want to remove the constraint affecting a certain particle, use GetConstraintsInvolvingParticle(particleIndex) to find out the appropriate constraint index.


RE: Access violation crash! - M. Hanssen - 19-06-2018

Thanks for the quick reply. I understand that I mixed up the constraint indices with the particle indices. However even after adjusting the code to remove the right index, the access violation error still triggers at random.

The weird thing is that when I try to trigger the access violation by feeding the pinconstraints non existing indices, the access violation crash is not triggered!
The current code is:

Code:
public override T Spawn<T>(WorldObject worldObject)
   {
       T genericSpawnedObject = base.Spawn<T>(worldObject);
       HitablePulleyWorldObject spawnedObject = genericSpawnedObject as HitablePulleyWorldObject;
       if (spawnedObject != null)
       {
           ObiPinConstraintBatch batch = PinConstraints.GetFirstBatch();
           if (batch != null)
           {
               PinConstraints.RemoveFromSolver(null);
               int index = GetClosestParticleIndex();
               if (index >= 0)
               {
                   batch.AddConstraint(index, spawnedObject.GetComponentInChildren<ObiCollider>(), Vector3.zero, 1);
                   spawnedObject.ConstraintIndex = batch.ConstraintCount - 1;
                   spawnedObject.PinConstraints = PinConstraints;
               }
               PinConstraints.AddToSolver(null);
           }
       }
       return genericSpawnedObject;
   }

   private int GetClosestParticleIndex()
   {
       int result = -1;

       float closestDistance = float.MaxValue;

       for (int i = 0; i < Rope.invMasses.Length; i++)
       {
           if (Rope.invMasses[i] > 0)
           {
               float distance = Vector3.Distance(Rope.GetParticlePosition(i), transform.position);
               if (distance < closestDistance)
               {
                   closestDistance = distance;
                   result = i;
               }
           }
       }
       return result;
   }

Code:
private void DetachFromRope()
   {
       ObiPinConstraintBatch batch = PinConstraints.GetFirstBatch();
       if (batch != null && ConstraintIndex < batch.ConstraintCount)
       {
           PinConstraints.RemoveFromSolver(null);
           batch.RemoveConstraint(ConstraintIndex);
           PinConstraints.AddToSolver(null);
       }
       Object.Destroy(GetComponent<ObiCollider>());
   }

Is there still something wrong with this?
And above all, why is it that the whole application crashes by inserting a wrong index according to you?
Cant this be fixed by throwing a safe exception? An access violation crash seems a bit harsh for an out of bounds exception!
I hope you can help me resolve this issue.
The new dump file of the crash that is still occurring: https://we.tl/SoBARZU6P0


RE: Access violation crash! - josemendez - 21-06-2018

(19-06-2018, 10:50 AM)M. Hanssen Wrote: Thanks for the quick reply. I understand that I mixed up the constraint indices with the particle indices. However even after adjusting the code to remove the right index, the access violation error still triggers at random.

The weird thing is that when I try to trigger the access violation by feeding the pinconstraints non existing indices, the access violation crash is not triggered!
The current code is:

Code:
public override T Spawn<T>(WorldObject worldObject)
   {
       T genericSpawnedObject = base.Spawn<T>(worldObject);
       HitablePulleyWorldObject spawnedObject = genericSpawnedObject as HitablePulleyWorldObject;
       if (spawnedObject != null)
       {
           ObiPinConstraintBatch batch = PinConstraints.GetFirstBatch();
           if (batch != null)
           {
               PinConstraints.RemoveFromSolver(null);
               int index = GetClosestParticleIndex();
               if (index >= 0)
               {
                   batch.AddConstraint(index, spawnedObject.GetComponentInChildren<ObiCollider>(), Vector3.zero, 1);
                   spawnedObject.ConstraintIndex = batch.ConstraintCount - 1;
                   spawnedObject.PinConstraints = PinConstraints;
               }
               PinConstraints.AddToSolver(null);
           }
       }
       return genericSpawnedObject;
   }

   private int GetClosestParticleIndex()
   {
       int result = -1;

       float closestDistance = float.MaxValue;

       for (int i = 0; i < Rope.invMasses.Length; i++)
       {
           if (Rope.invMasses[i] > 0)
           {
               float distance = Vector3.Distance(Rope.GetParticlePosition(i), transform.position);
               if (distance < closestDistance)
               {
                   closestDistance = distance;
                   result = i;
               }
           }
       }
       return result;
   }

Code:
private void DetachFromRope()
   {
       ObiPinConstraintBatch batch = PinConstraints.GetFirstBatch();
       if (batch != null && ConstraintIndex < batch.ConstraintCount)
       {
           PinConstraints.RemoveFromSolver(null);
           batch.RemoveConstraint(ConstraintIndex);
           PinConstraints.AddToSolver(null);
       }
       Object.Destroy(GetComponent<ObiCollider>());
   }

Is there still something wrong with this?
And above all, why is it that the whole application crashes by inserting a wrong index according to you?
Cant this be fixed by throwing a safe exception? An access violation crash seems a bit harsh for an out of bounds exception!
I hope you can help me resolve this issue.
The new dump file of the crash that is still occurring: https://we.tl/SoBARZU6P0

Hi,

I'll take a look at your code asap and get back to you.

Obi uses raw, unmanaged memory buffers for performance reasons. Including range check for all indices passed trough its API (which are accessed very frame multiple times, for potentially thousands of particles) would defeat the purpose of using unmanaged memory which is precisely to avoid the checks performed by managed code and scrape performance out of it. Many other low-level buffer based c APIs (OpenGL, Flex) behave the same way: they assume you pass well-formed data to them. If the input is inconsistent, behaviour is undefined in most cases: it might work, it might not, or it might crash. Performing a range check yourself just once, before calling the API is both faster and easier, as it allows you to bail out before even entering unmanaged territory.


RE: Access violation crash! - M. Hanssen - 25-06-2018

The crash still occurs after completely removing the "remove pin constraints" logic.
The destroy code now looks like this:


Code:
private void DetachFromRope()
{
   Object.Destroy(GetComponent<ObiCollider>());
}

The crash log & dump file: https://we.tl/XW7205mLU9
I really hope you can check the dump file for us and see what's happening!


RE: Access violation crash! - M. Hanssen - 27-06-2018

*Bump* @josemendez, did you have any time to look into this issue yet?


RE: Access violation crash! - josemendez - 27-06-2018

(27-06-2018, 09:16 AM)M. Hanssen Wrote: *Bump* @josemendez, did you have any time to look into this issue yet?

Hi there!

I'm looking into it. Still crashes when assigning pin constraints, which is odd. It could be (unlikely but possible) due to some memory alignment bug. I'll give you more info once I'm certain of the cause.


RE: Access violation crash! - M. Hanssen - 09-07-2018

Thanks for your reply, we're really looking forward for a stable solution...


RE: Access violation crash! - M. Hanssen - 27-07-2018

*Bump* Any news? As we still encounter the same issue!