From 2b880d1264f1493f50bee3906b7d48ecdae4fc6e Mon Sep 17 00:00:00 2001 From: Erin Catto Date: Thu, 15 Aug 2024 20:36:40 -0700 Subject: [PATCH] Fix null being passed to memcpy (#770) Joints were incorrectly using the body bit-set for the overflow color Sensor shapes now always generate events when created --- README.md | 2 ++ include/box2d/types.h | 1 + samples/sample_continuous.cpp | 2 ++ src/bitset.c | 3 ++- src/bitset.h | 2 +- src/block_array.c | 5 +++++ src/constraint_graph.c | 24 ++++++++++++++---------- src/constraint_graph.h | 3 ++- src/dynamic_tree.c | 1 + src/shape.c | 2 +- 10 files changed, 31 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 0abfca65c..903a950c6 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ # Box2D Box2D is a 2D physics engine for games. +[![Box2D Version 3.0 Release Demo](https://img.youtube.com/vi/dAoM-xjOWtA/0.jpg)](https://www.youtube.com/watch?v=dAoM-xjOWtA) + ## Features ### Collision diff --git a/include/box2d/types.h b/include/box2d/types.h index e03c33ed1..54f395ed5 100644 --- a/include/box2d/types.h +++ b/include/box2d/types.h @@ -343,6 +343,7 @@ typedef struct b2ShapeDef /// Normally shapes on static bodies don't invoke contact creation when they are added to the world. This overrides /// that behavior and causes contact creation. This significantly slows down static body creation which can be important /// when there are many static shapes. + /// This is implicitly always true for sensors. bool forceContactCreation; /// Used internally to detect a valid definition. DO NOT SET. diff --git a/samples/sample_continuous.cpp b/samples/sample_continuous.cpp index f6727261c..b1984bfe8 100644 --- a/samples/sample_continuous.cpp +++ b/samples/sample_continuous.cpp @@ -67,6 +67,8 @@ class BounceHouse : public Sample m_bodyId = b2_nullBodyId; m_enableHitEvents = true; + memset( m_hitEvents, 0, sizeof( m_hitEvents ) ); + Launch(); } diff --git a/src/bitset.c b/src/bitset.c index 413ac570f..861678b01 100644 --- a/src/bitset.c +++ b/src/bitset.c @@ -49,7 +49,8 @@ void b2GrowBitSet( b2BitSet* bitSet, uint32_t blockCount ) bitSet->blockCapacity = blockCount + blockCount / 2; uint64_t* newBits = b2Alloc( bitSet->blockCapacity * sizeof( uint64_t ) ); memset( newBits, 0, bitSet->blockCapacity * sizeof( uint64_t ) ); - memcpy( newBits, bitSet->bits, bitSet->blockCount * sizeof( uint64_t ) ); + B2_ASSERT( bitSet->bits != NULL ); + memcpy( newBits, bitSet->bits, oldCapacity * sizeof( uint64_t ) ); b2Free( bitSet->bits, oldCapacity * sizeof( uint64_t ) ); bitSet->bits = newBits; } diff --git a/src/bitset.h b/src/bitset.h index 0a76f6447..848b486d3 100644 --- a/src/bitset.h +++ b/src/bitset.h @@ -8,7 +8,7 @@ #include #include -// Bit set provides fast operations on large arrays of bits +// Bit set provides fast operations on large arrays of bits. typedef struct b2BitSet { uint64_t* bits; diff --git a/src/block_array.c b/src/block_array.c index 8ca09c531..574fd20f4 100644 --- a/src/block_array.c +++ b/src/block_array.c @@ -102,6 +102,7 @@ b2BodySim* b2AddBodySim( b2BodySimArray* array ) { int newCapacity = 2 * array->capacity; b2BodySim* newElements = b2Alloc( newCapacity * elementSize ); + B2_ASSERT( array->data != NULL ); memcpy( newElements, array->data, array->capacity * elementSize ); b2Free( array->data, array->capacity * elementSize ); array->data = newElements; @@ -126,6 +127,7 @@ b2BodyState* b2AddBodyState( b2BodyStateArray* array ) { int newCapacity = 2 * array->capacity; b2BodyState* newElements = b2Alloc( newCapacity * elementSize ); + B2_ASSERT( array->data != NULL ); memcpy( newElements, array->data, array->capacity * elementSize ); b2Free( array->data, array->capacity * elementSize ); array->data = newElements; @@ -150,6 +152,7 @@ b2ContactSim* b2AddContact( b2ContactArray* array ) { int newCapacity = 2 * array->capacity; b2ContactSim* newElements = b2Alloc( newCapacity * elementSize ); + B2_ASSERT( array->data != NULL ); memcpy( newElements, array->data, array->capacity * elementSize ); b2Free( array->data, array->capacity * elementSize ); array->data = newElements; @@ -174,6 +177,7 @@ b2JointSim* b2AddJoint( b2JointArray* array ) { int newCapacity = 2 * array->capacity; b2JointSim* newElements = b2Alloc( newCapacity * elementSize ); + B2_ASSERT( array->data != NULL ); memcpy( newElements, array->data, array->capacity * elementSize ); b2Free( array->data, array->capacity * elementSize ); array->data = newElements; @@ -198,6 +202,7 @@ b2IslandSim* b2AddIsland( b2IslandArray* array ) { int newCapacity = 2 * array->capacity; b2IslandSim* newElements = b2Alloc( newCapacity * elementSize ); + B2_ASSERT( array->data != NULL ); memcpy( newElements, array->data, array->capacity * elementSize ); b2Free( array->data, array->capacity * elementSize ); array->data = newElements; diff --git a/src/constraint_graph.c b/src/constraint_graph.c index 8f4a93364..41a6b18f3 100644 --- a/src/constraint_graph.c +++ b/src/constraint_graph.c @@ -30,19 +30,19 @@ _Static_assert( b2_graphColorCount == 12, "graph color count assumed to be 12" ) void b2CreateGraph( b2ConstraintGraph* graph, int bodyCapacity ) { _Static_assert( b2_graphColorCount >= 2, "must have at least two constraint graph colors" ); + _Static_assert( b2_overflowIndex == b2_graphColorCount - 1, "bad over flow index"); *graph = ( b2ConstraintGraph ){ 0 }; bodyCapacity = b2MaxInt( bodyCapacity, 8 ); - for ( int i = 0; i < b2_graphColorCount; ++i ) + + // Initialize graph color bit set. + // No bitset for overflow color. + for ( int i = 0; i < b2_overflowIndex; ++i ) { b2GraphColor* color = graph->colors + i; - - if ( i != b2_overflowIndex ) - { - color->bodySet = b2CreateBitSet( bodyCapacity ); - b2SetBitCountAndClear( &color->bodySet, bodyCapacity ); - } + color->bodySet = b2CreateBitSet( bodyCapacity ); + b2SetBitCountAndClear( &color->bodySet, bodyCapacity ); } } @@ -51,6 +51,10 @@ void b2DestroyGraph( b2ConstraintGraph* graph ) for ( int i = 0; i < b2_graphColorCount; ++i ) { b2GraphColor* color = graph->colors + i; + + // The bit set should never be used on the overflow color + B2_ASSERT( i != b2_overflowIndex || color->bodySet.bits == NULL ); + b2DestroyBitSet( &color->bodySet ); b2DestroyContactArray( &color->contacts ); @@ -220,7 +224,7 @@ static int b2AssignJointColor( b2ConstraintGraph* graph, int bodyIdA, int bodyId #if B2_FORCE_OVERFLOW == 0 if ( staticA == false && staticB == false ) { - for ( int i = 0; i < b2_graphColorCount; ++i ) + for ( int i = 0; i < b2_overflowIndex; ++i ) { b2GraphColor* color = graph->colors + i; if ( b2GetBit( &color->bodySet, bodyIdA ) || b2GetBit( &color->bodySet, bodyIdB ) ) @@ -235,7 +239,7 @@ static int b2AssignJointColor( b2ConstraintGraph* graph, int bodyIdA, int bodyId } else if ( staticA == false ) { - for ( int i = 0; i < b2_graphColorCount; ++i ) + for ( int i = 0; i < b2_overflowIndex; ++i ) { b2GraphColor* color = graph->colors + i; if ( b2GetBit( &color->bodySet, bodyIdA ) ) @@ -249,7 +253,7 @@ static int b2AssignJointColor( b2ConstraintGraph* graph, int bodyIdA, int bodyId } else if ( staticB == false ) { - for ( int i = 0; i < b2_graphColorCount; ++i ) + for ( int i = 0; i < b2_overflowIndex; ++i ) { b2GraphColor* color = graph->colors + i; if ( b2GetBit( &color->bodySet, bodyIdB ) ) diff --git a/src/constraint_graph.h b/src/constraint_graph.h index 158666449..1725ef107 100644 --- a/src/constraint_graph.h +++ b/src/constraint_graph.h @@ -22,8 +22,9 @@ typedef struct b2World b2World; typedef struct b2GraphColor { - // base on bodyId so this is over-sized to encompass static bodies + // This bitset is indexed by bodyId so this is over-sized to encompass static bodies // however I never traverse these bits or use the bit count for anything + // This bitset is unused on the overflow color. b2BitSet bodySet; // cache friendly arrays diff --git a/src/dynamic_tree.c b/src/dynamic_tree.c index c5b69aa67..1f76f4426 100644 --- a/src/dynamic_tree.c +++ b/src/dynamic_tree.c @@ -87,6 +87,7 @@ static int32_t b2AllocateNode( b2DynamicTree* tree ) int32_t oldCapcity = tree->nodeCapacity; tree->nodeCapacity += oldCapcity >> 1; tree->nodes = (b2TreeNode*)b2Alloc( tree->nodeCapacity * sizeof( b2TreeNode ) ); + B2_ASSERT( oldNodes != NULL ); memcpy( tree->nodes, oldNodes, tree->nodeCount * sizeof( b2TreeNode ) ); b2Free( oldNodes, oldCapcity * sizeof( b2TreeNode ) ); diff --git a/src/shape.c b/src/shape.c index 637ec31b5..dea3c2962 100644 --- a/src/shape.c +++ b/src/shape.c @@ -131,7 +131,7 @@ static b2Shape* b2CreateShapeInternal( b2World* world, b2Body* body, b2Transform if ( body->setIndex != b2_disabledSet ) { b2BodyType proxyType = body->type; - b2CreateShapeProxy( shape, &world->broadPhase, proxyType, transform, def->forceContactCreation ); + b2CreateShapeProxy( shape, &world->broadPhase, proxyType, transform, def->forceContactCreation || def->isSensor ); } // Add to shape doubly linked list