Roger Gilbrat
Roger Gilbrat

Reputation: 3835

std::map compare function and NULL

I've written a compare function for a std::map so I can have custom key types.

std::map<GGString *, GGObject *, GGDictionaryMapCompare> _map;

...

class GGDictionaryMapCompare
{
public:
    bool operator()(GGString * lhs, GGString * rhs)
    {
        return strcmp(lhs->str(), rhs->str()) < 0;
    }
};

Code that adds elements:

GGObject *GGDictionary::addKeyObject(GGString *theKey, GGObject *theObject)
{
    if (theKey == NULL || theObject == NULL)
        return NULL;

    _map.insert(std::pair<GGString *, GGObject *>(theKey, theObject));

    return theObject;
}

Code that is causing the crash:

GGObject *GGDictionary::objectForKey(GGString *theKey)
{
    if (theKey == NULL)
        return NULL;

    std::map<GGString *, GGObject *, GGDictionaryMapCompare>::iterator ii = _map.find(theKey);
    if (ii == _map.end())
    return NULL;

    return GGAutoRelease(ii->second);
}

Stack trace:

#0  0x00009f15 in GGString::str()
#1  0x0004a4c4 in GGDictionaryMapCompare::operator()(GGString*, GGString*)
#2  0x0004a3d3 in std::_Rb_tree<GGString*, std::pair<GGString* const, GGObject*>, std::_Select1st<std::pair<GGString* const, GGObject*> >, GGDictionaryMapCompare, std::allocator<std::pair<GGString* const, GGObject*> > >::find(GGString* const&)
#3  0x00049b04 in std::map<GGString*, GGObject*, GGDictionaryMapCompare, std::allocator<std::pair<GGString* const, GGObject*> > >::find(GGString* const&)
#4  0x00048ec9 in GGDictionary::objectForKey(GGString*)

The issue is that the lhs is coming in NULL. I never insert a NULL into the map, so this should not be happening. Any idea why? Or am I just doing the compare function wrong? I can protect against getting NULL, but it seems like something is wrong and I don't want to cure a symptom and not the problem.

Thanks

Upvotes: 3

Views: 1935

Answers (3)

Michael
Michael

Reputation: 5897

Are you sure the crash happens when accessing NULL? You are storing pointers in the map; is it possible that you deleted one of the pointers after storing it in the map? Something like this:

dict->addKeyObject( key1, obj1 );
delete key1; // now dict has a pointer to deleted key1
dict->addKeyObject( key2, obj2 ); // now dict will compare key2 to key1, causing crash

Upvotes: 0

MorbidFuzzball
MorbidFuzzball

Reputation: 71

I wonder if the key compare function should be revised to something like this:

bool operator()(const GGString *&lhs, const GGString *&rhs)
{
    if (lhs == NULL || rhs == NULL)
    {
       return false;
    }
    return strcmp(lhs->str(), rhs->str()) < 0;
}

Basically I'm thinking the parameters should be const references, and also that the function should protect against dereferencing NULL pointers

Upvotes: 0

templatetypedef
templatetypedef

Reputation: 372814

In this code:

GGObject *GGDictionary::objectForKey(GGString *theKey)
{
    std::map<GGString *, GGObject *, GGDictionaryMapCompare>::iterator ii = _map.find(theKey);
    if (ii == _map.end())
        return NULL;

    return GGAutoRelease(ii->second);
}

You aren't checking whether theKey is NULL. Accordingly, when the comparator is invoked on theKey and any element of the map, you will dereference NULL.

To fix this, try adding in a NULL check:

GGObject *GGDictionary::objectForKey(GGString *theKey)
{
    if (theKey == NULL) return NULL;

    std::map<GGString *, GGObject *, GGDictionaryMapCompare>::iterator ii = _map.find(theKey);
    if (ii == _map.end())
        return NULL;

    return GGAutoRelease(ii->second);
}

Hope this helps!

Upvotes: 5

Related Questions