From 8abaafab79e3a548b7f15b7bb1646fffa60c68a2 Mon Sep 17 00:00:00 2001 From: paxcut <53811119+paxcut@users.noreply.github.com> Date: Wed, 15 Jan 2025 11:38:38 -0700 Subject: [PATCH] fix: Crash in 3D Visualizer, improved error messages (#2062) The recently added data checks allowed invalid sized vertex arrays to be used as if they were valid making ImHex crash. Moved all the error messages into localization strings for translation. --- plugins/visualizers/romfs/lang/en_US.json | 11 ++++ .../content/pl_visualizers/3d_model.cpp | 64 ++++++++++--------- 2 files changed, 45 insertions(+), 30 deletions(-) diff --git a/plugins/visualizers/romfs/lang/en_US.json b/plugins/visualizers/romfs/lang/en_US.json index d37d6a6fb..9cba99376 100644 --- a/plugins/visualizers/romfs/lang/en_US.json +++ b/plugins/visualizers/romfs/lang/en_US.json @@ -7,6 +7,17 @@ "hex.visualizers.pl_visualizer.3d.light_position": "Light Position", "hex.visualizers.pl_visualizer.3d.ambient_brightness": "Ambient Brightness", "hex.visualizers.pl_visualizer.3d.diffuse_brightness": "Diffuse Brightness", + "hex.visualizers.pl_visualizer.3d.error_message_count": "{} count must be a multiple of {}", + "hex.visualizers.pl_visualizer.3d.error_message_not_empty": "{} can't be empty", + "hex.visualizers.pl_visualizer.3d.error_message_expected": "Expected {} but got {}", + "hex.visualizers.pl_visualizer.3d.error_message_positions": "Positions", + "hex.visualizers.pl_visualizer.3d.error_message_vertex_count": "Error: Vertex count must be a multiple of 3", + "hex.visualizers.pl_visualizer.3d.error_message_colors": "Colors", + "hex.visualizers.pl_visualizer.3d.error_message_normals": "Normals", + "hex.visualizers.pl_visualizer.3d.error_message_uv_coords": "Texture Coordinates", + "hex.visualizers.pl_visualizer.3d.error_message_index_count": "Error: Index count must be a multiple of 3", + "hex.visualizers.pl_visualizer.3d.error_message_invalid_indices": "Error: Indices must be between 0 and the number of vertices minus one. Invalid indices: ", + "hex.visualizers.pl_visualizer.3d.error_message_for_vertex_count": " for {} vertices", "hex.visualizers.pl_visualizer.3d.specular_brightness": "Specular Brightness", "hex.visualizers.pl_visualizer.3d.object_reflectiveness": "Object Reflectiveness", "hex.visualizers.pl_visualizer.3d.light_color": "Light Color", diff --git a/plugins/visualizers/source/content/pl_visualizers/3d_model.cpp b/plugins/visualizers/source/content/pl_visualizers/3d_model.cpp index 807a7d67d..8d1376b44 100644 --- a/plugins/visualizers/source/content/pl_visualizers/3d_model.cpp +++ b/plugins/visualizers/source/content/pl_visualizers/3d_model.cpp @@ -19,7 +19,6 @@ #include #include -#include namespace hex::plugin::visualizers { @@ -345,16 +344,16 @@ namespace hex::plugin::visualizers { bool validateVector(const std::vector &vector, u32 vertexCount, u32 divisor, const std::string &name,std::string &errorMessage) { if (!vector.empty()) { if (vector.size() % divisor != 0) { - errorMessage = name + " must be a multiple of " + std::to_string(divisor); + errorMessage = hex::format("hex.visualizers.pl_visualizer.3d.error_message_count"_lang, name , std::to_string(divisor)); return false; } } else { - errorMessage = name + " can't be empty"; + errorMessage = hex::format("hex.visualizers.pl_visualizer.3d.error_message_not_empty"_lang, name); return false; } auto vectorCount = vector.size()/divisor; if (vectorCount != vertexCount) { - errorMessage = hex::format("Expected {} colors, got {}", vertexCount, vectorCount); + errorMessage = hex::format("hex.visualizers.pl_visualizer.3d.error_message_expected"_lang, std::to_string(vertexCount), std::to_string(vectorCount)); return false; } return true; @@ -375,27 +374,26 @@ namespace hex::plugin::visualizers { if (indexType != IndexType::Undefined && !vectors.indices.empty()) buffers.indices = gl::Buffer(gl::BufferType::Index, vectors.indices); - if (validateVector(vectors.vertices, vertexCount, 3, "Positions", errorMessage)) { - if ((indexType == IndexType::Undefined || vectors.indices.empty()) && vertexCount % 3 != 0) { - throw std::runtime_error("Error: Vertex count must be a multiple of 3"); - } else - buffers.vertices = gl::Buffer(gl::BufferType::Vertex, vectors.vertices); - } else { - throw std::runtime_error(errorMessage); - } - if (validateVector(vectors.colors, vertexCount, 4, "Colors", errorMessage)) + if ((indexType == IndexType::Undefined || vectors.indices.empty()) && vertexCount % 3 != 0) { + throw std::runtime_error(std::string("hex.visualizers.pl_visualizer.3d.error_message_vertex_count"_lang)); + } else + buffers.vertices = gl::Buffer(gl::BufferType::Vertex, vectors.vertices); + + + if (validateVector(vectors.colors, vertexCount, 4, std::string("hex.visualizers.pl_visualizer.3d.error_message_colors"_lang), errorMessage)) buffers.colors = gl::Buffer(gl::BufferType::Vertex, vectors.colors); else { throw std::runtime_error(errorMessage); } - if (validateVector(vectors.normals, vertexCount, 3, "Normals", errorMessage)) + + if (validateVector(vectors.normals, vertexCount, 3, std::string("hex.visualizers.pl_visualizer.3d.error_message_normals"_lang), errorMessage)) buffers.normals = gl::Buffer(gl::BufferType::Vertex, vectors.normals); else { throw std::runtime_error(errorMessage); } - if (validateVector(vectors.uv, vertexCount, 2, "UV coordinates", errorMessage)) + if (validateVector(vectors.uv, vertexCount, 2, std::string("hex.visualizers.pl_visualizer.3d.error_message_uv_coords"_lang), errorMessage)) buffers.uv = gl::Buffer(gl::BufferType::Vertex, vectors.uv); else { throw std::runtime_error(errorMessage); @@ -430,19 +428,17 @@ namespace hex::plugin::visualizers { if (indexType != IndexType::Undefined) lineBuffers.indices = gl::Buffer(gl::BufferType::Index, lineVectors.indices); - if (validateVector(lineVectors.vertices, vertexCount, 3, "Positions", errorMessage)) { - if ((indexType == IndexType::Undefined || lineVectors.indices.empty()) && vertexCount % 3 != 0) { - throw std::runtime_error("Error: Vertex count must be a multiple of 3"); - } else - lineBuffers.vertices = gl::Buffer(gl::BufferType::Vertex, lineVectors.vertices); - } else { - throw std::runtime_error(errorMessage); - } - if (validateVector(lineVectors.colors, vertexCount, 4, "Colors", errorMessage)) + if ((indexType == IndexType::Undefined || lineVectors.indices.empty()) && vertexCount % 3 != 0) { + throw std::runtime_error(std::string("hex.visualizers.pl_visualizer.3d.error_message_vertex_count"_lang)); + } else + lineBuffers.vertices = gl::Buffer(gl::BufferType::Vertex, lineVectors.vertices); + + if (validateVector(lineVectors.colors, vertexCount, 4, std::string("hex.visualizers.pl_visualizer.3d.error_message_colors"_lang), errorMessage)) lineBuffers.colors = gl::Buffer(gl::BufferType::Vertex, lineVectors.colors); else { throw std::runtime_error(errorMessage); } + vertexArray.addBuffer(0, lineBuffers.vertices); vertexArray.addBuffer(1, lineBuffers.colors, 4); @@ -645,22 +641,26 @@ namespace hex::plugin::visualizers { Vectors vectors; vectors.vertices = patternToArray(verticesPattern.get()); + std::string errorMessage; s_vertexCount = vectors.vertices.size() / 3; + if (!validateVector(vectors.vertices, s_vertexCount, 3, std::string("hex.visualizers.pl_visualizer.3d.error_message_positions"_lang), errorMessage)) + throw std::runtime_error(errorMessage); + if (s_indexType != IndexType::Undefined) { vectors.indices = patternToArray(indicesPattern.get()); s_badIndices.clear(); auto indexCount = vectors.indices.size(); if (indexCount < 3 || indexCount % 3 != 0) { - throw std::runtime_error("Error: IndexCount must be a multiple of 3"); + throw std::runtime_error(std::string("hex.visualizers.pl_visualizer.3d.error_message_index_count"_lang)); } auto booleans = std::views::transform(vectors.indices,isIndexInRange); if (!std::accumulate(std::begin(booleans), std::end(booleans), true, std::logical_and<>())) { - std::string errorMessage = "Error: indices must be between 0 and the number of vertices minus one. Invalid indices: "; + errorMessage = std::string("hex.visualizers.pl_visualizer.3d.error_message_invalid_indices"_lang); for (auto badIndex : s_badIndices) errorMessage += std::to_string(badIndex) + ", "; errorMessage.pop_back(); errorMessage.pop_back(); - errorMessage += hex::format(" for {} vertices",s_vertexCount); + errorMessage += hex::format(std::string("hex.visualizers.pl_visualizer.3d.error_message_for_vertex_count"_lang),s_vertexCount); throw std::runtime_error(errorMessage); } } @@ -677,23 +677,27 @@ namespace hex::plugin::visualizers { bindBuffers(buffers, vertexArray, vectors, s_indexType); } else { LineVectors lineVectors; + std::string errorMessage; lineVectors.vertices = patternToArray(verticesPattern.get()); s_vertexCount = lineVectors.vertices.size() / 3; + if (!validateVector(lineVectors.vertices, s_vertexCount, 3, std::string("hex.visualizers.pl_visualizer.3d.error_message_positions"_lang), errorMessage)) + throw std::runtime_error(errorMessage); + if (s_indexType != IndexType::Undefined) { lineVectors.indices = patternToArray(indicesPattern.get()); auto indexCount = lineVectors.indices.size(); if (indexCount < 3 || indexCount % 3 != 0) { - throw std::runtime_error("Error: IndexCount must be a multiple of 3"); + throw std::runtime_error(std::string("hex.visualizers.pl_visualizer.3d.error_message_index_count"_lang)); } s_badIndices.clear(); if (!std::ranges::all_of(lineVectors.indices,isIndexInRange)) { - std::string errorMessage = "Error: indices must be between 0 and the number of vertices minus one. Invalid indices: "; + errorMessage = std::string("hex.visualizers.pl_visualizer.3d.error_message_invalid_indices"_lang); for (auto badIndex : s_badIndices) errorMessage += std::to_string(badIndex) + ", "; errorMessage.pop_back(); errorMessage.pop_back(); - errorMessage += hex::format(" for {} vertices",s_vertexCount); + errorMessage += hex::format(std::string("hex.visualizers.pl_visualizer.3d.error_message_for_vertex_count"_lang),s_vertexCount); throw std::runtime_error(errorMessage); } }