Access violation reading location 0x0000000C.

Started by
3 comments, last by BiiXteR 8 years ago

I'm having a problem where this error crashes my game :


Exception thrown at 0x00CFA4C4 in SDL_Game.exe: 0xC0000005: Access violation reading location 0x0000000C.

It appears this Box2D line (in my code) is causing this error :


body = World::GetWorld()->CreateBody(&bodyDef);

I know that GetWorld returns a valid pointer, so that's not the problem, however the error also leads me to a Box2D source file (b2BlockAllocator.cpp, line 112) :


if (m_freeLists[index])
{
    b2Block* block = m_freeLists[index];
    m_freeLists[index] = block->next;
    return block;
}

And when checking the values of m_freeLists it tells me :


Unable to read memory

This is how I created all the Box2D fitures, bodies etc :


bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(x, y);


body = World::GetWorld()->CreateBody(&bodyDef); // <--- Error here :(


shape.SetAsBox(size.x, size.y);


fixtureDef.shape = &shape;
fixtureDef.density = density;
fixtureDef.friction = friction;


body->CreateFixture(&fixtureDef);

I never remove / free any of these variables in my code at all, so that's not whats causing the error)

I'm not sure what else to add here since that's And here's what my b2World looks like :


b2_world = new b2World(gravity);

And the GetWorld function :


b2World* World::GetWorld()
{
    return b2_world;
}

I'm not sure what else to add, that's pretty much all Box2D code I have except for stepping the world.

Advertisement
That's definitely a null pointer crash. If you have proven that GetWorld() returns a valid pointer at that point in code (don't just blindly trust that your new b2World object makes it all the way there), the next thing to check is whether something in CreateBody has been inlined and is accessing NULL.

Where is b2_world defined? Did you define it as a global variable in a header or something silly like that?

Assuming it happens at the same location every time, if you have any trouble debugging a wrapper is in order.

body = World::GetWorld()->CreateBody(&bodyDef);

becomes

World* world = World::GetWorld();

if(!world) {

// Big error logging and debugger stopper here

} else {

body = world->CreateBody(&bodyDef);

}

As an implementation pattern, for some game designs it can make sense to have special objects that get returned in error cases, and these special objects make all kinds of noisy alerts whenever they're used in non-final releases, but otherwise act as invisible objects or a small white box or something. This type of "failure object" looks and acts like a regular game object in other ways, but make a simple test to determine if you've got the failure object (e.g. isFailureObject()) or the real object.

It is still a sentinel value just like NULL, meaning it is a key value you need to test against, but unlike NULL it should work as a fully functional object if it ever gets created after the game is released.

Assuming it happens at the same location every time, if you have any trouble debugging a wrapper is in order.


frob's approach is good. I also recommend just learning to read through the disassembled version of the code (alt-8 in visual studio with the standard keybindings). Out in the "real world" you can't rely on being able to modify code to make debugging easier. :)

I'd also definitely take the rest of frob's advice to heart. Or even go a stpe further and just remove ever actually having a pointer in the first place. Most pointers in a project are never _supposed_ to be null, so just don't let them be pointers or be null. For instance, your functions and code could change like so:


// old way
body = World::GetWorld()->CreateBody(&bodyDef);
 
// new way
body = Physics::CreateBody(World::GetWorld(), &bodyDef);

edit ... for reasons I don't fully understand, the editor cut off the second half of my reply. The very short version is to just stop using so many pointers. Use "value types" and references to objects with more reliable lifetimes. Pointers to objects that could be null are just asking for trouble.

Sean Middleditch – Game Systems Engineer – Join my team!

Assuming it happens at the same location every time, if you have any trouble debugging a wrapper is in order.

body = World::GetWorld()->CreateBody(&bodyDef);

becomes

World* world = World::GetWorld();

if(!world) {

// Big error logging and debugger stopper here

} else {

body = world->CreateBody(&bodyDef);

}

As an implementation pattern, for some game designs it can make sense to have special objects that get returned in error cases, and these special objects make all kinds of noisy alerts whenever they're used in non-final releases, but otherwise act as invisible objects or a small white box or something. This type of "failure object" looks and acts like a regular game object in other ways, but make a simple test to determine if you've got the failure object (e.g. isFailureObject()) or the real object.

It is still a sentinel value just like NULL, meaning it is a key value you need to test against, but unlike NULL it should work as a fully functional object if it ever gets created after the game is released.

I did this, and it does say "World is nullptr".


b2World* world = World::GetWorld();
if (world == nullptr)
{
    std::cout << "World is nullptr" << std::endl;
}

So, I checked my world.cpp file and realized I never actually created the box2d world...lol

This topic is closed to new replies.

Advertisement