Search code examples
c++cvisual-studio-2012structmsvcrt

Initializing a ref-to-ptr in a struct after malloc()


I'm facing a problem using VC++ and Debug CRT with a DLL in development.

I have a struct like that, holding some references.

struct DATA
{
    TA*& a;
    TB*& b;
    TC*& c;
    TD*& d;

    char** chars;
    int num_chars;

private:
    // because:
    // DATA a;
    // DATA b;
    // a = b; // is impossible
    DATA& operator=(const DATA&); // append " = delete;" for C++11

    // Default ctor (private because struct should be manually constructed using malloc)
    DATA(TA*& a, TB*& b, TC*& c, TD*& d)
        : a(a),
          b(b),
          c(c),
          d(d),
          chars(NULL),
          num_chars(0)
    {}
};

and construct it like that:

DATA*& Get()
{
    static struct DATA *data = (struct DATA*)malloc(sizeof(struct DATA));
    return data;
}

now it should hold uninitialized ref-to-ptrs, which I want to init by:

void func(TA* a, TB* b, TC* c, TD* d)
{
    Get()->a = a;
    Get()->b = b;
    Get()->c = c;
    Get()->d = d;
    ...
}

which works for everything, but ref-to-ptrs..

I'm getting a INVALID_POINTER_WRITE_FILL_PATTERN_cdcdcdcd on the first Get()->a = a; when I do !analyze -v -f using WinDbg (in a remote Kernel Debugging "kd" instance)

Thanks for your help! :)

Edit: Solution

Solution is to use the points from the correct answer.

Making the c'tor public is necessary:

struct DATA
{
    TA*& a;
    TB*& b;
    TC*& c;
    TD*& d;

    char** chars;
    int num_chars;

    // Default ctor
    DATA(TA*& a, TB*& b, TC*& c, TD*& d)
        : a(a),
          b(b),
          c(c),
          d(d),
          chars(NULL),
          num_chars(0)
    {}

private:
    // because:
    // DATA a;
    // DATA b;
    // a = b; // is impossible
    DATA& operator=(const DATA&); // append " = delete;" for C++11
};

then using placement newto construct the struct:

DATA*& Get(...)
{
    // ... some stuff, overloading, other init-method etc. to init and construct like:
    static struct DATA *data = 
        new(malloc(sizeof(struct DATA))) DATA(...); // At least assign ALL references in the c'tor
    return data;
}

then use it and maybe assign everything that's no reference:

void func(TA* a, TB* b, TC* c, TD* d)
{
    Get(a, b, c, d);

    Get()->chars = ...
    ...
}

free'ing the whole thing needs to be done explicitly by calling the d'tor and free , because we use placement new:

data->~DATA();
free(data);

Solution

  • Note that malloc() returns uninitialized memory. C++ objects need to be constructed. The way to get an object into uninitialized memory is to use placement new (this code also adds clean-up):

    #include <new>
    DATA*& Get()
    {
        static DATA *data = new(malloc(sizeof(struct DATA))) DATA(...);
        static std::unique_ptr<DATA, void(*)(DATA*)> clean(data,
                                                    [](DATA* d){
                                                        d->~DATA();
                                                        free(data);
                                                    });
    
        return data;
    }
    

    There is no way in C++ to reseat references, i.e., they need to be set during construction. Personally, I wouldn't use malloc() but rather a suitable allocation anyway:

        static DATA* data(new DATA(...));
    

    ... or, as Jarod42 pointed out, actually

        static DATA data(...);
        return &data;