AndresTraks / BulletSharpPInvoke

.NET wrapper for the Bullet physics library using Platform Invoke
http://andrestraks.github.io/BulletSharp/
150 stars 97 forks source link

Very infrequent and random bad memory accesses #68

Closed maxilevi closed 4 years ago

maxilevi commented 4 years ago

I am having different exceptions pop up infrequently on different places causing the game to randomly crash. The exceptions occur on anything related to bullet like when an object gets finalized, when a dynamics world is updated, etc. Since they are infrequent and all are related to bad native memory accesses I am having a very hard time to reproduce/track/fix them.

My question is: Do you have any idea of what may be causing this (some compilation options maybe?) or if not a way of reducing these type of issues?

Here is an example of one of them

System.BadImageFormatException: Illegal storage access. (Exception from HRESULT: 0x800703E6)
bei System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
bei System.Runtime.InteropServices.Marshal.FreeHGlobal(IntPtr hglobal)
bei BulletSharp.IndexedMesh.Free()
bei BulletSharp.IndexedMesh.Dispose(Boolean disposing)
bei BulletSharp.BulletDisposableObject.Finalize()

I really appreciate any help, thank you

AndresTraks commented 4 years ago

It could be that IndexedMesh is trying to free its memory, but the memory is actually contained within a btTriangleIndexVertexArray, which has already been deleted.

I'll review the cleanup logic soon. Ideally, Finalize should never get called if all objects are correctly Disposed.

maxilevi commented 4 years ago

Thank you, that was helpful, thats exactly what was happening.

However I am still getting this type of exception on DynamicsWorld.StepSimulation every now and then:

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at BulletSharp.UnsafeNativeMethods.btDynamicsWorld_stepSimulation(IntPtr obj, Single timeStep, Int32 maxSubSteps, Single fixedTimeStep)
   at BulletSharp.DynamicsWorld.StepSimulation(Single timeStep, Int32 maxSubSteps, Single fixedTimeStep) in D:\Repositories\BulletSharpPInvoke\BulletSharp\Dynamics\DynamicsWorld.cs:line 240
   at Hedra.Engine.Bullet.BulletPhysics.Update(Single DeltaTime) in D:\Project Hedra\Hedra\Engine\Bullet\BulletPhysics.cs:line 95
   at Hedra.Engine.Loader.Hedra.UpdateFrame(Double Delta) in D:\Project Hedra\Hedra\Engine\Loader\Hedra.cs:line 160
   at Hedra.Engine.Loader.HedraWindow.Run() in D:\Project Hedra\Hedra\Engine\Loader\HedraWindow.cs:line 95
   at Hedra.Engine.Program.RunNormalAndDummyMode(Boolean DummyMode) in D:\Project Hedra\Hedra\Engine\Program.cs:line 191
   at Hedra.Engine.Program.Main(String[] Args) in D:\Project Hedra\Hedra\Engine\Program.cs:line 80

Any clue on what it might be related to?

AndresTraks commented 4 years ago

StepSimulation internally goes through a lot of native code, so it is difficult to diagnose in release mode. The best way to investigate is to compile libbulletc in debug mode and "Enable native code debugging" in your .NET application.

Since it's a memory access problem, it is probably related to the cleanup problem. Like some object is getting freed while it is still used in the dynamics world.

I haven't yet figured out how to replicate the IndexedMesh problem. It would be good if you could show me how you set up the TriangleIndexVertexArrays/IndexedMeshes. IndexedMesh allows for some memory manipulation with pointers that could be dangerous.

maxilevi commented 4 years ago

I haven't yet figured out how to replicate the IndexedMesh problem. It would be good if you could show me how you set up the TriangleIndexVertexArrays/IndexedMeshes. IndexedMesh allows for some memory manipulation with pointers that could be dangerous.

I don't think I am doing anything too crazy. Here is my code:

public static BvhTriangleMeshShape CreateTriangleShape(ICollection<uint> Indices, ICollection<System.Numerics.Vector3> Vertices)
        {
            var triangleMesh = new TriangleIndexVertexArray();
            var indexedMesh = CreateIndexedMesh(Indices, Vertices);
            triangleMesh.AddIndexedMesh(indexedMesh);
            return new BvhTriangleMeshShape(triangleMesh, true);
        }

        private static IndexedMesh CreateIndexedMesh(ICollection<uint> Indices, ICollection<System.Numerics.Vector3> Vertices)
        {
            var indexedMesh = new IndexedMesh();
            indexedMesh.Allocate(Indices.Count / 3, Vertices.Count);
            indexedMesh.SetData(
                Indices.Select(I => (int) I).ToList(),
                Vertices.SelectMany(V => new[] {V.X, V.Y, V.Z}).ToList()
            );
            return indexedMesh;
        }

When disposing of a rigidbody I only disposed the BvhTriangleMeshShape and not the TriangleIndexVertexArray nor the IndexedMesh that were inside.

One thing to note is that I was unable reproduce the exception on my system. It happened to a user while playing the game.

maxilevi commented 4 years ago

@AndresTraks Here is an example of what I was referring earlier. Rarely and on some computers on disposing an object the heap gets corrupted. Here is the trace from WinDBG

OS Thread Id: 0x2338 (0)
        Child SP               IP Call Site
000000c19d36e4b0 00007ff94141cc14 [InlinedCallFrame: 000000c19d36e4b0] BulletSharp.UnsafeNativeMethods.btCollisionShape_delete(IntPtr)
000000c19d36e4b0 00007ff8ce413359 [InlinedCallFrame: 000000c19d36e4b0] BulletSharp.UnsafeNativeMethods.btCollisionShape_delete(IntPtr)
000000c19d36e480 00007ff8ce413359 BulletSharp.CollisionShape.Dispose(Boolean)
    PARAMETERS:
        this = <no data>
        disposing = <no data>

000000c19d36e530 00007ff8ce347db0 BulletSharp.BulletDisposableObject.Dispose()
    PARAMETERS:
        this (<CLR reg>) = 0x0000022a21132c00

000000c19d36e560 00007ff8ce4a4b8d *** WARNING: Unable to verify checksum for Hedra.exe
Hedra.Engine.Bullet.BulletPhysics.DisposeBody(BulletSharp.RigidBody) [D:\Project Hedra\Hedra\Engine\Bullet\BulletPhysics.cs @ 459]
    PARAMETERS:

000000c19d36e5b0 00007ff8ce4a4302 Hedra.Engine.Bullet.BulletPhysics.RemoveAndDispose(BulletSharp.RigidBody) [D:\Project Hedra\Hedra\Engine\Bullet\BulletPhysics.cs @ 391]
    PARAMETERS:

000000c19d36e620 00007ff8ce4a5318 Hedra.Engine.WorldBuilding.BaseStructure.Dispose() [D:\Project Hedra\Hedra\Engine\WorldBuilding\BaseStructure.cs @ 88]

Any ideas of what could be causing this?