1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-01 04:39:44 +00:00

Limit navmesh vertices coordinates values

Float values with more than 22 significant fraction bits may cause out of bounds
access in recastnavigation on triangles rasterization. Prevent passing such
values there.
This commit is contained in:
elsid 2024-01-30 23:59:58 +01:00
parent 2114f84939
commit e6196c782d
No known key found for this signature in database
GPG key ID: 4DE04C198CBA7625
3 changed files with 27 additions and 4 deletions

View file

@ -37,6 +37,7 @@
Bug #6402: The sound of a thunderstorm does not stop playing after entering the premises Bug #6402: The sound of a thunderstorm does not stop playing after entering the premises
Bug #6427: Enemy health bar disappears before damaging effect ends Bug #6427: Enemy health bar disappears before damaging effect ends
Bug #6550: Cloned body parts don't inherit texture effects Bug #6550: Cloned body parts don't inherit texture effects
Bug #6574: Crash at far away from world origin coordinates
Bug #6645: Enemy block sounds align with animation instead of blocked hits Bug #6645: Enemy block sounds align with animation instead of blocked hits
Bug #6657: Distant terrain tiles become black when using FWIW mod Bug #6657: Distant terrain tiles become black when using FWIW mod
Bug #6661: Saved games that have no preview screenshot cause issues or crashes Bug #6661: Saved games that have no preview screenshot cause issues or crashes

View file

@ -871,7 +871,7 @@ namespace
TEST_F(DetourNavigatorNavigatorTest, update_for_very_big_object_should_be_limited) TEST_F(DetourNavigatorNavigatorTest, update_for_very_big_object_should_be_limited)
{ {
const float size = static_cast<float>(2 * static_cast<std::int64_t>(std::numeric_limits<int>::max()) - 1); const float size = static_cast<float>((1 << 22) - 1);
CollisionShapeInstance bigBox(std::make_unique<btBoxShape>(btVector3(size, size, 1))); CollisionShapeInstance bigBox(std::make_unique<btBoxShape>(btVector3(size, size, 1)));
const ObjectTransform objectTransform{ const ObjectTransform objectTransform{
.mPosition = ESM::Position{ .pos = { 0, 0, 0 }, .rot{ 0, 0, 0 } }, .mPosition = ESM::Position{ .pos = { 0, 0, 0 }, .rot{ 0, 0, 0 } },

View file

@ -186,16 +186,35 @@ namespace DetourNavigator
&context, solid, width, height, bmin.ptr(), bmax.ptr(), settings.mCellSize, settings.mCellHeight); &context, solid, width, height, bmin.ptr(), bmax.ptr(), settings.mCellSize, settings.mCellHeight);
} }
bool isSupportedCoordinate(float value)
{
constexpr float maxVertexCoordinate = static_cast<float>(1 << 22);
return -maxVertexCoordinate < value && value < maxVertexCoordinate;
}
template <class Iterator>
bool isSupportedCoordinates(Iterator begin, Iterator end)
{
return std::all_of(begin, end, isSupportedCoordinate);
}
[[nodiscard]] bool rasterizeTriangles(RecastContext& context, const Mesh& mesh, const RecastSettings& settings, [[nodiscard]] bool rasterizeTriangles(RecastContext& context, const Mesh& mesh, const RecastSettings& settings,
const RecastParams& params, rcHeightfield& solid) const RecastParams& params, rcHeightfield& solid)
{ {
std::vector<unsigned char> areas(mesh.getAreaTypes().begin(), mesh.getAreaTypes().end()); std::vector<unsigned char> areas(mesh.getAreaTypes().begin(), mesh.getAreaTypes().end());
std::vector<float> vertices = mesh.getVertices(); std::vector<float> vertices = mesh.getVertices();
for (std::size_t i = 0; i < vertices.size(); i += 3) constexpr std::size_t verticesPerTriangle = 3;
for (std::size_t i = 0; i < vertices.size(); i += verticesPerTriangle)
{ {
for (std::size_t j = 0; j < 3; ++j) for (std::size_t j = 0; j < verticesPerTriangle; ++j)
vertices[i + j] = toNavMeshCoordinates(settings, vertices[i + j]); {
const float coordinate = toNavMeshCoordinates(settings, vertices[i + j]);
if (!isSupportedCoordinate(coordinate))
return false;
vertices[i + j] = coordinate;
}
std::swap(vertices[i + 1], vertices[i + 2]); std::swap(vertices[i + 1], vertices[i + 2]);
} }
@ -217,6 +236,9 @@ namespace DetourNavigator
rectangle.mBounds.mMax.x(), rectangle.mHeight, rectangle.mBounds.mMin.y(), // vertex 3 rectangle.mBounds.mMax.x(), rectangle.mHeight, rectangle.mBounds.mMin.y(), // vertex 3
}; };
if (!isSupportedCoordinates(vertices.begin(), vertices.end()))
return false;
const std::array indices{ const std::array indices{
0, 1, 2, // triangle 0 0, 1, 2, // triangle 0
0, 2, 3, // triangle 1 0, 2, 3, // triangle 1