Why is alloca returning the same address twice?

288 Views Asked by At

I'm trying to implement my own math library, and I'm starting off with vectors. The idea is to give the class a pointer to an array of numbers, then copy the array and store it in the data address given by a private variable pointer. To begin with, I used alloca to try and free up some memory for the private variable

vml.h

namespace vml {
    // Vectors
    template <typename in_type, const int in_length>
    class vec {
    public:
        vec(in_type* in_data) {
            std::cout << data << std::endl;
            std::copy(in_data, in_data + in_length, data);
        }
        vec() {
            data = nullptr;
        }
        in_type& operator()(int index) const {
            _ASSERT(0 <= index && index < in_length);
            return data[index];
        }

    private:
        in_type* data = alloca(in_length * sizeof(in_type));
    };

main.cpp

int main() {
    int list[] = { 1,2,3 };
    int list2[] = {2,4,6 };

    vml::vec<int, 3> a(list);
    vml::vec<int, 3> b(list);

    return 0;
}

This gives no errors however, for some reason, alloca returns the same address twice when calling two instances. I searched this up everywhere and I couldn't find an explanation why. So I decided to allocate memory using an array. If you can answer this question that would be extremely helpful. Thanks.

3

There are 3 best solutions below

9
Ferruccio On BEST ANSWER

You have to be very careful with alloca. It allocates memory on the stack rather than the heap. That memory is freed as soon as the function which called alloca exits. In this case, it will be called in the constructor so when you call operator() that memory has already been freed and you are dealing with undefined behavior.

Unless you really need to avoid heap allocations and you know for sure that you wont overflow the stack and you understand all the limitations of using alloca, it's best to steer clear of it.

2
Surt On

Lets start with the basics, your stack is most likely only 1 MB, so after a few vectors and recursive calls you program will likely die.

To solve it if you want it on stack you could use std::array as data

Warning untested code ahead

template <typename in_type, const int in_length>
class vec {
public:
    vec(in_type* in_data) {
        std::cout << data << std::endl;
        std::copy(in_data, in_data + in_length, data);
    }
    vec() = default;
    in_type& operator()(int index) const {
        _ASSERT(0 <= index && index < in_length);
        return data[index];

    }

private:
  std::array<in_type, in_length> data;
};

Alternatively if you want to use all the nice things from std::array

template <typename in_type, const int in_length>
class vec : public std::array<in_type, in_length> {
public:
  using std::array::array; // use constructors, might need template param to compile
}

This also means that if you at some point just want to change to heap you just allocate your vec as every other class.

Another alternative is to use C++17 PMR, use an allocation on the stack as the storage and make vec PMR aware.

2
Alex Guteniev On

You cannot wrap alloca in a function and return its pointer outside, since the stack of wrapper function would be freed.

If you call it as member initializer, it is actually called from constructor, and may be freed when constructor returns and then re-used.