check for nullptr dereferencing before copying scene data

pull/1580/head
Kim Kulling 2017-11-19 17:41:31 +01:00
parent b408e25a1d
commit 9707fde709
4 changed files with 97 additions and 74 deletions

View File

@ -1280,7 +1280,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
std::vector<ai_real> frames; std::vector<ai_real> frames;
for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) { 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()); WriteFloatArray( node_idstr , FloatType_Time, (const ai_real*) frames.data(), frames.size());

View File

@ -66,8 +66,8 @@ namespace Assimp {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Add a prefix to a string // 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 the string is already prefixed, we won't prefix it a second time
if (string.length >= 1 && string.data[0] == '$') if (string.length >= 1 && string.data[0] == '$')
return; return;
@ -88,8 +88,7 @@ inline void PrefixString(aiString& string,const char* prefix, unsigned int len)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Add node identifiers to a hashing set // 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 // 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. // and they can't have any anims assigned so its absolutely safe to duplicate them.
if (node->mName.length) { 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 // 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); ai_assert(NULL != prefix);
PrefixString(node->mName,prefix,len); PrefixString(node->mName,prefix,len);
@ -115,8 +113,7 @@ void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned i
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Search for matching names // 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)); 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 // 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 // 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, 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); ai_assert(NULL != prefix);
const unsigned int hash = SuperFastHash(node->mName.data, static_cast<uint32_t>(node->mName.length)); 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. // Merges two scenes. Currently only used by the LWS loader.
void SceneCombiner::MergeScenes(aiScene** _dest,std::vector<aiScene*>& src, void SceneCombiner::MergeScenes(aiScene** _dest,std::vector<aiScene*>& src,
unsigned int flags) unsigned int flags) {
{ if ( nullptr == _dest ) {
ai_assert(NULL != _dest); return;
}
// if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it // if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it
if (src.empty()) 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; unsigned int cnt;
for ( cnt = 0; cnt < attach->mNumChildren; ++cnt ) { for ( cnt = 0; cnt < attach->mNumChildren; ++cnt ) {
AttachToGraph( attach->mChildren[ cnt ], srcList ); AttachToGraph( attach->mChildren[ cnt ], srcList );
@ -239,19 +235,16 @@ void SceneCombiner::AttachToGraph (aiNode* attach, std::vector<NodeAttachmentInf
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void SceneCombiner::AttachToGraph ( aiScene* master, void SceneCombiner::AttachToGraph ( aiScene* master, std::vector<NodeAttachmentInfo>& src) {
std::vector<NodeAttachmentInfo>& src)
{
ai_assert(NULL != master); ai_assert(NULL != master);
AttachToGraph(master->mRootNode,src); AttachToGraph(master->mRootNode,src);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, std::vector<AttachmentInfo>& srcList, unsigned int flags) {
std::vector<AttachmentInfo>& srcList, if ( nullptr == _dest ) {
unsigned int flags) return;
{ }
ai_assert(NULL != _dest);
// if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it // if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it
if (srcList.empty()) { 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, void SceneCombiner::MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator it,
std::vector<aiMesh*>::const_iterator end) 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. // find we need to build an unique list of all bones.
// we work with hashes to make the comparisons MUCH faster, // 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 begin,
std::vector<aiMesh*>::const_iterator end) std::vector<aiMesh*>::const_iterator end)
{ {
ai_assert(NULL != _out); if ( nullptr == _out ) {
return;
}
if (begin == end) { if (begin == end) {
*_out = NULL; // no meshes ... *_out = NULL; // no meshes ...
@ -903,7 +900,9 @@ void SceneCombiner::MergeMaterials(aiMaterial** dest,
std::vector<aiMaterial*>::const_iterator begin, std::vector<aiMaterial*>::const_iterator begin,
std::vector<aiMaterial*>::const_iterator end) std::vector<aiMaterial*>::const_iterator end)
{ {
ai_assert(NULL != dest); if ( nullptr == dest ) {
return;
}
if (begin == end) { if (begin == end) {
*dest = NULL; // no materials ... *dest = NULL; // no materials ...
@ -953,10 +952,9 @@ void SceneCombiner::MergeMaterials(aiMaterial** dest,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
template <typename Type> template <typename Type>
inline void CopyPtrArray (Type**& dest, const Type* const * src, ai_uint num) inline
{ void CopyPtrArray (Type**& dest, const Type* const * src, ai_uint num) {
if (!num) if (!num) {
{
dest = NULL; dest = NULL;
return; return;
} }
@ -968,9 +966,11 @@ inline void CopyPtrArray (Type**& dest, const Type* const * src, ai_uint num)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
template <typename Type> template <typename Type>
inline void GetArrayCopy (Type*& dest, ai_uint num ) inline
{ void GetArrayCopy(Type*& dest, ai_uint num ) {
if (!dest)return; if ( !dest ) {
return;
}
Type* old = dest; Type* old = dest;
dest = new Type[num]; 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? // reuse the old scene or allocate a new?
if (*_dest) { if (*_dest) {
(*_dest)->~aiScene(); (*_dest)->~aiScene();
new (*_dest) aiScene(); new (*_dest) aiScene();
} else {
*_dest = new aiScene();
} }
else *_dest = new aiScene();
::memcpy(*_dest,src,sizeof(aiScene)); ::memcpy(*_dest,src,sizeof(aiScene));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate) void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate) {
{ if ( nullptr == _dest || nullptr == src ) {
ai_assert(NULL != _dest && NULL != src); return;
}
if (allocate) { if (allocate) {
*_dest = new aiScene(); *_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) void SceneCombiner::Copy( aiMesh** _dest, const aiMesh* src ) {
{ if ( nullptr == _dest || nullptr == src ) {
ai_assert(NULL != _dest && NULL != src); return;
}
aiMesh* dest = *_dest = new aiMesh(); 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) void SceneCombiner::Copy (aiMaterial** _dest, const aiMaterial* src) {
{ if ( nullptr == _dest || nullptr == src ) {
ai_assert(NULL != _dest && NULL != src); return;
}
aiMaterial* dest = (aiMaterial*) ( *_dest = new aiMaterial() ); 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) void SceneCombiner::Copy(aiTexture** _dest, const aiTexture* src) {
{ if ( nullptr == _dest || nullptr == src ) {
ai_assert(NULL != _dest && NULL != src); return;
}
aiTexture* dest = *_dest = new aiTexture(); 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 ) void SceneCombiner::Copy( aiAnimation** _dest, const aiAnimation* src ) {
{ if ( nullptr == _dest || nullptr == src ) {
ai_assert( NULL != _dest ); return;
ai_assert( NULL != src ); }
aiAnimation* dest = *_dest = new aiAnimation(); 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) void SceneCombiner::Copy(aiNodeAnim** _dest, const aiNodeAnim* src) {
{ if ( nullptr == _dest || nullptr == src ) {
ai_assert(NULL != _dest && NULL != src); return;
}
aiNodeAnim* dest = *_dest = new aiNodeAnim(); 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) void SceneCombiner::Copy( aiCamera** _dest,const aiCamera* src) {
{ if ( nullptr == _dest || nullptr == src ) {
ai_assert(NULL != _dest && NULL != src); return;
}
aiCamera* dest = *_dest = new aiCamera(); 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) void SceneCombiner::Copy(aiLight** _dest, const aiLight* src) {
{ if ( nullptr == _dest || nullptr == src ) {
ai_assert(NULL != _dest && NULL != src); return;
}
aiLight* dest = *_dest = new aiLight(); 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) void SceneCombiner::Copy(aiBone** _dest, const aiBone* src) {
{ if ( nullptr == _dest || nullptr == src ) {
ai_assert(NULL != _dest && NULL != src); return;
}
aiBone* dest = *_dest = new aiBone(); 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) void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src) {
{ if ( nullptr == _dest || nullptr == src ) {
ai_assert( NULL != _dest ); return;
ai_assert( NULL != src); }
aiMetadata* dest = *_dest = aiMetadata::Alloc( src->mNumProperties ); aiMetadata* dest = *_dest = aiMetadata::Alloc( src->mNumProperties );
std::copy(src->mKeys, src->mKeys + src->mNumProperties, dest->mKeys); std::copy(src->mKeys, src->mKeys + src->mNumProperties, dest->mKeys);
@ -1271,4 +1284,5 @@ void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src)
} }
} }
} } // Namespace Assimp

View File

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

View File

@ -71,3 +71,8 @@ TEST_F( utSceneCombiner, MergeMeshes_ValidNames_Test ) {
std::string outName = out->mName.C_Str(); std::string outName = out->mName.C_Str();
EXPECT_EQ( "mesh_1.mesh_2.mesh_3", outName ); 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 ) );
}