[solved] softbody java native binding, btAligned problem

Post Reply
User avatar
Dokthar
Posts: 8
Joined: Thu Aug 13, 2015 4:57 pm

[solved] softbody java native binding, btAligned problem

Post by Dokthar »

Hi,

I am currently making a java native binding (JNI) of softbody. (for the jmonkeyengine)
When a java object is destroyed by the garbage collector i call a native code to free the bullet (native C) object.

The problem is when the bullet object is destroyed i get a [del]double free[/del] SIGSEGV exception.
At the begin i was allocating my bullet object with btAlignedAlloc and free them with btAlignedFree but i got a bunch of errors.
So using new & delete work nice.
But softbody use internally btAlignedAlloc/Free and i believe this is what caus my double free exception.

My question is : here is a way to replace btAligned by usual alloc/free (or new/delete) ?

thanks.
Last edited by Dokthar on Sun Apr 24, 2016 9:15 pm, edited 2 times in total.
Basroil
Posts: 463
Joined: Fri Nov 30, 2012 4:50 am

Re: softbody java native binding, btAligned problem

Post by Basroil »

If you disable SSE you should have no problems (other than taking forever to do it), but if you keep SSE (which does help considerably), you'll need to ensure alignment within your compiler by other means. If it's not 16byte aligned, it might just flat out crash at SSE code
anthrax11
Posts: 72
Joined: Wed Feb 24, 2010 9:49 pm

Re: softbody java native binding, btAligned problem

Post by anthrax11 »

Could the finalize method of the Java object be called twice?
If so, you can either:
1) use a boolean value to say that the native object was deleted and not call delete a second time or
2) set the pointer to the native object to 0, in which case the C++ delete operator does nothing if you try to delete a second time.
Try printing something out before deleting to see when finalize is called.

It shouldn't matter if you use btAlignedAlloc/Free or new/delete. In the first case you would just align the object twice, which is unnecessary. If alignment is really the issue, then you wouldn't get an error when deleting, but somewhere else.
User avatar
Dokthar
Posts: 8
Joined: Thu Aug 13, 2015 4:57 pm

Re: softbody java native binding, btAligned problem

Post by Dokthar »

thanks for you replies.
Sorry, unfortunately it's not double free exceptions (iirc it was when i was allocating softbody with btAlignedAlloc).

But i got a SIGSEGV every time the btSoftBody destructor is called, it is called once and crash every time :

sorry for the long post but i hope this will help : (error report & application logging)

error report :

Code: Select all

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f4086e20e0c, pid=24206, tid=139914367784704
#
# JRE version: OpenJDK Runtime Environment (8.0_72-b15) (build 1.8.0_72-internal-b15)
# Java VM: OpenJDK 64-Bit Server VM (25.72-b15 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libc.so.6+0x82e0c]  cfree+0x1c
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

---------------  T H R E A D  ---------------

Current thread (0x00007f4080085000):  JavaThread "Finalizer" daemon [_thread_in_native, id=24216, stack(0x00007f405a20d000,0x00007f405a30e000)]

siginfo: si_signo: 11 (SIGSEGV), si_code: 1 (SEGV_MAPERR), si_addr: 0x00000000000000dd

Registers:
RAX=0x0000000000000000, RBX=0x00007f4015d92c60, RCX=0x00007f3ffcf3cf40, RDX=0x00000000000000e5
RSP=0x00007f405a30c758, RBP=0x00007f405a30c770, RSI=0x0000000000000000, RDI=0x00000000000000e5
R8 =0x00007f4086f14d00, R9 =0x00007f3ffcf3b8e0, R10=0x00007f405a30c510, R11=0x00007f40052b6e0c
R12=0x0000000000000000, R13=0x00007f4015d92c60, R14=0x00007f405a30c908, R15=0x00007f4080085000
RIP=0x00007f4086e20e0c, EFLAGS=0x0000000000010202, CSGSFS=0x0000000000000033, ERR=0x0000000000000004
  TRAPNO=0x000000000000000e

Top of Stack: (sp=0x00007f405a30c758)
0x00007f405a30c758:   00007f4005246aaf 00007f3ffcf3d500
0x00007f405a30c768:   00000000000000e5 00007f405a30c7a0
0x00007f405a30c778:   00007f4005246b55 00000000fcf463c0
0x00007f405a30c788:   00007f3ffcf415d0 00007f3ffcf3b890
0x00007f405a30c798:   00000000000000e5 00007f405a30c7c0
0x00007f405a30c7a8:   00007f4005246c5c 0000000000000000
0x00007f405a30c7b8:   00007f3ffcf415d0 00007f405a30c800
0x00007f405a30c7c8:   00007f4005296cae 00007f3ffcf463c0
0x00007f405a30c7d8:   00007f3ffcf463c0 00007f3ffcf463c0
0x00007f405a30c7e8:   0000000086f14dc0 00007f3ffcf3ba40
0x00007f405a30c7f8:   00007f4015d92c60 00007f405a30c820
0x00007f405a30c808:   00007f400529703c 00007f4015d92c60
0x00007f405a30c818:   00007f3ffcf463c0 00007f405a30c870
0x00007f405a30c828:   00007f40052818c7 00007f405b678558
0x00007f405a30c838:   00007f3ffcf463c0 00007f405a30c908
0x00007f405a30c848:   00007f40800851e0 00007f405a30c880
0x00007f405a30c858:   00007f3ffcf463c0 00007f4070dfe98d
0x00007f405a30c868:   00007f3ffcf3ba40 00007f405a30c8d8
0x00007f405a30c878:   00007f4070e0c6d4 00000000d6aa09b0
0x00007f405a30c888:   00000000d6a9f850 00007f405a30c890
0x00007f405a30c898:   00007f405a30c898 0000000000000000
0x00007f405a30c8a8:   00007f405a30c908 00007f4015db98e0
0x00007f405a30c8b8:   0000000000000000 00007f4015d92c60
0x00007f405a30c8c8:   0000000000000000 00007f405a30c8f8
0x00007f405a30c8d8:   00007f405a30c950 00007f4070dfe98d
0x00007f405a30c8e8:   0000000000000000 00007f4070e062b8
0x00007f405a30c8f8:   00007f3ffcf463c0 0000000083fa07a8
0x00007f405a30c908:   00000000d8a3fd88 00007f405a30c910
0x00007f405a30c918:   00007f4015d92bb6 00007f405a30c960
0x00007f405a30c928:   00007f4015db98e0 0000000000000000
0x00007f405a30c938:   00007f4015d92bd8 00007f405a30c8f8
0x00007f405a30c948:   00007f405a30c960 00007f405a30c9a8 

Instructions: (pc=0x00007f4086e20e0c)
0x00007f4086e20dec:   00 00 00 00 48 8b 05 f1 b0 33 00 48 8b 00 48 85
0x00007f4086e20dfc:   c0 0f 85 c7 00 00 00 48 85 ff 0f 84 bc 00 00 00
0x00007f4086e20e0c:   48 8b 47 f8 48 8d 77 f0 a8 02 75 28 a8 04 48 8d
0x00007f4086e20e1c:   3d 3f b9 33 00 74 0c 48 89 f0 48 25 00 00 00 fc 

Register to memory mapping:

RAX=0x0000000000000000 is an unknown value
RBX={method} {0x00007f4015d92c60} 'finalizeNative' '(J)V' in 'com/jme3/bullet/collision/PhysicsCollisionObject'
RCX=0x00007f3ffcf3cf40 is an unknown value
RDX=0x00000000000000e5 is an unknown value
RSP=0x00007f405a30c758 is pointing into the stack for thread: 0x00007f4080085000
RBP=0x00007f405a30c770 is pointing into the stack for thread: 0x00007f4080085000
RSI=0x0000000000000000 is an unknown value
RDI=0x00000000000000e5 is an unknown value
R8 =0x00007f4086f14d00: <offset 0x176d00> in /lib/x86_64-linux-gnu/libc.so.6 at 0x00007f4086d9e000
R9 =0x00007f3ffcf3b8e0 is an unknown value
R10=0x00007f405a30c510 is pointing into the stack for thread: 0x00007f4080085000
R11=0x00007f40052b6e0c: _ZN20btAlignedObjectArrayIPN10btSoftBody7ClusterEE8pop_backEv+0 in /home/dokthar/workspace-JME/SoftPhysics-Test/libbulletjme.so at 0x00007f4005149000
R12=0x0000000000000000 is an unknown value
R13={method} {0x00007f4015d92c60} 'finalizeNative' '(J)V' in 'com/jme3/bullet/collision/PhysicsCollisionObject'
R14=0x00007f405a30c908 is pointing into the stack for thread: 0x00007f4080085000
R15=0x00007f4080085000 is a thread


Stack: [0x00007f405a20d000,0x00007f405a30e000],  sp=0x00007f405a30c758,  free space=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [libc.so.6+0x82e0c]  cfree+0x1c
C  [libbulletjme.so+0xfdb55]  btAlignedFreeDefault(void*)+0x2f
C  [libbulletjme.so+0xfdc5c]  btAlignedFreeInternal(void*)+0x3a
C  [libbulletjme.so+0x14dcae]  btSoftBody::~btSoftBody()+0xd8
C  [libbulletjme.so+0x14e03c]  btSoftBody::~btSoftBody()+0x18
C  [libbulletjme.so+0x1388c7]  Java_com_jme3_bullet_collision_PhysicsCollisionObject_finalizeNative+0xbe
j  com.jme3.bullet.collision.PhysicsCollisionObject.finalizeNative(J)V+0
j  com.jme3.bullet.collision.PhysicsCollisionObject.finalize()V+30
j  com.jme3.bullet.objects.PhysicsSoftBody.finalize()V+32
J 1522 C1 java.lang.ref.Finalizer.runFinalizer(Lsun/misc/JavaLangAccess;)V (62 bytes) @ 0x00007f40713203c4 [0x00007f407131fe40+0x584]
J 1521 C1 java.lang.ref.Finalizer.access$100(Ljava/lang/ref/Finalizer;Lsun/misc/JavaLangAccess;)V (6 bytes) @ 0x00007f407131fadc [0x00007f407131fa80+0x5c]
j  java.lang.ref.Finalizer$FinalizerThread.run()V+45
v  ~StubRoutines::call_stub
V  [libjvm.so+0x631cea]
V  [libjvm.so+0x62f3c4]
V  [libjvm.so+0x62f9ba]
V  [libjvm.so+0x66f16e]
V  [libjvm.so+0x99eb00]
V  [libjvm.so+0x8570f2]
C  [libpthread.so.0+0x8182]  start_thread+0xc2

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  com.jme3.bullet.collision.PhysicsCollisionObject.finalizeNative(J)V+0
j  com.jme3.bullet.collision.PhysicsCollisionObject.finalize()V+30
j  com.jme3.bullet.objects.PhysicsSoftBody.finalize()V+32
J 1522 C1 java.lang.ref.Finalizer.runFinalizer(Lsun/misc/JavaLangAccess;)V (62 bytes) @ 0x00007f40713203c4 [0x00007f407131fe40+0x584]
J 1521 C1 java.lang.ref.Finalizer.access$100(Ljava/lang/ref/Finalizer;Lsun/misc/JavaLangAccess;)V (6 bytes) @ 0x00007f407131fadc [0x00007f407131fa80+0x5c]
j  java.lang.ref.Finalizer$FinalizerThread.run()V+45
v  ~StubRoutines::call_stub
Application logging :

Code: Select all

Apr 18, 2016 3:17:38 PM com.jme3.bullet.PhysicsSpace finalize
FINE: Finalizing PhysicsSpace 7f401c32ec40
Apr 18, 2016 3:17:38 PM com.jme3.bullet.PhysicsSpace finalize
FINE: Finalizing PhysicsSpace 7f40280008c0
Apr 18, 2016 3:17:38 PM com.jme3.bullet.collision.PhysicsCollisionObject finalize
FINE: Finalizing CollisionObject 7f3ffcf39ae0
Apr 18, 2016 3:17:38 PM com.jme3.bullet.objects.infos.RigidBodyMotionState finalize
FINE: Finalizing MotionState 7f3ffcf399b0
Apr 18, 2016 3:17:38 PM com.jme3.bullet.collision.shapes.CollisionShape finalize
FINE: Finalizing CollisionShape 7f3ffcf39a70
Apr 18, 2016 3:17:38 PM com.jme3.bullet.collision.PhysicsCollisionObject finalize
FINE: Finalizing CollisionObject 7f3ffcf3a340
com.jme3.bullet.objects.PhysicsSoftBody.finalize() called : objectId = 7f3ffcf463c0
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f4086e20e0c, pid=24206, tid=139914367784704
#
# JRE version: OpenJDK Runtime Environment (8.0_72-b15) (build 1.8.0_72-internal-b15)
# Java VM: OpenJDK 64-Bit Server VM (25.72-b15 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libc.so.6+0x82e0c]  cfree+0x1c
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/dokthar/workspace-JME/SoftPhysics-Test/hs_err_pid24206.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Native side, Finalizing CollisionObject : 7f3ffcf39ae0
Native side, Finalizing CollisionObject : 7f3ffcf3a340
Native side, Finalizing CollisionObject : 7f3ffcf463c0
Apr 18, 2016 3:17:38 PM com.jme3.bullet.objects.infos.RigidBodyMotionState finalize
FINE: Finalizing MotionState 7f3ffcf3a210
Apr 18, 2016 3:17:38 PM com.jme3.bullet.collision.shapes.CollisionShape finalize
FINE: Finalizing CollisionShape 7f3ffcf3a2d0
Apr 18, 2016 3:17:38 PM com.jme3.bullet.collision.PhysicsCollisionObject finalize
FINE: Finalizing CollisionObject 7f3ffcf463c0
Apr 18, 2016 3:17:38 PM com.jme3.util.NativeObjectManager deleteUnused
FINE: NativeObjectManager: 16 native objects were removed from native
Java Result: 134
Edit : i do not call the finalize method, but a JVM demon does, and there are called only once (when the java object is destroyed by the garbage collector).
Edit : also to trigger the garbage collector i repeat in a short amount of time 3 to 5 times a simulation ( creation of a PhysicsSoftSpace(btSoftRigidDynamicsWorld, ...) adding rigid and soft bodies, adding constraint )
anthrax11
Posts: 72
Joined: Wed Feb 24, 2010 9:49 pm

Re: softbody java native binding, btAligned problem

Post by anthrax11 »

Can you show how you set up the softbodies in Java?

~btSoftBody also cleans up clusters, materials and joints, so maybe there is a Java object that wraps one of them, loses scope and gets cleaned up by the GC too soon?
User avatar
Dokthar
Posts: 8
Joined: Thu Aug 13, 2015 4:57 pm

Re: softbody java native binding, btAligned problem

Post by Dokthar »

thanks.
@anthrax11 : i think it's related to my setup for joint & anchors. I tested with only softbodies and i didn't get any issues .

I also used valgrind and i figured out that some times softbody destruction is fine. But when it fail it's seem related to joints (or anchors which are handled differently).

On my side i handle soft joints like a constraint so i want to add/remove them without needing to call a softbody's method.
User avatar
Dokthar
Posts: 8
Joined: Thu Aug 13, 2015 4:57 pm

Re: softbody java native binding, btAligned problem

Post by Dokthar »

I think i understand my problem : some times the softbody is finalized but not his joints or anchors, when this append the are finalized by the btSoftBody destructor. but this destructor use btAlignedFree on not btAlignedAlloc'd object which i think cause my errors.

all the source can be found on here :
java : https://github.com/Dokthar/jmonkeyengin ... me3/bullet
native JNI : https://github.com/Dokthar/jmonkeyengin ... native/cpp

This is the most relevant code for Joint :

how a AJoint is created :

Code: Select all

 /*
     * Class:     com_jme3_bullet_joints_SoftAngularJoint
     * Method:    createJointSoftRigid
     * Signature: (JJLcom/jme3/math/Vector3f;Lcom/jme3/math/Vector3f;FFFLcom/jme3/math/Vector3f;)J
     */
    JNIEXPORT jlong JNICALL Java_com_jme3_bullet_joints_SoftAngularJoint_createJointSoftRigid
    (JNIEnv *env, jobject object, jlong softIdA, jlong rigidIdB, jobject pivotA, jobject pivotB, jfloat erp, jfloat cfm, jfloat split, jobject axis) {
        btSoftBody* softA = reinterpret_cast<btSoftBody*> (softIdA);
        if (softA == NULL) {
            jclass newExc = env->FindClass("java/lang/NullPointerException");
            env->ThrowNew(newExc, "The native object does not exist.");
            return 0;
        }

        btRigidBody* rigidB = reinterpret_cast<btRigidBody*> (rigidIdB);
        if (rigidB == NULL) {
            jclass newExc = env->FindClass("java/lang/NullPointerException");
            env->ThrowNew(newExc, "The native object does not exist.");
            return 0;
        }

        btVector3 ax = btVector3();
        jmeBulletUtil::convert(env, axis, &ax);

        btVector3 pivA = btVector3();
        jmeBulletUtil::convert(env, pivotA, &pivA);

        btVector3 pivB = btVector3();
        jmeBulletUtil::convert(env, pivotB, &pivB);

        btSoftBody::AJoint* ajoint = new btSoftBody::AJoint();
        ajoint->m_bodies[0] = softA->m_clusters[0];
        ajoint->m_bodies[1] = rigidB;

        ajoint->m_refs[0] = ajoint->m_bodies[0].xform().inverse().getBasis() * ax;
        ajoint->m_refs[1] = ajoint->m_bodies[1].xform().inverse().getBasis() * ax;

        ajoint->m_icontrol = btSoftBody::AJoint::IControl::Default();

        ajoint->m_cfm = cfm;
        ajoint->m_erp = erp;
        ajoint->m_split = split;

        return reinterpret_cast<long> (ajoint);
    }
called upon adding/removing the joint to/from the physics space :

Code: Select all

 /*
     * Class:     com_jme3_bullet_joints_SoftPhysicsJoint
     * Method:    addConstraint
     * Signature: (JJ)V
     */
    JNIEXPORT void JNICALL Java_com_jme3_bullet_joints_SoftPhysicsJoint_addConstraint
    (JNIEnv *env, jobject object, jlong jointId, jlong bodyId) {
        btSoftBody::Joint* joint = reinterpret_cast<btSoftBody::Joint*> (jointId);
        if (joint == NULL) {
            jclass newExc = env->FindClass("java/lang/NullPointerException");
            env->ThrowNew(newExc, "The native object does not exist.");
            return;
        }

        btSoftBody* soft = reinterpret_cast<btSoftBody*> (bodyId);
        if (soft == NULL) {
            jclass newExc = env->FindClass("java/lang/NullPointerException");
            env->ThrowNew(newExc, "The native object does not exist.");
            return;
        }

        soft->m_joints.push_back(joint);
    }

    /*
     * Class:     com_jme3_bullet_joints_SoftPhysicsJoint
     * Method:    removeConstraint
     * Signature: (JJ)V
     */
    JNIEXPORT void JNICALL Java_com_jme3_bullet_joints_SoftPhysicsJoint_removeConstraint
    (JNIEnv *env, jobject object, jlong jointId, jlong bodyId) {
        btSoftBody::Joint* joint = reinterpret_cast<btSoftBody::Joint*> (jointId);
        if (joint == NULL) {
            jclass newExc = env->FindClass("java/lang/NullPointerException");
            env->ThrowNew(newExc, "The native object does not exist.");
            return;
        }

        btSoftBody* soft = reinterpret_cast<btSoftBody*> (bodyId);
        if (soft == NULL) {
            jclass newExc = env->FindClass("java/lang/NullPointerException");
            env->ThrowNew(newExc, "The native object does not exist.");
            return;
        }

        soft->m_joints.remove(joint);
    }
called on finalize :

Code: Select all

    /*
     * Class:     com_jme3_bullet_joints_SoftPhysicsJoint
     * Method:    finalizeNative
     * Signature: (J)V
     */
    JNIEXPORT void JNICALL Java_com_jme3_bullet_joints_SoftPhysicsJoint_finalizeNative
    (JNIEnv *env, jobject object, jlong jointId) {
        btSoftBody::Joint* joint = reinterpret_cast<btSoftBody::Joint*> (jointId);
        if (joint == NULL) {
            jclass newExc = env->FindClass("java/lang/NullPointerException");
            env->ThrowNew(newExc, "The native object does not exist.");
            return;
        }
        
        delete joint;
    }
Edit : i think i understand the double free exception : using the btAlignedFree/Alloc the joint is deleted by the java softJoint then a second btAlignedFree is called upon the delete of the btSoftBody. If i don't use btAlignedFree/Alloc i get a SIGSEGV once the joint is deleted by the btSoftBody.
I am going to verify this.
anthrax11
Posts: 72
Joined: Wed Feb 24, 2010 9:49 pm

Re: softbody java native binding, btAligned problem

Post by anthrax11 »

Yes, that is correct. SoftPhysicsJoint should only delete the joint if it's not in m_joints, otherwise ~btSoftBody will delete it, as you said.

The API is designed such that joints are both created and added with appendAngularJoint and are never removed. That way the memory is always handled by Bullet. But in your case, adding to and removing from m_joints will work fine too as long as you use btAlignedAlloc/btAlignedFree.

btSoftBody overrides the new/delete operators (see BT_DECLARE_ALIGNED_ALLOCATOR), so it does not need btAlignedAlloc/btAlignedFree. AJoint doesn't have that, but alignment is still necessary because of the m_refs member, which can be accessed using SSE instructions, so btAlignedAlloc/btAlignedFree are needed.

You could also construct the joint using appendAngularJoint and then grab its reference like so:
btSoftBody::Joint* joint = m_joints[m_joints->size() - 1]
That would make constructing the joint easier, but the joint would be added immediately, which might not be what you want.

On the other hand, if you let users create, add and free joint objects on their own, then it makes sense to always just clear m_joints before deleting the softbody. This prevents ~btSoftBody from freeing the joints and they would later be freed by SoftPhysicsJoint_finalizeNative.

Either way you need to call btAlignedFree on the joint, but only if the softbody doesn't own it.
User avatar
Dokthar
Posts: 8
Joined: Thu Aug 13, 2015 4:57 pm

Re: softbody java native binding, btAligned problem

Post by Dokthar »

thanks for you answer. effectively this solved my issue (at least for soft joint, didn't tested for anchors)
I just added a boolean : if the joint is still "attached" to the softbody i do nothing else it will be finalized.

diff : https://github.com/Dokthar/jmonkeyengin ... 929f523fc4
the joint would be added immediately, which might not be what you want.
That's true.

thanks again, for all the informations.
Post Reply