Fix out-of-range access cause of aiProcess_GenNormals : array size inconsistency of members of mesh after process (#6332)

* Fix aiProcess_GenNormals process: copy members of mesh corresponding with additional vertices

* Fix aiProcess_GenNormals process: Refoctoring

* refactoring: fix SonarQube Issue

* Update GenFaceNormalsProcess.cpp: fix small findings

---------

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
This commit is contained in:
sSsA01
2025-11-02 05:15:17 +09:00
committed by GitHub
parent ea249be466
commit 8e35cb1a9f

View File

@@ -51,6 +51,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <numeric>
#include <memory>
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
@@ -86,6 +89,64 @@ void GenFaceNormalsProcess::Execute(aiScene *pScene) {
}
}
namespace {
template<class XMesh>
void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
// replace vertex data with the unique data sets
pMesh->mNumVertices = static_cast<unsigned int>(uniqueVertices.size());
// ----------------------------------------------------------------------------
// NOTE - we're *not* calling Vertex::SortBack() because it would check for
// presence of every single vertex component once PER VERTEX. And our CPU
// dislikes branches, even if they're easily predictable.
// ----------------------------------------------------------------------------
// Position, if present (check made for aiAnimMesh)
if (pMesh->mVertices) {
std::unique_ptr<aiVector3D[]> oldVertices(pMesh->mVertices);
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
pMesh->mVertices[a] = oldVertices[uniqueVertices[a]];
}
}
// Tangents, if present
if (pMesh->mTangents) {
std::unique_ptr<aiVector3D[]> oldTangents(pMesh->mTangents);
pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
pMesh->mTangents[a] = oldTangents[uniqueVertices[a]];
}
}
// Bitangents as well
if (pMesh->mBitangents) {
std::unique_ptr<aiVector3D[]> oldBitangents(pMesh->mBitangents);
pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
pMesh->mBitangents[a] = oldBitangents[uniqueVertices[a]];
}
}
// Vertex colors
for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) {
std::unique_ptr<aiColor4D[]> oldColors(pMesh->mColors[a]);
pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
for (unsigned int b = 0; b < pMesh->mNumVertices; b++) {
pMesh->mColors[a][b] = oldColors[uniqueVertices[b]];
}
}
// Texture coords
for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) {
std::unique_ptr<aiVector3D[]> oldTextureCoords(pMesh->mTextureCoords[a]);
pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
for (unsigned int b = 0; b < pMesh->mNumVertices; b++) {
pMesh->mTextureCoords[a][b] = oldTextureCoords[uniqueVertices[b]];
}
}
}
} // namespace
// ------------------------------------------------------------------------------------------------
// Executes the post-processing step on the given imported data.
bool GenFaceNormalsProcess::GenMeshFaceNormals(aiMesh *pMesh) {
@@ -112,17 +173,21 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals(aiMesh *pMesh) {
// mask to indicate if a vertex was already referenced and needs to be duplicated
std::vector<bool> alreadyReferenced;
alreadyReferenced.resize(pMesh->mNumVertices, false);
std::vector<aiVector3D> duplicatedVertices;
std::vector<int> duplicatedVertices;
duplicatedVertices.resize(pMesh->mNumVertices);
std::iota(std::begin(duplicatedVertices), std::end(duplicatedVertices), 0);
auto storeNormalSplitVertex = [&](unsigned int index, const aiVector3D& normal) {
if (!alreadyReferenced[index]) {
normals[index] = normal;
alreadyReferenced[index] = true;
} else {
duplicatedVertices.push_back(pMesh->mVertices[index]);
normals.push_back(normal);
index = pMesh->mNumVertices + static_cast<unsigned int>(duplicatedVertices.size() - 1);
duplicatedVertices.push_back(index);
index = static_cast<unsigned int>(duplicatedVertices.size() - 1);
}
return index;
};
@@ -154,16 +219,10 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals(aiMesh *pMesh) {
}
// store normals (and additional vertices) back into the mesh
if (!duplicatedVertices.empty()) {
const aiVector3D * oldVertices = pMesh->mVertices;
auto oldNumVertices = pMesh->mNumVertices;
pMesh->mNumVertices += static_cast<unsigned int>(duplicatedVertices.size());
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
memcpy(pMesh->mVertices, oldVertices, oldNumVertices * sizeof(aiVector3D));
memcpy(pMesh->mVertices + oldNumVertices, duplicatedVertices.data(), duplicatedVertices.size() * sizeof(aiVector3D));
delete[] oldVertices;
if (pMesh->mNumVertices != std::size(duplicatedVertices)) {
updateXMeshVertices(pMesh, duplicatedVertices);
}
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
pMesh->mNormals = new aiVector3D[normals.size()];
memcpy(pMesh->mNormals, normals.data(), normals.size() * sizeof(aiVector3D));
return true;