static maps and stack errors

Started by
7 comments, last by rip-off 12 years, 5 months ago
I am having some issues with a map ive created and not even my tutor after 3 hours could figure out why it was screwing up.

I have a class that is designed to hold a map of all textures i have loaded and return ones already made.

Problem is that the second the static map is defined, it causes the stack to become corrupted and the program crashes.
I have tried moving the map around, making it global instead of static, etc. Nothing seems to make it happy.



#include "TextureLoader.h"
#include "DXMgr.h"

#include <d3dx9.h>
#include <iostream>
#include <map>

TextureLoader *m_instance;

TextureLoader* TextureLoader::GetInstance()
{
if(m_instance == NULL)
{
m_instance = new TextureLoader();

}
return m_instance;
}

//std::map<char*,LPDIRECT3DTEXTURE9*> m_textureMap;

HRESULT TextureLoader::GetTexture(LPDIRECT3DDEVICE9 device, std::string filename, LPDIRECT3DTEXTURE9* texture)
{
static std::map<std::string,LPDIRECT3DTEXTURE9*>m_textureMap; //MUST BE IN RELEASE MODE FOR THIS TO WORK FOR SOME REASON FFS
if(m_textureMap.find(filename) != m_textureMap.end())
{
texture = m_textureMap[filename];
return D3D_OK;
}
HRESULT result = D3DXCreateTextureFromFile(device,filename.c_str(),texture);
if(result == D3D_OK)
m_textureMap[filename] = texture;
return result;
}


The error it gets at the moment is
_CrtIsValidHeapPointer(pUserData)

As far as i can see... this should work, my tutor agrees as well. So we are both very eager to see why the hell this keeps breaking.


The only time it seems to work is when the program is in release mode. Which was fine up until it broke a seemingly normal bit of code in a different class.
char* filename = "Dwarf.x";

that line gets skipped over in the code and is apparently not considered executable code.... in release mode.



Any help would be greatly appreciated
Advertisement
Could be memory corruption, or many other things. It probably "works" in Release mode because the debug checks are omitted.

Your function appears to map local pointers. Accessing these pointers could be causing the corruption.

Try:

HRESULT TextureLoader::GetTexture(LPDIRECT3DDEVICE9 device, std::string filename, LPDIRECT3DTEXTURE9& texture)
{
static std::map<std::string,LPDIRECT3DTEXTURE9> m_textureMap;
if(m_textureMap.find(filename) != m_textureMap.end())
{
texture = m_textureMap[filename];
return D3D_OK;
}
HRESULT result = D3DXCreateTextureFromFile(device,filename.c_str(),&texture);
if(result == D3D_OK)
m_textureMap[filename] = texture;
return result;
}

Or:

HRESULT TextureLoader::GetTexture(LPDIRECT3DDEVICE9 device, std::string filename, LPDIRECT3DTEXTURE9* texture)
{
static std::map<std::string,LPDIRECT3DTEXTURE9> m_textureMap;
if(m_textureMap.find(filename) != m_textureMap.end())
{
*texture = m_textureMap[filename];
return D3D_OK;
}
HRESULT result = D3DXCreateTextureFromFile(device,filename.c_str(),texture);
if(result == D3D_OK)
m_textureMap[filename] = *texture;
return result;
}

These are roughly equivalent. Some people prefer references where NULL parameters aren't permitted. Others prefer to see the ampersand "address-of" operator in the calling code when parameters are modified.

If this fixes the problem, you can promote your map to a member of the class.
Make the std::map a class member of TextureLoader, otherwise how do you plan to unload the textures after use?
Also, I see this

std::map<char*, LPDIRECT3DTEXTURE9*> m_texturemap;


Get rid of that immediately.

@rip-off

both of those produced the same error, never getting past the initialization of the map

I fiddled with the code a bit and it seems that the problem lies in the LPDIRECT3DTEXTURE9. If that gets changed to say a string, the problem goes away.
Could it be that the LPDIRECT3DTEXTURE9 class just dislikes being mapped or something?


Edit.

Removing the static keyword makes the function work without error... but renders the function relatively useless.
Moving the map outside of the function, making it global, causes the program to break when it attempts to find or add an entry, returning a null root
For the record,

static std::map<std::string,std::pair<void*,LPDIRECT3DTEXTURE9*>>m_textureMap;


doesnt fix the problem either.


Edit:

Just found a new warning appear that may provide some info.


warning LNK4210: .CRT section exists; there may be unhandled static initializers or terminators



that sounds like it may be something...
FINALLY FIGURED IT OUT!!!!


[font=Arial][size=2][color=#ED1C24][font=inherit][font=Arial][size=2][color="#000000"][font=inherit]In the project properties:[/font][/font][/font]

[color=#ED1C24][font=inherit][font=Arial][size=2][color="#000000"][font=inherit]1. Set Linker\Advanced\Entry Point to "" (empty string)
2. Set Linker\System\Subsystem to Not Set[/font][/font][/font]

[color=#ED1C24][font=inherit][font=Arial][size=2][color="#000000"][font=inherit]
[/font][/font][/font]

[font=inherit]Changing these two values fixed it. Turns out if a project is not a windows project (mine was console) then it wont call the internal startup function that sets up things such as the heap or whatever.[/font]

[/font]
That doesn't sound right. Are you saying you disabled the entry point and subsystem to fix this? Or are you saying that they weren't set, and you changed them to something else?

My only experience of playing with these settings is that the subsystem is not set on "empty" projects, but this causes a link error IIRC.

That doesn't sound right. Are you saying you disabled the entry point and subsystem to fix this? Or are you saying that they weren't set, and you changed them to something else?

My only experience of playing with these settings is that the subsystem is not set on "empty" projects, but this causes a link error IIRC.



I had never touched the subsystem before this, so it was whatever default is. As for the entry point, by default it WAS empty, but i was taught to change it to say WinMain when making these kind of programs.

Typically, setting the subsystem to Windows implies that the entry point is WinMain(). I believe that setting a custom entry point is dangerous, as it may allow for aspects of the C and C++ runtimes to be incorrectly initialised.

Link:

The function must be defined with the __stdcall calling convention. The parameters and return value must be defined as documented in the Win32 API for WinMain (for an .exe file) or DllEntryPoint (for a DLL). It is recommended that you let the linker set the entry point so that the C run-time library is initialized correctly, and C++ constructors for static objects are executed.
[/quote]
As such, I believe the preferred solution is to set the subsystem, rather than the entry point.

This topic is closed to new replies.

Advertisement