Fixed memory leak in MDLLoader.cpp

If one of the MDL importer implementations throw an exception, the memory allocated at mBuffer may never be freed. This fix should prevent further memory leaks.
pull/2927/head
Marc-Antoine Lortie 2020-01-18 14:58:19 -05:00
parent e0571329e7
commit 247667233d
1 changed files with 89 additions and 78 deletions

View File

@ -184,88 +184,99 @@ void MDLImporter::InternReadFile( const std::string& pFile,
if( iFileSize < sizeof(MDL::HalfLife::SequenceHeader_HL1)) { if( iFileSize < sizeof(MDL::HalfLife::SequenceHeader_HL1)) {
throw DeadlyImportError( "MDL File is too small."); throw DeadlyImportError( "MDL File is too small.");
} }
// Allocate storage and copy the contents of the file to a memory buffer // delete the file buffer and cleanup.
mBuffer =new unsigned char[iFileSize+1]; auto DeleteBufferAndCleanup = [&]() {
file->Read( (void*)mBuffer, 1, iFileSize); if (mBuffer) {
delete mBuffer;
// Append a binary zero to the end of the buffer. mBuffer = nullptr;
// this is just for safety that string parsing routines
// find the end of the buffer ...
mBuffer[iFileSize] = '\0';
const uint32_t iMagicWord = *((uint32_t*)mBuffer);
// Determine the file subtype and call the appropriate member function
// Original Quake1 format
if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || AI_MDL_MAGIC_NUMBER_LE == iMagicWord) {
ASSIMP_LOG_DEBUG("MDL subtype: Quake 1, magic word is IDPO");
iGSFileVersion = 0;
InternReadFile_Quake1();
}
// GameStudio A<old> MDL2 format - used by some test models that come with 3DGS
else if (AI_MDL_MAGIC_NUMBER_BE_GS3 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS3 == iMagicWord) {
ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A2, magic word is MDL2");
iGSFileVersion = 2;
InternReadFile_Quake1();
}
// GameStudio A4 MDL3 format
else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS4 == iMagicWord) {
ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A4, magic word is MDL3");
iGSFileVersion = 3;
InternReadFile_3DGS_MDL345();
}
// GameStudio A5+ MDL4 format
else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5a == iMagicWord) {
ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A4, magic word is MDL4");
iGSFileVersion = 4;
InternReadFile_3DGS_MDL345();
}
// GameStudio A5+ MDL5 format
else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5b == iMagicWord) {
ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A5, magic word is MDL5");
iGSFileVersion = 5;
InternReadFile_3DGS_MDL345();
}
// GameStudio A7 MDL7 format
else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS7 == iMagicWord) {
ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A7, magic word is MDL7");
iGSFileVersion = 7;
InternReadFile_3DGS_MDL7();
}
// IDST/IDSQ Format (CS:S/HL^2, etc ...)
else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord ||
AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord)
{
iGSFileVersion = 0;
HalfLife::HalfLifeMDLBaseHeader *pHeader = (HalfLife::HalfLifeMDLBaseHeader *)mBuffer;
if (pHeader->version == AI_MDL_HL1_VERSION)
{
ASSIMP_LOG_DEBUG("MDL subtype: Half-Life 1/Goldsrc Engine, magic word is IDST/IDSQ");
InternReadFile_HL1(pFile, iMagicWord);
} }
else AI_DEBUG_INVALIDATE_PTR(pIOHandler);
{ AI_DEBUG_INVALIDATE_PTR(pScene);
ASSIMP_LOG_DEBUG("MDL subtype: Source(tm) Engine, magic word is IDST/IDSQ"); };
InternReadFile_HL2();
try {
// Allocate storage and copy the contents of the file to a memory buffer
mBuffer = new unsigned char[iFileSize+1];
file->Read( (void*)mBuffer, 1, iFileSize);
// Append a binary zero to the end of the buffer.
// this is just for safety that string parsing routines
// find the end of the buffer ...
mBuffer[iFileSize] = '\0';
const uint32_t iMagicWord = *((uint32_t*)mBuffer);
// Determine the file subtype and call the appropriate member function
// Original Quake1 format
if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || AI_MDL_MAGIC_NUMBER_LE == iMagicWord) {
ASSIMP_LOG_DEBUG("MDL subtype: Quake 1, magic word is IDPO");
iGSFileVersion = 0;
InternReadFile_Quake1();
} }
} // GameStudio A<old> MDL2 format - used by some test models that come with 3DGS
else { else if (AI_MDL_MAGIC_NUMBER_BE_GS3 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS3 == iMagicWord) {
// print the magic word to the log file ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A2, magic word is MDL2");
throw DeadlyImportError( "Unknown MDL subformat " + pFile + iGSFileVersion = 2;
". Magic word (" + std::string((char*)&iMagicWord,4) + ") is not known"); InternReadFile_Quake1();
} }
// GameStudio A4 MDL3 format
else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS4 == iMagicWord) {
ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A4, magic word is MDL3");
iGSFileVersion = 3;
InternReadFile_3DGS_MDL345();
}
// GameStudio A5+ MDL4 format
else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5a == iMagicWord) {
ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A4, magic word is MDL4");
iGSFileVersion = 4;
InternReadFile_3DGS_MDL345();
}
// GameStudio A5+ MDL5 format
else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS5b == iMagicWord) {
ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A5, magic word is MDL5");
iGSFileVersion = 5;
InternReadFile_3DGS_MDL345();
}
// GameStudio A7 MDL7 format
else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_GS7 == iMagicWord) {
ASSIMP_LOG_DEBUG("MDL subtype: 3D GameStudio A7, magic word is MDL7");
iGSFileVersion = 7;
InternReadFile_3DGS_MDL7();
}
// IDST/IDSQ Format (CS:S/HL^2, etc ...)
else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord ||
AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord)
{
iGSFileVersion = 0;
// Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system HalfLife::HalfLifeMDLBaseHeader *pHeader = (HalfLife::HalfLifeMDLBaseHeader *)mBuffer;
pScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, if (pHeader->version == AI_MDL_HL1_VERSION)
0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f); {
ASSIMP_LOG_DEBUG("MDL subtype: Half-Life 1/Goldsrc Engine, magic word is IDST/IDSQ");
InternReadFile_HL1(pFile, iMagicWord);
}
else
{
ASSIMP_LOG_DEBUG("MDL subtype: Source(tm) Engine, magic word is IDST/IDSQ");
InternReadFile_HL2();
}
}
else {
// print the magic word to the log file
throw DeadlyImportError( "Unknown MDL subformat " + pFile +
". Magic word (" + std::string((char*)&iMagicWord,4) + ") is not known");
}
// delete the file buffer and cleanup // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
delete [] mBuffer; pScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f,
mBuffer= nullptr; 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f);
AI_DEBUG_INVALIDATE_PTR(pIOHandler);
AI_DEBUG_INVALIDATE_PTR(pScene); DeleteBufferAndCleanup();
} catch(...) {
DeleteBufferAndCleanup();
throw;
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------