Search code examples
c++visual-studio-2008stdvectoraccess-violationpush-back

std::vector push_back results in access Violation


Story: I'm making a shared library exposing C code as a wrapper to a C++ static library compiled in VS 2008, so I'm tied to that compiler. In my library I'm trying to do a very simple dictionary to pass data through the shared library boundaries. I'll not pass the actual dictionary, just the handler an provide functions to access its members. The dictionary is simply a std::vector of key-value pairs.

Problem: My program crashes every time I try to push_back a key-value pair into the dictionary. Here is a self-contained demo code (main.cpp of a fresh Win32 console project):

#include "stdafx.h"

#include <cstdlib>
#include <vector>

typedef enum KeyType
{
    KeyType_CHAR = 0,
    KeyType_INT,
    KeyType_CHAR_PTR_AS_STRING
};

typedef enum ValueType
{
    ValueType_CHAR = 0,
    ValueType_INT,
    ValueType_CHAR_PTR_AS_STRING
};

struct DictNode
{
    ValueType value_type;
    void* value_unsafe_ptr;
    void* key_unsafe_ptr;
};

struct Dict
{
    KeyType key_type;
    std::vector<DictNode> nodes;
};

int _tmain(int argc, _TCHAR* argv[])
{
    /* Create Dict */
    Dict* test = (Dict*)malloc(sizeof(Dict));
    test->key_type = KeyType_INT;

    /* Add (0, "Zero") */
    int* key0 = (int*)malloc(sizeof(int));
    *key0 = 0;

    char* content0 = (char*)malloc(sizeof(char)*5);
    content0[0] = 'Z';
    content0[1] = 'e';
    content0[2] = 'r';
    content0[3] = 'o';
    content0[4] = '\0';

    DictNode node0;
    node0.value_type = ValueType_CHAR;
    node0.key_unsafe_ptr = key0;
    node0.value_unsafe_ptr = content0;

    test->nodes.push_back(node0); // BOOM

    /* Release memory */
    test->nodes.clear();
    free(key0);
    free(content0);
    free(test);

    return 0;
}

At line test->nodes.push_back(node0); I get 0xC0000005: Access violation reading location 0xcdcdcdc1. By setting a breakpoint at that line, I can see that all key, content0, node0 and test are defined and have the correct values.


Solution

  • Dict* test = (Dict*)malloc(sizeof(Dict)); does not do what you think it does.

    malloc allocates a block of memory, but does not initialize it. So later on, when you call test->nodes.push_back, you're calling into uninitialized memory. Undefined behavior. In your case, it crashes.

    The solution here is allocate test with new, which will initialize both test and test->nodes.

    Dict* test = new Dict;
    

    The even better solution is to ask why test is dynamically allocated to begin with.