Browse Source

check for nullptr dereferencing before copying scene data

Kim Kulling 7 years ago
parent
commit
9707fde709
4 changed files with 97 additions and 74 deletions
  1. 1 1
      code/ColladaExporter.cpp
  2. 83 69
      code/SceneCombiner.cpp
  3. 8 4
      include/assimp/SceneCombiner.h
  4. 5 0
      test/unit/utSceneCombiner.cpp

+ 1 - 1
code/ColladaExporter.cpp

@@ -1280,7 +1280,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
 
 			std::vector<ai_real> frames;
 			for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
-				frames.push_back(nodeAnim->mPositionKeys[i].mTime);
+				frames.push_back(static_cast<ai_real>(nodeAnim->mPositionKeys[i].mTime));
 			}
 			
 			WriteFloatArray( node_idstr , FloatType_Time, (const ai_real*) frames.data(), frames.size());

+ 83 - 69
code/SceneCombiner.cpp

@@ -66,8 +66,8 @@ namespace Assimp {
 
 // ------------------------------------------------------------------------------------------------
 // Add a prefix to a string
-inline void PrefixString(aiString& string,const char* prefix, unsigned int len)
-{
+inline
+void PrefixString(aiString& string,const char* prefix, unsigned int len) {
     // If the string is already prefixed, we won't prefix it a second time
     if (string.length >= 1 && string.data[0] == '$')
         return;
@@ -88,8 +88,7 @@ inline void PrefixString(aiString& string,const char* prefix, unsigned int len)
 
 // ------------------------------------------------------------------------------------------------
 // Add node identifiers to a hashing set
-void SceneCombiner::AddNodeHashes(aiNode* node, std::set<unsigned int>& hashes)
-{
+void SceneCombiner::AddNodeHashes(aiNode* node, std::set<unsigned int>& hashes) {
     // Add node name to hashing set if it is non-empty - empty nodes are allowed
     // and they can't have any anims assigned so its absolutely safe to duplicate them.
     if (node->mName.length) {
@@ -103,8 +102,7 @@ void SceneCombiner::AddNodeHashes(aiNode* node, std::set<unsigned int>& hashes)
 
 // ------------------------------------------------------------------------------------------------
 // Add a name prefix to all nodes in a hierarchy
-void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned int len)
-{
+void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned int len) {
     ai_assert(NULL != prefix);
     PrefixString(node->mName,prefix,len);
 
@@ -115,8 +113,7 @@ void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned i
 
 // ------------------------------------------------------------------------------------------------
 // Search for matching names
-bool SceneCombiner::FindNameMatch(const aiString& name, std::vector<SceneHelper>& input, unsigned int cur)
-{
+bool SceneCombiner::FindNameMatch(const aiString& name, std::vector<SceneHelper>& input, unsigned int cur) {
     const unsigned int hash = SuperFastHash(name.data, static_cast<uint32_t>(name.length));
 
     // Check whether we find a positive match in one of the given sets
@@ -132,8 +129,7 @@ bool SceneCombiner::FindNameMatch(const aiString& name, std::vector<SceneHelper>
 // ------------------------------------------------------------------------------------------------
 // Add a name prefix to all nodes in a hierarchy if a hash match is found
 void SceneCombiner::AddNodePrefixesChecked(aiNode* node, const char* prefix, unsigned int len,
-    std::vector<SceneHelper>& input, unsigned int cur)
-{
+        std::vector<SceneHelper>& input, unsigned int cur) {
     ai_assert(NULL != prefix);
     const unsigned int hash = SuperFastHash(node->mName.data, static_cast<uint32_t>(node->mName.length));
 
@@ -165,9 +161,10 @@ void SceneCombiner::OffsetNodeMeshIndices (aiNode* node, unsigned int offset)
 // ------------------------------------------------------------------------------------------------
 // Merges two scenes. Currently only used by the LWS loader.
 void SceneCombiner::MergeScenes(aiScene** _dest,std::vector<aiScene*>& src,
-    unsigned int flags)
-{
-    ai_assert(NULL != _dest);
+        unsigned int flags) {
+    if ( nullptr == _dest ) {
+        return;
+    }
 
     // if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it
     if (src.empty())
@@ -198,8 +195,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest,std::vector<aiScene*>& src,
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::AttachToGraph (aiNode* attach, std::vector<NodeAttachmentInfo>& srcList)
-{
+void SceneCombiner::AttachToGraph (aiNode* attach, std::vector<NodeAttachmentInfo>& srcList) {
     unsigned int cnt;
     for ( cnt = 0; cnt < attach->mNumChildren; ++cnt ) {
         AttachToGraph( attach->mChildren[ cnt ], srcList );
@@ -239,19 +235,16 @@ void SceneCombiner::AttachToGraph (aiNode* attach, std::vector<NodeAttachmentInf
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::AttachToGraph ( aiScene* master,
-    std::vector<NodeAttachmentInfo>& src)
-{
+void SceneCombiner::AttachToGraph ( aiScene* master, std::vector<NodeAttachmentInfo>& src) {
     ai_assert(NULL != master);
     AttachToGraph(master->mRootNode,src);
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
-    std::vector<AttachmentInfo>& srcList,
-    unsigned int flags)
-{
-    ai_assert(NULL != _dest);
+void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, std::vector<AttachmentInfo>& srcList, unsigned int flags) {
+    if ( nullptr == _dest ) {
+        return;
+    }
 
     // if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it
     if (srcList.empty())    {
@@ -708,7 +701,9 @@ void SceneCombiner::BuildUniqueBoneList(std::list<BoneWithHash>& asBones,
 void SceneCombiner::MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator it,
     std::vector<aiMesh*>::const_iterator end)
 {
-    ai_assert(NULL != out && !out->mNumBones);
+    if ( nullptr == out || out->mNumBones == 0 ) {
+        return;
+    }
 
     // find we need to build an unique list of all bones.
     // we work with hashes to make the comparisons MUCH faster,
@@ -762,7 +757,9 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
     std::vector<aiMesh*>::const_iterator begin,
     std::vector<aiMesh*>::const_iterator end)
 {
-    ai_assert(NULL != _out);
+    if ( nullptr == _out ) {
+        return;
+    }
 
     if (begin == end)   {
         *_out = NULL; // no meshes ...
@@ -903,7 +900,9 @@ void SceneCombiner::MergeMaterials(aiMaterial** dest,
         std::vector<aiMaterial*>::const_iterator begin,
         std::vector<aiMaterial*>::const_iterator end)
 {
-    ai_assert(NULL != dest);
+    if ( nullptr == dest ) {
+        return;
+    }
 
     if (begin == end)   {
         *dest = NULL; // no materials ...
@@ -953,10 +952,9 @@ void SceneCombiner::MergeMaterials(aiMaterial** dest,
 
 // ------------------------------------------------------------------------------------------------
 template <typename Type>
-inline void CopyPtrArray (Type**& dest, const Type* const * src, ai_uint num)
-{
-    if (!num)
-    {
+inline
+void CopyPtrArray (Type**& dest, const Type* const * src, ai_uint num) {
+    if (!num) {
         dest = NULL;
         return;
     }
@@ -968,9 +966,11 @@ inline void CopyPtrArray (Type**& dest, const Type* const * src, ai_uint num)
 
 // ------------------------------------------------------------------------------------------------
 template <typename Type>
-inline void GetArrayCopy (Type*& dest, ai_uint num )
-{
-    if (!dest)return;
+inline
+void GetArrayCopy(Type*& dest, ai_uint num ) {
+    if ( !dest ) {
+        return;
+    }
     Type* old = dest;
 
     dest = new Type[num];
@@ -978,22 +978,27 @@ inline void GetArrayCopy (Type*& dest, ai_uint num )
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::CopySceneFlat(aiScene** _dest,const aiScene* src)
-{
+void SceneCombiner::CopySceneFlat(aiScene** _dest,const aiScene* src) {
+    if ( nullptr == _dest || nullptr == src ) {
+        return;
+    }
+
     // reuse the old scene or allocate a new?
     if (*_dest) {
         (*_dest)->~aiScene();
         new (*_dest) aiScene();
+    } else {
+        *_dest = new aiScene();
     }
-    else *_dest = new aiScene();
 
     ::memcpy(*_dest,src,sizeof(aiScene));
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate)
-{
-    ai_assert(NULL != _dest && NULL != src);
+void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate) {
+    if ( nullptr == _dest || nullptr == src ) {
+        return;
+    }
 
     if (allocate) {
         *_dest = new aiScene();
@@ -1044,9 +1049,10 @@ void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate)
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::Copy     (aiMesh** _dest, const aiMesh* src)
-{
-    ai_assert(NULL != _dest && NULL != src);
+void SceneCombiner::Copy( aiMesh** _dest, const aiMesh* src ) {
+    if ( nullptr == _dest || nullptr == src ) {
+        return;
+    }
 
     aiMesh* dest = *_dest = new aiMesh();
 
@@ -1080,9 +1086,11 @@ void SceneCombiner::Copy     (aiMesh** _dest, const aiMesh* src)
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::Copy (aiMaterial** _dest, const aiMaterial* src)
-{
-    ai_assert(NULL != _dest && NULL != src);
+void SceneCombiner::Copy (aiMaterial** _dest, const aiMaterial* src) {
+    if ( nullptr == _dest || nullptr == src ) {
+        return;
+    }
+
 
     aiMaterial* dest = (aiMaterial*) ( *_dest = new aiMaterial() );
 
@@ -1110,9 +1118,10 @@ void SceneCombiner::Copy (aiMaterial** _dest, const aiMaterial* src)
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::Copy  (aiTexture** _dest, const aiTexture* src)
-{
-    ai_assert(NULL != _dest && NULL != src);
+void SceneCombiner::Copy(aiTexture** _dest, const aiTexture* src) {
+    if ( nullptr == _dest || nullptr == src ) {
+        return;
+    }
 
     aiTexture* dest = *_dest = new aiTexture();
 
@@ -1139,10 +1148,10 @@ void SceneCombiner::Copy  (aiTexture** _dest, const aiTexture* src)
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::Copy( aiAnimation** _dest, const aiAnimation* src )
-{
-    ai_assert( NULL != _dest );
-    ai_assert( NULL != src );
+void SceneCombiner::Copy( aiAnimation** _dest, const aiAnimation* src ) {
+    if ( nullptr == _dest || nullptr == src ) {
+        return;
+    }
 
     aiAnimation* dest = *_dest = new aiAnimation();
 
@@ -1154,9 +1163,10 @@ void SceneCombiner::Copy( aiAnimation** _dest, const aiAnimation* src )
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::Copy     (aiNodeAnim** _dest, const aiNodeAnim* src)
-{
-    ai_assert(NULL != _dest && NULL != src);
+void SceneCombiner::Copy(aiNodeAnim** _dest, const aiNodeAnim* src) {
+    if ( nullptr == _dest || nullptr == src ) {
+        return;
+    }
 
     aiNodeAnim* dest = *_dest = new aiNodeAnim();
 
@@ -1170,9 +1180,10 @@ void SceneCombiner::Copy     (aiNodeAnim** _dest, const aiNodeAnim* src)
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::Copy   (aiCamera** _dest,const  aiCamera* src)
-{
-    ai_assert(NULL != _dest && NULL != src);
+void SceneCombiner::Copy( aiCamera** _dest,const  aiCamera* src) {
+    if ( nullptr == _dest || nullptr == src ) {
+        return;
+    }
 
     aiCamera* dest = *_dest = new aiCamera();
 
@@ -1181,9 +1192,10 @@ void SceneCombiner::Copy   (aiCamera** _dest,const  aiCamera* src)
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::Copy   (aiLight** _dest, const aiLight* src)
-{
-    ai_assert(NULL != _dest && NULL != src);
+void SceneCombiner::Copy(aiLight** _dest, const aiLight* src) {
+    if ( nullptr == _dest || nullptr == src ) {
+        return;
+    }
 
     aiLight* dest = *_dest = new aiLight();
 
@@ -1192,9 +1204,10 @@ void SceneCombiner::Copy   (aiLight** _dest, const aiLight* src)
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::Copy     (aiBone** _dest, const aiBone* src)
-{
-    ai_assert(NULL != _dest && NULL != src);
+void SceneCombiner::Copy(aiBone** _dest, const aiBone* src) {
+    if ( nullptr == _dest || nullptr == src ) {
+        return;
+    }
 
     aiBone* dest = *_dest = new aiBone();
 
@@ -1230,10 +1243,10 @@ void SceneCombiner::Copy     (aiNode** _dest, const aiNode* src)
 }
 
 // ------------------------------------------------------------------------------------------------
-void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src)
-{
-    ai_assert( NULL != _dest );
-    ai_assert( NULL != src);
+void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src) {
+    if ( nullptr == _dest || nullptr == src ) {
+        return;
+    }
 
     aiMetadata* dest = *_dest = aiMetadata::Alloc( src->mNumProperties );
     std::copy(src->mKeys, src->mKeys + src->mNumProperties, dest->mKeys);
@@ -1271,4 +1284,5 @@ void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src)
     }
 }
 
-}
+} // Namespace Assimp
+

+ 8 - 4
include/assimp/SceneCombiner.h

@@ -197,13 +197,17 @@ struct SceneHelper
  * The class is currently being used by various postprocessing steps
  * and loaders (ie. LWS).
  */
-class ASSIMP_API SceneCombiner
-{
+class ASSIMP_API SceneCombiner {
     // class cannot be instanced
-    SceneCombiner() {}
+    SceneCombiner() {
+        // empty
+    }
 
-public:
+    ~SceneCombiner() {
+        // empty
+    }
 
+public:
     // -------------------------------------------------------------------
     /** Merges two or more scenes.
      *

+ 5 - 0
test/unit/utSceneCombiner.cpp

@@ -71,3 +71,8 @@ TEST_F( utSceneCombiner, MergeMeshes_ValidNames_Test ) {
     std::string outName = out->mName.C_Str();
     EXPECT_EQ( "mesh_1.mesh_2.mesh_3", outName );
 }
+
+TEST_F( utSceneCombiner, CopySceneWithNullptr_NoException ) {
+    EXPECT_NO_THROW( SceneCombiner::CopyScene( nullptr, nullptr ) );
+    EXPECT_NO_THROW( SceneCombiner::CopySceneFlat( nullptr, nullptr ) );
+}