box2d-optimized icon indicating copy to clipboard operation
box2d-optimized copied to clipboard

Crash after creating 28 dynamic objects at runtime.

Open RonYanDaik opened this issue 1 year ago • 7 comments

For some reason after proceeding with Step function if i try create new dynamic object and number of dynamic object is more then 28 I get crash at ContactManager::FindNewContacts.

I don't have such issue with original lib. Am I suppose to suppose to set up something? Thank you.

image

image

inside b2BroadPhase::UpdateAndQuery(T* callback) image

RonYanDaik avatar Apr 06 '23 14:04 RonYanDaik

I did some more testing and found out that the crash happens depending from number of static bodies (or fixtures) in the scene.

Crash happens: image

crash does not happen: image

crash does not happen: image

RonYanDaik avatar Apr 06 '23 21:04 RonYanDaik

Apparently problem is here:

image

m_rootStatic members ore not valid (not null but also not a value). Thats why (root->IsLeaf()) gives false May be it got somewhere deleted and not nullified?

RonYanDaik avatar Apr 06 '23 21:04 RonYanDaik

Hi, thanks for the detailed summary. In general the broadphase detector will use slightly different algorithms depending on the ratio of dynamic to static bodies because then it can do faster detection. This can be seen here https://github.com/mtsamis/box2d-optimized/blob/505bb43175e6126d13dba398c2cc5d618c818f89/include/box2d/b2_broad_phase.h#L278-L284 where the heuristic is enabled when the number of static bodies is > 1/8 of the total number of bodies. It looks like m_rootStatic is left invalid in one of the transitions of using the other broadphase strategy.

Do you have code that can help me reproduce that? I can have a look.

mtsamis avatar Apr 07 '23 06:04 mtsamis

I've got new exception. this time it tries to access right member which is invalid.

image

RonYanDaik avatar Apr 07 '23 09:04 RonYanDaik

Do you have code that can help me reproduce that? I can have a look.

I think I've managed to reproduce it in Tiles test.

this is the code for entire Tiles class. I've changed static ground creation and added creation of bodies in Step() function.

class Tiles : public Test
{
public:
    enum
    {
        e_count = 2
      };

    Tiles()
    {
        m_fixtureCount = 0;
        b2Timer timer;

        {
            float a = 10.5f;
            b2BodyDef bd;
            bd.position.y = -a;

            int32 N = 4;
            int32 M = 2;
            b2Vec2 position;
            position.y = 0.0f;
            for (int32 j = 0; j < M; ++j)
            {
                position.x = -N * a;
                for (int32 i = 0; i < N; ++i)
                {
                    bd.position = position;
                    b2Body* ground = m_world->CreateBody(&bd);

                    b2PolygonShape shape;
                    shape.SetAsBox(a, a*0.5);
                    ground->CreateFixture(&shape, 0.0f);
                    ++m_fixtureCount;
                    position.x += 2.0f * a;
                    //code line bellow wil lbreak static bodies
                    //ground->SetTransform(position,0.0f);
                }
                position.y -= 2.0f * a;
            }

        }

        {
            float a = 0.5f;
            b2PolygonShape shape;
            shape.SetAsBox(a, a);

            b2Vec2 x(-7.0f, 0.75f);
            b2Vec2 y;
            b2Vec2 deltaX(0.5625f, 1.25f);
            b2Vec2 deltaY(1.125f, 0.0f);

            for (int32 i = 0; i < e_count; ++i)
            {
                y = x;

                for (int32 j = i; j < e_count; ++j)
                {
                    b2BodyDef bd;
                    bd.type = b2_dynamicBody;
                    bd.position = y;
                    bd.position.y = 50 - bd.position.y;

                    b2Body* body = m_world->CreateBody(&bd);
                    body->CreateFixture(&shape, 5.0f);
                    ++m_fixtureCount;
                    y += deltaY;
                }

                x += deltaX;
            }
        }

        m_createTime = timer.GetMilliseconds();
    }

    void Step(Settings& settings) override
    {
        /*
        const b2ContactManager& cm = m_world->GetContactManager();
        int32 height = cm.m_broadPhase.GetTreeHeight();
        int32 leafCount = cm.m_broadPhase.GetCount();
        int32 minimumNodeCount = 2 * leafCount - 1;
        float minimumHeight = ceilf(logf(float(minimumNodeCount)) / logf(2.0f));
        g_debugDraw.DrawString(5, m_textLine, "dynamic tree height = %d, min = %d", height, int32(minimumHeight));
        m_textLine += m_textIncrement;
        */

        Test::Step(settings);

        g_debugDraw.DrawString(5, m_textLine, "create time = %6.2f ms, fixture count = %d",
          m_createTime, m_fixtureCount);
        m_textLine += m_textIncrement;

        float a = 0.5f;
        b2PolygonShape shape;
        shape.SetAsBox(a, a);
        static int cnt =0;

        if(cnt<1500)
        {
            cnt++;

            b2BodyDef bd;
            bd.type = b2_dynamicBody;
            bd.position.y = 50;

            b2Body* body = m_world->CreateBody(&bd);
            body->CreateFixture(&shape, 5.0f);
        }
    }

    static Test* Create()
    {
        return new Tiles;
    }

    int32 m_fixtureCount;
    float m_createTime;
};

static int testIndex = RegisterTest("Benchmark", "Tiles", Tiles::Create);

I've commented line int32 height = cm.m_broadPhase.GetTreeHeight(); because it also gives exception.

RonYanDaik avatar Apr 07 '23 09:04 RonYanDaik

Maybe I'm onto something here? Looks like oldNodes points to m_rootStatic and here its being freed with b2Free(oldNodes). And from here on m_rootStatic has invalid values. image

RonYanDaik avatar Apr 07 '23 13:04 RonYanDaik

And from here on m_rootStatic has invalid values.

Adding m_rootStatic = nullptr; there fixed the crash but I have no idea if it will break speed of algorithm or not.

RonYanDaik avatar Apr 07 '23 13:04 RonYanDaik