diff --git a/code/BaseImporter.cpp b/code/BaseImporter.cpp index a0de9c72e..eab2e3ae9 100644 --- a/code/BaseImporter.cpp +++ b/code/BaseImporter.cpp @@ -328,7 +328,7 @@ void BaseImporter::ConvertToUTF8(std::vector& data) if(*((uint16_t*)&data.front()) == 0xFEFF) { DefaultLogger::get()->debug("Found UTF-16 BOM ..."); - const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)&data.back()+1; + const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1); char* dstart,*dend; std::vector output; do { diff --git a/code/ObjFileData.h b/code/ObjFileData.h index b8248bbf1..e17c307c7 100644 --- a/code/ObjFileData.h +++ b/code/ObjFileData.h @@ -236,9 +236,9 @@ struct Mesh //! \brief Data structure to store all obj-specific model datas struct Model { - typedef std::map* > GroupMap; - typedef std::map* >::iterator GroupMapIt; - typedef std::map* >::const_iterator ConstGroupMapIt; + typedef std::map* > GroupMap; + typedef std::map* >::iterator GroupMapIt; + typedef std::map* >::const_iterator ConstGroupMapIt; //! Model name std::string m_ModelName; diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index 60f8f37f8..43e13825b 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -66,6 +66,8 @@ ObjFileParser::ObjFileParser(std::vector &Data,const std::string &strModel m_uiLine(0), m_pIO( io ) { + memset(m_buffer, BUFFERSIZE, 0); + // Create the model instance to store all the data m_pModel = new ObjFile::Model(); m_pModel->m_ModelName = strModelName; @@ -188,7 +190,7 @@ void ObjFileParser::copyNextWord(char *pBuffer, size_t length) { size_t index = 0; m_DataIt = getNextWord(m_DataIt, m_DataItEnd); - while ( !isSeparator(*m_DataIt) && m_DataIt != m_DataItEnd ) + while ( m_DataIt != m_DataItEnd && !isSeparator(*m_DataIt) ) { pBuffer[index] = *m_DataIt; index++; @@ -262,7 +264,7 @@ void ObjFileParser::getFace() char *pPtr = m_buffer; char *pEnd = &pPtr[BUFFERSIZE]; pPtr = getNextToken(pPtr, pEnd); - if (pPtr == '\0') + if (pPtr == pEnd || *pPtr == '\0') return; std::vector *pIndices = new std::vector; @@ -279,7 +281,7 @@ void ObjFileParser::getFace() if (*pPtr == '\0') break; - if (*pPtr=='\r') + if (*pPtr=='\r' || *pPtr=='\n') break; if (*pPtr=='/' ) @@ -372,7 +374,7 @@ void ObjFileParser::getMaterialDesc() return; char *pStart = &(*m_DataIt); - while ( !isSeparator(*m_DataIt) && m_DataIt != m_DataItEnd ) + while ( m_DataIt != m_DataItEnd && !isSeparator(*m_DataIt) ) ++m_DataIt; // Get name @@ -406,10 +408,9 @@ void ObjFileParser::getMaterialDesc() // Get a comment, values will be skipped void ObjFileParser::getComment() { - bool running = true; - while (running) + while (m_DataIt != m_DataItEnd) { - if ( '\n' == (*m_DataIt) || m_DataIt == m_DataItEnd ) + if ( '\n' == (*m_DataIt)) { ++m_DataIt; break; @@ -431,7 +432,7 @@ void ObjFileParser::getMaterialLib() return; char *pStart = &(*m_DataIt); - while (!isNewLine(*m_DataIt)) + while (m_DataIt != m_DataItEnd && !isNewLine(*m_DataIt)) m_DataIt++; // Check for existence @@ -465,7 +466,7 @@ void ObjFileParser::getNewMaterial() char *pStart = &(*m_DataIt); std::string strMat( pStart, *m_DataIt ); - while ( isSeparator( *m_DataIt ) ) + while ( m_DataIt != m_DataItEnd && isSeparator( *m_DataIt ) ) m_DataIt++; std::map::iterator it = m_pModel->m_MaterialMap.find( strMat ); if ( it == m_pModel->m_MaterialMap.end() ) @@ -516,7 +517,7 @@ void ObjFileParser::getGroupName() // Store groupname in group library char *pStart = &(*m_DataIt); - while ( !isSeparator(*m_DataIt) ) + while ( m_DataIt != m_DataItEnd && !isSeparator(*m_DataIt) ) m_DataIt++; std::string strGroupName(pStart, &(*m_DataIt)); @@ -524,7 +525,7 @@ void ObjFileParser::getGroupName() if ( m_pModel->m_strActiveGroup != strGroupName ) { // Search for already existing entry - ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(&strGroupName); + ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(strGroupName); // We are mapping groups into the object structure createObject( strGroupName ); @@ -533,7 +534,7 @@ void ObjFileParser::getGroupName() if (it == m_pModel->m_Groups.end()) { std::vector *pFaceIDArray = new std::vector; - m_pModel->m_Groups[ &strGroupName ] = pFaceIDArray; + m_pModel->m_Groups[ strGroupName ] = pFaceIDArray; m_pModel->m_pGroupFaceIDs = (pFaceIDArray); } else @@ -563,7 +564,7 @@ void ObjFileParser::getObjectName() if (m_DataIt == m_DataItEnd) return; char *pStart = &(*m_DataIt); - while ( !isSeparator( *m_DataIt ) ) + while ( m_DataIt != m_DataItEnd && !isSeparator( *m_DataIt ) ) ++m_DataIt; std::string strObjectName(pStart, &(*m_DataIt)); diff --git a/code/RemoveRedundantMaterials.cpp b/code/RemoveRedundantMaterials.cpp index 67a05bd6f..33b77667e 100644 --- a/code/RemoveRedundantMaterials.cpp +++ b/code/RemoveRedundantMaterials.cpp @@ -147,7 +147,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) uint32_t me = aiHashes[i] = ((MaterialHelper*)pScene->mMaterials[i])->ComputeHash(); for (unsigned int a = 0; a < i;++a) { - if (me == aiHashes[a]) { + if (abReferenced[a] && me == aiHashes[a]) { ++iCnt; me = 0; aiMappingTable[i] = aiMappingTable[a]; diff --git a/code/SplitByBoneCountProcess.cpp b/code/SplitByBoneCountProcess.cpp index 59ea46183..3c511599c 100644 --- a/code/SplitByBoneCountProcess.cpp +++ b/code/SplitByBoneCountProcess.cpp @@ -47,6 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers of the post-processing framework #include "SplitByBoneCountProcess.h" +#include + using namespace Assimp; // ------------------------------------------------------------------------------------------------ @@ -262,7 +264,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormFaces = new aiFace[subMeshFaces.size()]; size_t nvi = 0; // next vertex index - std::vector previousVertexIndices( numSubMeshVertices, SIZE_MAX); // per new vertex: its index in the source mesh + std::vector previousVertexIndices( numSubMeshVertices, std::numeric_limits::max()); // per new vertex: its index in the source mesh for( size_t a = 0; a < subMeshFaces.size(); ++a ) { const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]]; @@ -306,7 +308,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vectormNumBones = 0; newMesh->mBones = new aiBone*[numBones]; - std::vector mappedBoneIndex( pMesh->mNumBones, SIZE_MAX); + std::vector mappedBoneIndex( pMesh->mNumBones, std::numeric_limits::max()); for( size_t a = 0; a < pMesh->mNumBones; ++a ) { if( !isBoneUsed[a] ) @@ -333,7 +335,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector::max() ) newMesh->mBones[newBoneIndex]->mNumWeights++; } } @@ -359,7 +361,7 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector::max() ); aiVertexWeight* dstWeight = newMesh->mBones[newBoneIndex]->mWeights + newMesh->mBones[newBoneIndex]->mNumWeights; newMesh->mBones[newBoneIndex]->mNumWeights++; diff --git a/code/XFileImporter.cpp b/code/XFileImporter.cpp index 18db52b6d..4c8703ce3 100644 --- a/code/XFileImporter.cpp +++ b/code/XFileImporter.cpp @@ -101,7 +101,7 @@ void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, I mImportedMats.clear(); // in the hope that binary files will never start with a BOM ... - mBuffer.resize( fileSize); + mBuffer.resize( fileSize + 1); file->Read( &mBuffer.front(), 1, fileSize); ConvertToUTF8(mBuffer); diff --git a/code/XFileParser.cpp b/code/XFileParser.cpp index 0a9e23e0a..3fef9781f 100644 --- a/code/XFileParser.cpp +++ b/code/XFileParser.cpp @@ -91,7 +91,7 @@ XFileParser::XFileParser( const std::vector& pBuffer) // set up memory pointers P = &pBuffer.front(); - End = P + pBuffer.size(); + End = P + pBuffer.size() - 1; // check header if( strncmp( P, "xof ", 4) != 0) @@ -180,7 +180,8 @@ XFileParser::XFileParser( const std::vector& pBuffer) // First find out how much storage we'll need. Count sections. const char* P1 = P; unsigned int est_out = 0; - while (P1 < End) + + while (P1 + 3 < End) { // read next offset uint16_t ofs = *((uint16_t*)P1); @@ -199,12 +200,16 @@ XFileParser::XFileParser( const std::vector& pBuffer) // and advance to the next offset P1 += ofs; est_out += MSZIP_BLOCK; // one decompressed block is 32786 in size + + // this block would continue past the file end, abort + if (P1 > End) + throw DeadlyImportError("X: Unexpected end of file while uncompressing"); } - // Allocate storage and do the actual uncompressing - uncompressed.resize(est_out); + // Allocate storage and terminating zero and do the actual uncompressing + uncompressed.resize(est_out + 1); char* out = &uncompressed.front(); - while (P < End) + while (P + 3 < End) { uint16_t ofs = *((uint16_t*)P); AI_SWAP2(ofs); @@ -592,6 +597,9 @@ void XFileParser::ParseDataObjectMeshNormals( Mesh* pMesh) void XFileParser::ParseDataObjectMeshTextureCoords( Mesh* pMesh) { readHeadOfDataObject(); + if( pMesh->mNumTextures + 1 > AI_MAX_NUMBER_OF_TEXTURECOORDS) + ThrowException( "Too many sets of texture coordinates"); + std::vector& coords = pMesh->mTexCoords[pMesh->mNumTextures++]; unsigned int numCoords = ReadInt(); @@ -609,6 +617,8 @@ void XFileParser::ParseDataObjectMeshTextureCoords( Mesh* pMesh) void XFileParser::ParseDataObjectMeshVertexColors( Mesh* pMesh) { readHeadOfDataObject(); + if( pMesh->mNumColorSets + 1 > AI_MAX_NUMBER_OF_COLOR_SETS) + ThrowException( "Too many colorsets"); std::vector& colors = pMesh->mColors[pMesh->mNumColorSets++]; unsigned int numColors = ReadInt(); @@ -659,7 +669,7 @@ void XFileParser::ParseDataObjectMeshMaterialList( Mesh* pMesh) // commented out version check, as version 03.03 exported from blender also has 2 semicolons if( !mIsBinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2) { - if( *P == ';') + if(P < End && *P == ';') ++P; } @@ -1043,6 +1053,7 @@ std::string XFileParser::GetNextToken() // in binary mode it will only return NAME and STRING token // and (correctly) skip over other tokens. + if( End - P < 2) return s; unsigned int tok = ReadBinWord(); unsigned int len; @@ -1051,13 +1062,17 @@ std::string XFileParser::GetNextToken() { case 1: // name token + if( End - P < 4) return s; len = ReadBinDWord(); + if( End - P < len) return s; s = std::string(P, len); P += len; return s; case 2: // string token + if( End - P < 4) return s; len = ReadBinDWord(); + if( End - P < len) return s; s = std::string(P, len); P += (len + 2); return s; @@ -1070,10 +1085,12 @@ std::string XFileParser::GetNextToken() P += 16; return ""; case 6: + if( End - P < 4) return s; len = ReadBinDWord(); P += (len * 4); return ""; case 7: + if( End - P < 4) return s; len = ReadBinDWord(); P += (len * mBinaryFloatSize); return ""; @@ -1227,6 +1244,7 @@ void XFileParser::ReadUntilEndOfLine() // ------------------------------------------------------------------------------------------------ unsigned short XFileParser::ReadBinWord() { + assert(End - P >= 2); const unsigned char* q = (const unsigned char*) P; unsigned short tmp = q[0] | (q[1] << 8); P += 2; @@ -1236,6 +1254,7 @@ unsigned short XFileParser::ReadBinWord() // ------------------------------------------------------------------------------------------------ unsigned int XFileParser::ReadBinDWord() { + assert(End - P >= 4); const unsigned char* q = (const unsigned char*) P; unsigned int tmp = q[0] | (q[1] << 8) | (q[2] << 16) | (q[3] << 24); P += 4; @@ -1247,17 +1266,22 @@ unsigned int XFileParser::ReadInt() { if( mIsBinaryFormat) { - if( mBinaryNumCount == 0) + if( mBinaryNumCount == 0 && End - P >= 2) { unsigned short tmp = ReadBinWord(); // 0x06 or 0x03 - if( tmp == 0x06) // array of ints follows + if( tmp == 0x06 && End - P >= 4) // array of ints follows mBinaryNumCount = ReadBinDWord(); else // single int follows mBinaryNumCount = 1; } --mBinaryNumCount; - return ReadBinDWord(); + if ( End - P >= 4) { + return ReadBinDWord(); + } else { + P = End; + return 0; + } } else { FindNextNoneWhiteSpace(); @@ -1296,10 +1320,10 @@ float XFileParser::ReadFloat() { if( mIsBinaryFormat) { - if( mBinaryNumCount == 0) + if( mBinaryNumCount == 0 && End - P >= 2) { unsigned short tmp = ReadBinWord(); // 0x07 or 0x42 - if( tmp == 0x07) // array of floats following + if( tmp == 0x07 && End - P >= 4) // array of floats following mBinaryNumCount = ReadBinDWord(); else // single float following mBinaryNumCount = 1; @@ -1308,14 +1332,24 @@ float XFileParser::ReadFloat() --mBinaryNumCount; if( mBinaryFloatSize == 8) { - float result = (float) (*(double*) P); - P += 8; - return result; + if( End - P >= 8) { + float result = (float) (*(double*) P); + P += 8; + return result; + } else { + P = End; + return 0; + } } else { - float result = *(float*) P; - P += 4; - return result; + if( End - P >= 4) { + float result = *(float*) P; + P += 4; + return result; + } else { + P = End; + return 0; + } } } @@ -1323,6 +1357,7 @@ float XFileParser::ReadFloat() FindNextNoneWhiteSpace(); // check for various special strings to allow reading files from faulty exporters // I mean you, Blender! + // Reading is safe because of the terminating zero if( strncmp( P, "-1.#IND00", 9) == 0 || strncmp( P, "1.#IND00", 8) == 0) { P += 9; diff --git a/code/XFileParser.h b/code/XFileParser.h index 9f1ec6f33..1564db543 100644 --- a/code/XFileParser.h +++ b/code/XFileParser.h @@ -66,7 +66,7 @@ class XFileParser { public: /** Constructor. Creates a data structure out of the XFile given in the memory block. - * @param pBuffer Memory buffer containing the XFile + * @param pBuffer Null-terminated memory buffer containing the XFile */ XFileParser( const std::vector& pBuffer); diff --git a/include/export.h b/include/export.h index 5670d09d3..35d6735fb 100644 --- a/include/export.h +++ b/include/export.h @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "aiTypes.h" #ifdef __cplusplus +#include extern "C" { #endif