mirror of https://github.com/godotengine/godot
Add protective checks for invalid handle use in BVH
Adds DEV_ASSERTS that will halt at runtime if the BVH is misused with invalid IDs, and adds ERR_FAIL macros to prevent calling with invalid IDs. Any such misuse is a bug in the physics, but this should flag any errors quickly.
This commit is contained in:
parent
cd2e7fbc57
commit
109d08c84a
|
|
@ -196,6 +196,7 @@ public:
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
void move(BVHHandle p_handle, const BOUNDS &p_aabb) {
|
void move(BVHHandle p_handle, const BOUNDS &p_aabb) {
|
||||||
|
DEV_ASSERT(!p_handle.is_invalid());
|
||||||
BVH_LOCKED_FUNCTION
|
BVH_LOCKED_FUNCTION
|
||||||
if (tree.item_move(p_handle, p_aabb)) {
|
if (tree.item_move(p_handle, p_aabb)) {
|
||||||
if (USE_PAIRS) {
|
if (USE_PAIRS) {
|
||||||
|
|
@ -205,10 +206,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void recheck_pairs(BVHHandle p_handle) {
|
void recheck_pairs(BVHHandle p_handle) {
|
||||||
|
DEV_ASSERT(!p_handle.is_invalid());
|
||||||
force_collision_check(p_handle);
|
force_collision_check(p_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void erase(BVHHandle p_handle) {
|
void erase(BVHHandle p_handle) {
|
||||||
|
DEV_ASSERT(!p_handle.is_invalid());
|
||||||
BVH_LOCKED_FUNCTION
|
BVH_LOCKED_FUNCTION
|
||||||
// call unpair and remove all references to the item
|
// call unpair and remove all references to the item
|
||||||
// before deleting from the tree
|
// before deleting from the tree
|
||||||
|
|
@ -225,6 +228,7 @@ public:
|
||||||
// set pairable has never been called.
|
// set pairable has never been called.
|
||||||
// (deferred collision checks are a workaround for visual server for historical reasons)
|
// (deferred collision checks are a workaround for visual server for historical reasons)
|
||||||
void force_collision_check(BVHHandle p_handle) {
|
void force_collision_check(BVHHandle p_handle) {
|
||||||
|
DEV_ASSERT(!p_handle.is_invalid());
|
||||||
BVH_LOCKED_FUNCTION
|
BVH_LOCKED_FUNCTION
|
||||||
if (USE_PAIRS) {
|
if (USE_PAIRS) {
|
||||||
// the aabb should already be up to date in the BVH
|
// the aabb should already be up to date in the BVH
|
||||||
|
|
@ -243,6 +247,7 @@ public:
|
||||||
// but generically this makes items add or remove from the
|
// but generically this makes items add or remove from the
|
||||||
// tree internally, to speed things up by ignoring inactive items
|
// tree internally, to speed things up by ignoring inactive items
|
||||||
bool activate(BVHHandle p_handle, const BOUNDS &p_aabb, bool p_delay_collision_check = false) {
|
bool activate(BVHHandle p_handle, const BOUNDS &p_aabb, bool p_delay_collision_check = false) {
|
||||||
|
DEV_ASSERT(!p_handle.is_invalid());
|
||||||
BVH_LOCKED_FUNCTION
|
BVH_LOCKED_FUNCTION
|
||||||
// sending the aabb here prevents the need for the BVH to maintain
|
// sending the aabb here prevents the need for the BVH to maintain
|
||||||
// a redundant copy of the aabb.
|
// a redundant copy of the aabb.
|
||||||
|
|
@ -267,6 +272,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deactivate(BVHHandle p_handle) {
|
bool deactivate(BVHHandle p_handle) {
|
||||||
|
DEV_ASSERT(!p_handle.is_invalid());
|
||||||
BVH_LOCKED_FUNCTION
|
BVH_LOCKED_FUNCTION
|
||||||
// returns success
|
// returns success
|
||||||
if (tree.item_deactivate(p_handle)) {
|
if (tree.item_deactivate(p_handle)) {
|
||||||
|
|
@ -285,6 +291,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get_active(BVHHandle p_handle) {
|
bool get_active(BVHHandle p_handle) {
|
||||||
|
DEV_ASSERT(!p_handle.is_invalid());
|
||||||
BVH_LOCKED_FUNCTION
|
BVH_LOCKED_FUNCTION
|
||||||
return tree.item_get_active(p_handle);
|
return tree.item_get_active(p_handle);
|
||||||
}
|
}
|
||||||
|
|
@ -307,6 +314,7 @@ public:
|
||||||
|
|
||||||
// prefer calling this directly as type safe
|
// prefer calling this directly as type safe
|
||||||
void set_tree(const BVHHandle &p_handle, uint32_t p_tree_id, uint32_t p_tree_collision_mask, bool p_force_collision_check = true) {
|
void set_tree(const BVHHandle &p_handle, uint32_t p_tree_id, uint32_t p_tree_collision_mask, bool p_force_collision_check = true) {
|
||||||
|
DEV_ASSERT(!p_handle.is_invalid());
|
||||||
BVH_LOCKED_FUNCTION
|
BVH_LOCKED_FUNCTION
|
||||||
// Returns true if the pairing state has changed.
|
// Returns true if the pairing state has changed.
|
||||||
bool state_changed = tree.item_set_tree(p_handle, p_tree_id, p_tree_collision_mask);
|
bool state_changed = tree.item_set_tree(p_handle, p_tree_id, p_tree_collision_mask);
|
||||||
|
|
@ -465,13 +473,6 @@ private:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BVH_CHECKS
|
|
||||||
// if neither are pairable, they should ignore each other
|
|
||||||
// THIS SHOULD NEVER HAPPEN .. now we only test the pairable tree
|
|
||||||
// if the changed item is not pairable
|
|
||||||
CRASH_COND(params.test_pairable_only && !tree._extra[ref_id].pairable);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// checkmasks is already done in the cull routine.
|
// checkmasks is already done in the cull routine.
|
||||||
BVHHandle h_collidee;
|
BVHHandle h_collidee;
|
||||||
h_collidee.set_id(ref_id);
|
h_collidee.set_id(ref_id);
|
||||||
|
|
@ -485,6 +486,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void item_get_AABB(BVHHandle p_handle, BOUNDS &r_aabb) {
|
void item_get_AABB(BVHHandle p_handle, BOUNDS &r_aabb) {
|
||||||
|
DEV_ASSERT(!p_handle.is_invalid());
|
||||||
BVHABB_CLASS abb;
|
BVHABB_CLASS abb;
|
||||||
tree.item_get_ABB(p_handle, abb);
|
tree.item_get_ABB(p_handle, abb);
|
||||||
abb.to(r_aabb);
|
abb.to(r_aabb);
|
||||||
|
|
|
||||||
|
|
@ -60,11 +60,23 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// accessors
|
// accessors
|
||||||
BVHABB_CLASS &get_aabb(uint32_t p_id) { return aabbs[p_id]; }
|
BVHABB_CLASS &get_aabb(uint32_t p_id) {
|
||||||
const BVHABB_CLASS &get_aabb(uint32_t p_id) const { return aabbs[p_id]; }
|
BVH_ASSERT(p_id < MAX_ITEMS);
|
||||||
|
return aabbs[p_id];
|
||||||
|
}
|
||||||
|
const BVHABB_CLASS &get_aabb(uint32_t p_id) const {
|
||||||
|
BVH_ASSERT(p_id < MAX_ITEMS);
|
||||||
|
return aabbs[p_id];
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t &get_item_ref_id(uint32_t p_id) { return item_ref_ids[p_id]; }
|
uint32_t &get_item_ref_id(uint32_t p_id) {
|
||||||
const uint32_t &get_item_ref_id(uint32_t p_id) const { return item_ref_ids[p_id]; }
|
BVH_ASSERT(p_id < MAX_ITEMS);
|
||||||
|
return item_ref_ids[p_id];
|
||||||
|
}
|
||||||
|
const uint32_t &get_item_ref_id(uint32_t p_id) const {
|
||||||
|
BVH_ASSERT(p_id < MAX_ITEMS);
|
||||||
|
return item_ref_ids[p_id];
|
||||||
|
}
|
||||||
|
|
||||||
bool is_dirty() const { return dirty; }
|
bool is_dirty() const { return dirty; }
|
||||||
void set_dirty(bool p) { dirty = p; }
|
void set_dirty(bool p) { dirty = p; }
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
#define BVH_EXPAND_LEAF_AABBS
|
#define BVH_EXPAND_LEAF_AABBS
|
||||||
|
|
||||||
// never do these checks in release
|
// never do these checks in release
|
||||||
#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
|
#ifdef DEV_ENABLED
|
||||||
//#define BVH_VERBOSE
|
//#define BVH_VERBOSE
|
||||||
//#define BVH_VERBOSE_TREE
|
//#define BVH_VERBOSE_TREE
|
||||||
//#define BVH_VERBOSE_PAIRING
|
//#define BVH_VERBOSE_PAIRING
|
||||||
|
|
@ -217,7 +217,7 @@ private:
|
||||||
BVH_ASSERT(!parent.is_leaf());
|
BVH_ASSERT(!parent.is_leaf());
|
||||||
|
|
||||||
int child_num = parent.find_child(p_old_child_id);
|
int child_num = parent.find_child(p_old_child_id);
|
||||||
BVH_ASSERT(child_num != BVHCommon::INVALID);
|
BVH_ASSERT(child_num != -1);
|
||||||
parent.children[child_num] = p_new_child_id;
|
parent.children[child_num] = p_new_child_id;
|
||||||
|
|
||||||
TNode &new_child = _nodes[p_new_child_id];
|
TNode &new_child = _nodes[p_new_child_id];
|
||||||
|
|
@ -229,7 +229,7 @@ private:
|
||||||
BVH_ASSERT(!parent.is_leaf());
|
BVH_ASSERT(!parent.is_leaf());
|
||||||
|
|
||||||
int child_num = parent.find_child(p_child_id);
|
int child_num = parent.find_child(p_child_id);
|
||||||
BVH_ASSERT(child_num != BVHCommon::INVALID);
|
BVH_ASSERT(child_num != -1);
|
||||||
|
|
||||||
parent.remove_child_internal(child_num);
|
parent.remove_child_internal(child_num);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,31 +39,37 @@ GodotBroadPhase2D::ID GodotBroadPhase2DBVH::create(GodotCollisionObject2D *p_obj
|
||||||
}
|
}
|
||||||
|
|
||||||
void GodotBroadPhase2DBVH::move(ID p_id, const Rect2 &p_aabb) {
|
void GodotBroadPhase2DBVH::move(ID p_id, const Rect2 &p_aabb) {
|
||||||
|
ERR_FAIL_COND(!p_id);
|
||||||
bvh.move(p_id - 1, p_aabb);
|
bvh.move(p_id - 1, p_aabb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GodotBroadPhase2DBVH::set_static(ID p_id, bool p_static) {
|
void GodotBroadPhase2DBVH::set_static(ID p_id, bool p_static) {
|
||||||
|
ERR_FAIL_COND(!p_id);
|
||||||
uint32_t tree_id = p_static ? TREE_STATIC : TREE_DYNAMIC;
|
uint32_t tree_id = p_static ? TREE_STATIC : TREE_DYNAMIC;
|
||||||
uint32_t tree_collision_mask = p_static ? TREE_FLAG_DYNAMIC : (TREE_FLAG_STATIC | TREE_FLAG_DYNAMIC);
|
uint32_t tree_collision_mask = p_static ? TREE_FLAG_DYNAMIC : (TREE_FLAG_STATIC | TREE_FLAG_DYNAMIC);
|
||||||
bvh.set_tree(p_id - 1, tree_id, tree_collision_mask, false);
|
bvh.set_tree(p_id - 1, tree_id, tree_collision_mask, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GodotBroadPhase2DBVH::remove(ID p_id) {
|
void GodotBroadPhase2DBVH::remove(ID p_id) {
|
||||||
|
ERR_FAIL_COND(!p_id);
|
||||||
bvh.erase(p_id - 1);
|
bvh.erase(p_id - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
GodotCollisionObject2D *GodotBroadPhase2DBVH::get_object(ID p_id) const {
|
GodotCollisionObject2D *GodotBroadPhase2DBVH::get_object(ID p_id) const {
|
||||||
|
ERR_FAIL_COND_V(!p_id, nullptr);
|
||||||
GodotCollisionObject2D *it = bvh.get(p_id - 1);
|
GodotCollisionObject2D *it = bvh.get(p_id - 1);
|
||||||
ERR_FAIL_COND_V(!it, nullptr);
|
ERR_FAIL_COND_V(!it, nullptr);
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GodotBroadPhase2DBVH::is_static(ID p_id) const {
|
bool GodotBroadPhase2DBVH::is_static(ID p_id) const {
|
||||||
|
ERR_FAIL_COND_V(!p_id, false);
|
||||||
uint32_t tree_id = bvh.get_tree_id(p_id - 1);
|
uint32_t tree_id = bvh.get_tree_id(p_id - 1);
|
||||||
return tree_id == 0;
|
return tree_id == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GodotBroadPhase2DBVH::get_subindex(ID p_id) const {
|
int GodotBroadPhase2DBVH::get_subindex(ID p_id) const {
|
||||||
|
ERR_FAIL_COND_V(!p_id, 0);
|
||||||
return bvh.get_subindex(p_id - 1);
|
return bvh.get_subindex(p_id - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,31 +40,37 @@ GodotBroadPhase3DBVH::ID GodotBroadPhase3DBVH::create(GodotCollisionObject3D *p_
|
||||||
}
|
}
|
||||||
|
|
||||||
void GodotBroadPhase3DBVH::move(ID p_id, const AABB &p_aabb) {
|
void GodotBroadPhase3DBVH::move(ID p_id, const AABB &p_aabb) {
|
||||||
|
ERR_FAIL_COND(!p_id);
|
||||||
bvh.move(p_id - 1, p_aabb);
|
bvh.move(p_id - 1, p_aabb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GodotBroadPhase3DBVH::set_static(ID p_id, bool p_static) {
|
void GodotBroadPhase3DBVH::set_static(ID p_id, bool p_static) {
|
||||||
|
ERR_FAIL_COND(!p_id);
|
||||||
uint32_t tree_id = p_static ? TREE_STATIC : TREE_DYNAMIC;
|
uint32_t tree_id = p_static ? TREE_STATIC : TREE_DYNAMIC;
|
||||||
uint32_t tree_collision_mask = p_static ? TREE_FLAG_DYNAMIC : (TREE_FLAG_STATIC | TREE_FLAG_DYNAMIC);
|
uint32_t tree_collision_mask = p_static ? TREE_FLAG_DYNAMIC : (TREE_FLAG_STATIC | TREE_FLAG_DYNAMIC);
|
||||||
bvh.set_tree(p_id - 1, tree_id, tree_collision_mask, false);
|
bvh.set_tree(p_id - 1, tree_id, tree_collision_mask, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GodotBroadPhase3DBVH::remove(ID p_id) {
|
void GodotBroadPhase3DBVH::remove(ID p_id) {
|
||||||
|
ERR_FAIL_COND(!p_id);
|
||||||
bvh.erase(p_id - 1);
|
bvh.erase(p_id - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
GodotCollisionObject3D *GodotBroadPhase3DBVH::get_object(ID p_id) const {
|
GodotCollisionObject3D *GodotBroadPhase3DBVH::get_object(ID p_id) const {
|
||||||
|
ERR_FAIL_COND_V(!p_id, nullptr);
|
||||||
GodotCollisionObject3D *it = bvh.get(p_id - 1);
|
GodotCollisionObject3D *it = bvh.get(p_id - 1);
|
||||||
ERR_FAIL_COND_V(!it, nullptr);
|
ERR_FAIL_COND_V(!it, nullptr);
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GodotBroadPhase3DBVH::is_static(ID p_id) const {
|
bool GodotBroadPhase3DBVH::is_static(ID p_id) const {
|
||||||
|
ERR_FAIL_COND_V(!p_id, false);
|
||||||
uint32_t tree_id = bvh.get_tree_id(p_id - 1);
|
uint32_t tree_id = bvh.get_tree_id(p_id - 1);
|
||||||
return tree_id == 0;
|
return tree_id == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GodotBroadPhase3DBVH::get_subindex(ID p_id) const {
|
int GodotBroadPhase3DBVH::get_subindex(ID p_id) const {
|
||||||
|
ERR_FAIL_COND_V(!p_id, 0);
|
||||||
return bvh.get_subindex(p_id - 1);
|
return bvh.get_subindex(p_id - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue