Переглянути джерело

Verify GLTF indices to prevent crash with corrupt files

Also verify prior to vertex optimization.
lawnjelly 1 рік тому
батько
коміт
3771078c02

+ 14 - 0
core/math/geometry.cpp

@@ -1549,3 +1549,17 @@ void Geometry::sort_polygon_winding(Vector<Vector2> &r_verts, bool p_clockwise)
 		r_verts.invert();
 	}
 }
+
+bool Geometry::verify_indices(const int *p_indices, int p_num_indices, int p_num_vertices) {
+	ERR_FAIL_NULL_V(p_indices, false);
+	ERR_FAIL_COND_V(p_num_indices < 0, false);
+	ERR_FAIL_COND_V(p_num_vertices < 0, false);
+
+	for (int n = 0; n < p_num_indices; n++) {
+		if ((unsigned int)p_indices[n] >= (unsigned int)p_num_vertices) {
+			return false;
+		}
+	}
+
+	return true;
+}

+ 1 - 0
core/math/geometry.h

@@ -1020,6 +1020,7 @@ public:
 	static Vector<Vector3> compute_convex_mesh_points(const Plane *p_planes, int p_plane_count, real_t p_epsilon = CMP_EPSILON);
 	static bool convex_hull_intersects_convex_hull(const Plane *p_planes_a, int p_plane_count_a, const Plane *p_planes_b, int p_plane_count_b);
 	static real_t calculate_convex_hull_volume(const Geometry::MeshData &p_md);
+	static bool verify_indices(const int *p_indices, int p_num_indices, int p_num_vertices);
 
 private:
 	static Vector<Vector<Point2>> _polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open = false);

+ 4 - 0
core/math/vertex_cache_optimizer.cpp

@@ -30,6 +30,7 @@
 
 #include "vertex_cache_optimizer.h"
 
+#include "core/math/geometry.h"
 #include "core/math/math_funcs.h"
 
 // Precalculate the tables.
@@ -287,6 +288,9 @@ bool VertexCacheOptimizer::reorder_indices_pool(PoolVector<int> &r_indices, uint
 }
 
 bool VertexCacheOptimizer::reorder_indices(LocalVector<int> &r_indices, uint32_t p_num_triangles, uint32_t p_num_verts) {
+	// If the mesh contains invalid indices, abort.
+	ERR_FAIL_COND_V(!Geometry::verify_indices(r_indices.ptr(), r_indices.size(), p_num_verts), false);
+
 	LocalVector<int> temp;
 	temp.resize(r_indices.size());
 	if (_reorder_indices((VERTEX_INDEX_TYPE *)temp.ptr(), (VERTEX_INDEX_TYPE *)r_indices.ptr(), p_num_triangles, p_num_verts)) {

+ 14 - 0
modules/gltf/gltf_document.cpp

@@ -2936,6 +2936,20 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
 				mat = mat3d;
 			}
 			int32_t mat_idx = import_mesh->get_surface_count();
+
+			// Check for invalid indices.
+			if (array[Mesh::ARRAY_INDEX] && array[Mesh::ARRAY_INDEX] != Variant()) {
+				const Vector<int> &inds = array[Mesh::ARRAY_INDEX];
+
+				if (array[Mesh::ARRAY_VERTEX] && array[Mesh::ARRAY_VERTEX] != Variant()) {
+					const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX];
+					int num_verts = vertices.size();
+
+					// The mesh contains invalid indices, abort.
+					ERR_FAIL_COND_V(!Geometry::verify_indices(inds.ptr(), inds.size(), num_verts), ERR_FILE_CORRUPT);
+				}
+			}
+
 			import_mesh->add_surface_from_arrays(primitive, array, morphs, p_state->compress_flags);
 			import_mesh->surface_set_material(mat_idx, mat);
 		}