Same old "Crashing on release running on debug" issue or is it?

Started by
2 comments, last by iMalc 15 years, 10 months ago
Heya. Im playing around with my model loader and I stumbled upon something strange. Here is the code :

HRESULT AllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER meshContainerBase)
	{
		// Convert to our extended type. OK as we know for sure it is:
		D3DXMESHCONTAINER_EXTENDED* meshContainer = (D3DXMESHCONTAINER_EXTENDED*)meshContainerBase;
		if (!meshContainer)
			return S_OK;

		// name
		if (meshContainer->Name)
		{
			delete []meshContainer->Name;
			meshContainer->Name=0;
		}
		// uncommenting these two crashes in release builds
		// dont know why.. they should be released by the vector anyway
		//meshContainer->exMaterials.clear();
		//meshContainer->exTextures.clear();
		
	

		// adjacency data
		if (meshContainer->pAdjacency)
			delete []meshContainer->pAdjacency;
		
		// bone parts
		if (meshContainer->exBoneOffsets)
		{
			delete []meshContainer->exBoneOffsets;
			meshContainer->exBoneOffsets=0;
		}
		
		// frame matrices
		if (meshContainer->exFrameCombinedMatrixPointer)
		{
			delete []meshContainer->exFrameCombinedMatrixPointer;
			meshContainer->exFrameCombinedMatrixPointer=0;
		}
		
		// release skin mesh
		if (meshContainer->exSkinMesh)
		{
			meshContainer->exSkinMesh->Release();
			meshContainer->exSkinMesh=0;
		}
		
		// release the main mesh
		if (meshContainer->MeshData.pMesh)
		{
			meshContainer->MeshData.pMesh->Release();
			meshContainer->MeshData.pMesh=0;
		}
			
		// release skin information
		if (meshContainer->pSkinInfo)
		{
			meshContainer->pSkinInfo->Release();
			meshContainer->pSkinInfo=0;
		}
		
		// finally delete the mesh container itself
		delete meshContainer;
		meshContainer=0;

		return S_OK;
	}


This is the function used to free meshcontainer for x models. The x models are loaded with the function D3DXLoadMeshHierarchyFromX and a allocator object is passed to it to allocate the objects. Here is the creating part of it :

HRESULT AllocateHierarchy::CreateMeshContainer(
		LPCSTR Name,
		CONST D3DXMESHDATA *meshData,
		CONST D3DXMATERIAL *materials,
		CONST D3DXEFFECTINSTANCE *effectInstances,
		DWORD numMaterials,
		CONST DWORD *adjacency,
		LPD3DXSKININFO pSkinInfo,
		LPD3DXMESHCONTAINER* retNewMeshContainer)
	{    
		// Create a mesh container structure to fill and initilaise to zero values
		// Note: I use my extended version of the structure (D3DXMESHCONTAINER_EXTENDED) defined in MeshStructures.h
		D3DXMESHCONTAINER_EXTENDED *newMeshContainer = new D3DXMESHCONTAINER_EXTENDED;
		ZeroMemory(newMeshContainer, sizeof(D3DXMESHCONTAINER_EXTENDED));

		// Always a good idea to initialise return pointer before proceeding
		*retNewMeshContainer = 0;

		// The mesh name (may be 0) needs copying over
		if (Name && strlen(Name))
		{
			newMeshContainer->Name = STUtil::DuplicateCharString(Name);
			STUtil::DebugString("Added mesh: "+ToString(Name)+"\n");
		}
		else
		{
			STUtil::DebugString("Added Mesh: no name given\n");
		}

		// The mesh type (D3DXMESHTYPE_MESH, D3DXMESHTYPE_PMESH or D3DXMESHTYPE_PATCHMESH)
		if (meshData->Type!=D3DXMESHTYPE_MESH)
		{
			// This demo does not handle mesh types other than the standard
			// Other types are D3DXMESHTYPE_PMESH (progressive mesh) and D3DXMESHTYPE_PATCHMESH (patch mesh)
			DestroyMeshContainer(newMeshContainer);
			return E_FAIL;
		}

		newMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
		
		// Adjacency data - holds information about triangle adjacency, required by the ID3DMESH object
		DWORD dwFaces = meshData->pMesh->GetNumFaces();
		newMeshContainer->pAdjacency = new DWORD[dwFaces*3];
		memcpy(newMeshContainer->pAdjacency, adjacency, sizeof(DWORD) * dwFaces*3);
		
		// Get the Direct3D device, luckily this is held in the mesh itself (Note: must release it when done with it)
		LPDIRECT3DDEVICE9 pd3dDevice = 0;
		meshData->pMesh->GetDevice(&pd3dDevice);

		// Changed 24/09/07 - can just assign pointer and add a ref rather than need to clone
		newMeshContainer->MeshData.pMesh=meshData->pMesh;
		newMeshContainer->MeshData.pMesh->AddRef();

		// Create material and texture arrays. Note that I always want to have at least one
		newMeshContainer->NumMaterials = max(numMaterials,1);
		
		newMeshContainer->exMaterials.resize(newMeshContainer->NumMaterials);
		newMeshContainer->exTextures.resize(newMeshContainer->NumMaterials);
	
		//newMeshContainer->exMaterials = new D3DMATERIAL9[newMeshContainer->NumMaterials];
		//newMeshContainer->exTextures  = new LPDIRECT3DTEXTURE9[newMeshContainer->NumMaterials];
		//ZeroMemory(newMeshContainer->exTextures, sizeof(LPDIRECT3DTEXTURE9) * newMeshContainer->NumMaterials);

		if (numMaterials>0)
		{
			// Load all the textures and copy the materials over		
			for(DWORD i = 0; i < numMaterials; ++i)
			{
				newMeshContainer->exTextures = 0;	
				newMeshContainer->exMaterials = (materials.MatD3D);
				//set ambient to 0.5f
				newMeshContainer->exMaterials.Ambient.r = 0.5f;
				newMeshContainer->exMaterials.Ambient.g = 0.5f;
				newMeshContainer->exMaterials.Ambient.b = 0.5f;
					

				if(materials.pTextureFilename)
				{
					std::string texturePath(materials.pTextureFilename);
					if (STUtil::FindFile(&texturePath))
					{						
						newMeshContainer->exTextures = m_TextureMngr->addTexture(texturePath);
						if(newMeshContainer->exTextures == NULL)
						{
							std::string errorText = "Couldn't load model texture "+texturePath;
							ERRORMSGBOX(NULL,errorText);
						}
						
					}
					else
					{
						STUtil::DebugString("Could not find texture: "+ToString(materials.pTextureFilename)+"\n");					
					}
				}
			}
		}
		else    
		// make a default material in the case where the mesh did not provide one
		{
			ZeroMemory(&newMeshContainer->exMaterials[0], sizeof( D3DMATERIAL9 ) );
			newMeshContainer->exMaterials[0].Diffuse.r = 0.5f;
			newMeshContainer->exMaterials[0].Diffuse.g = 0.5f;
			newMeshContainer->exMaterials[0].Diffuse.b = 0.5f;
			newMeshContainer->exMaterials[0].Specular = newMeshContainer->exMaterials[0].Diffuse;
			newMeshContainer->exTextures[0]=0;
		}

		// If there is skin data associated with the mesh copy it over
		if (pSkinInfo)
		{
			// save off the SkinInfo
			newMeshContainer->pSkinInfo = pSkinInfo;
			pSkinInfo->AddRef();

			// Need an array of offset matrices to move the vertices from the figure space to the bone's space
			UINT numBones = pSkinInfo->GetNumBones();
			newMeshContainer->exBoneOffsets = new D3DXMATRIX[numBones];

			// Create the arrays for the bones and the frame matrices
			newMeshContainer->exFrameCombinedMatrixPointer = new D3DXMATRIX*[numBones];

			// get each of the bone offset matrices so that we don't need to get them later
			for (UINT i = 0; i < numBones; i++)
				newMeshContainer->exBoneOffsets = *(newMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i));

			STUtil::DebugString("Mesh has skinning info.\n Number of bones is: "+ToString(numBones)+"\n");
			// Note: in the Microsoft samples a GenerateSkinnedMesh function is called here in order to prepare
			// the skinned mesh data for optimial hardware acceleration. As mentioned in the notes this sample
			// does not do hardware skinning but instead uses software skinning.
		}
		else	
		{
			// No skin info so 0 all the pointers
			newMeshContainer->pSkinInfo = 0;
			newMeshContainer->exBoneOffsets = 0;
			newMeshContainer->exSkinMesh = 0;
			newMeshContainer->exFrameCombinedMatrixPointer = 0;
		}

		// When we got the device we caused an internal reference count to be incremented
		// So we now need to release it
		pd3dDevice->Release();

		// The mesh may contain a reference to an effect file
		if (effectInstances)
		{
			if (effectInstances->pEffectFilename)
				STUtil::DebugString("This .x file references an effect file. Effect files are not handled by this demo\n");
		}
		
		// Set the output mesh container pointer to our newly created one
		*retNewMeshContainer = newMeshContainer;    

		return S_OK;
	}


And this is the mesh container class :

struct D3DXMESHCONTAINER_EXTENDED: public D3DXMESHCONTAINER
	{
		
		std::vector<TexturePtr> exTextures;
		std::vector<D3DMATERIAL9> exMaterials;
		
	
		//IDirect3DTexture9**  exTextures;		// Array of texture pointers  
		//D3DMATERIAL9*		 exMaterials;		// Array of materials
	                                
		// Skinned mesh variables
		ID3DXMesh*           exSkinMesh;			// The skin mesh
		D3DXMATRIX*			 exBoneOffsets;			// The bone matrix Offsets, one per bone
		D3DXMATRIX**		 exFrameCombinedMatrixPointer;	// Array of frame matrix pointers
	};


If you look through the code you will notice that I replaced the raw pointers exTextures an exMaterials with vectors TexturePtr is CComPtr<IDirect3dTexture9>. When loading the meshContainer i size these vectors according to the material count and then add materials to the material vector.And use my texture manager to add textures to the texture vector.The texture manager addTexture method returns a TexturePtr too. The problem is this runs fine on debug but in release mode when i try to use meshContainer->exMaterials.clear(); meshContainer->exTextures.clear(); in DestroyMeshContainer method it crashes. I think I don't even need to call clear on the vectors as they will clean themselves up but I'm still curious about what might be wrong. You can get the whole project from : Link Any ideas?
Advertisement
If I use the raw pointers :
IDirect3DTexture9** exTextures; // Array of texture pointers
D3DMATERIAL9* exMaterials;

and allocate them like this :

newMeshContainer->exMaterials = new D3DMATERIAL9[newMeshContainer->NumMaterials];		newMeshContainer->exTextures  = new LPDIRECT3DTEXTURE9[newMeshContainer->NumMaterials];		ZeroMemory(newMeshContainer->exTextures, sizeof(LPDIRECT3DTEXTURE9) * newMeshContainer->NumMaterials);


And then delete like this :
  if (meshContainer->exMaterials)                {                        delete []meshContainer->exMaterials;                        meshContainer->exMaterials=0;                }                             // texture array                if (meshContainer->exTextures)                        delete []meshContainer->exTextures; 


It doesnt crash in debug and release builds.Also D3D does not report any memory leaks.So I think its something related to STL.Could it be some kind of thread issue?When i create the d3d object a new worker thread is created maybe its an access issue.
ZeroMemory(newMeshContainer, sizeof(D3DXMESHCONTAINER_EXTENDED));
No. Just no. newMeshContainer is not a random collection of bytes. It is a class1. It manages its own state. You just destroyed that state.

Σnigma

1In the type sense, not literally a class defined with the class-key class.
Don't check pointers for NULL before deleting them. It is so common to delete a pointer that may be NULL, that the check for this is actually already performed inside the implementation of delete, meaning that your code is always doing that check twice. I.e. delete[] NULL; is perfectly okay.

You shouldn't use memcpy in C++. The C++ way is to use std::copy instead.
Same goes for ZeroMemory; the C++ way is to use std::fill instead.

Manually calling AddRef and Release is an accident waiting to happen. Consider always wrapping your COM objects in a CComPtr instead.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

This topic is closed to new replies.

Advertisement