views:

215

answers:

2

Hello,

I have some code to handle resource (images, fonts, mesh data, etc.) management using a template'd static class, allowing client code to do something like:

ResourceManager<Texture>::init("data/textures");
ResourceManager<Font>::init("data/fonts");
// later ...
boost::shared_ptr<const Texture> tex = ResourceManager<Texture>::getResource("wall.png");
boost::shared_ptr<const Font> font = ResourceManager<Font>::getResource("Arial.ttf");
// later ...
ResourceManager<Texture>::release();

The "resource type" must have a constructor taking a const std::string&.

getResource is implemented as follows:

static boost::shared_ptr<const ResourceType> getResource(const std::string& fileName)
{
    boost::shared_ptr<ResourceType> resource;

    typename table_t::const_iterator itr = _resources.find(fileName);
    if (itr == _resources.end()) {
        resource.reset(new ResourceType(_dataDirectory + fileName));
        _resources[fileName] = resource;
    } else {
        resource = itr->second;
    }

    return resource;
}

table_t is defined as typedef typename boost::unordered_map< std::string, boost::shared_ptr<ResourceType> > table_t;

_resources is of type table_t.

The problem is with boost::unordered_map I get a segfault on the call to find (originating from find_iterator). However, with std::map instead, I either get a segfault on the insert operation (originating from _Rb_tree_decrement), or on the call to find (originating from string::compare).

The problem only occurs the 2nd time a resource is requested (fileName is valid when the failure occurs).

As this is happening with both map and unordered_map I'm assuming I must be doing something bizarre somewhere to cause this, any ideas?

Thanks.

EDIT: Still having the problem, I was wrong about it only happening the 2nd time a resource is requested. However, the first 2 calls to get a resource are successful, it's the 3rd call that is causing the segfault (each call is for a different resource).

Here is a stack trace:

Program received signal SIGSEGV, Segmentation fault.
0x00000000004b4978 in boost::unordered_detail::hash_table<boost::unordered_detail::map<std::string, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, boost::shared_ptr<Texture> > > > >::find_iterator (this=0x7aed80, bucket=0x38, k=...)
    at /usr/local/include/boost/unordered/detail/table.hpp:55
55          node_ptr it = bucket->next_;
(gdb) bt
#0  0x00000000004b4978 in boost::unordered_detail::hash_table<boost::unordered_detail::map<std::string, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, boost::shared_ptr<Texture> > > > >::find_iterator (this=0x7aed80, bucket=0x38, k=...)
    at /usr/local/include/boost/unordered/detail/table.hpp:55
#1  0x00000000004b294c in boost::unordered_detail::hash_table<boost::unordered_detail::map<std::string, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, boost::shared_ptr<Texture> > > > >::find (this=0x7aed80, k=...)
    at /usr/local/include/boost/unordered/detail/table.hpp:583
#2  0x00000000004b07c1 in boost::unordered_map<std::string, boost::shared_ptr<Texture>, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, boost::shared_ptr<Texture> > > >::find (this=0x7aed80, k=...)
    at /usr/local/include/boost/unordered/unordered_map.hpp:423
#3  0x00000000004ae7c6 in ResourceManager<Texture>::getResource (fileName=...) at /home/tim/Projects/gameproj/app/ResourceManager.hpp:52
#4  0x00000000004ce7fc in Map::loadCellTextures (this=0x7fffffffdfc0, in=...) at /home/tim/Projects/gameproj/app/Map.cpp:57
#5  0x00000000004ce632 in Map (this=0x7fffffffdfc0, fileName=...) at /home/tim/Projects/gameproj/app/Map.cpp:30
#6  0x0000000000495702 in Game::init (xResolution=1024, yResolution=768) at /home/tim/Projects/gameproj/app/Game.cpp:116
#7  0x0000000000494fa0 in Game::run (xResolution=1024, yResolution=768) at /home/tim/Projects/gameproj/app/Game.cpp:38
#8  0x0000000000487f1d in Main::run (xResolution=1024, yResolution=768) at /home/tim/Projects/gameproj/app/Main.cpp:28
#9  0x0000000000487db5 in main (argc=1, argv=0x7fffffffe398) at /home/tim/Projects/gameproj/app/main.cpp:10
A: 

The problem only occurs the 2nd time a resource is requested

This suggests to me that your code might be freeing the resource - the first time it's all fine, then you free it, then the next time the container tries to access that memory, it segfaults.

Anon.
+1  A: 

I can't spot any obvious errors, have you tried Valgrind (assuming you run some kind of *nix system)? It's an invaluable tool for finding memory errors, and this looks like it might be one of those.

Staffan
+1 for recommending valgrind, it is an invaluable tool and well worth your time to learn it.
Sam Miller
and it has the best profiler too!
Staffan
I'm somewhat familiar with Valgrind, I receive an 'Invalid read of size 8' when the segfault occurs. The offending line is `node_ptr it = bucket->next_;` in table.hpp (part of boost). With a debugger it appears that `bucket` is dangling/uninitialized.
Tim
@Tim: That's a clue, but I doubt the error is in boost itself. If you give more context someone might be able to spot it.
Staffan