array wrapper corrupts stack

有些话、适合烂在心里 提交于 2020-06-29 03:48:31

问题


my project is a dynamic array wrapper like std::vector. this is how it works:

  • when adding a new element, the memory is either allocated (malloc), if it is 0, or reallocated with a new size (realloc), if it is not 0. the size is the number of elements * size of type

  • when getting an already added element, i calculate the address by multiplying its index by the size of the type and adding it to the address at which the memory is allocated

NOTE: i write and read the memory myself with no function like memcpy or memset. this is required for my project. it should be possible for me to do this so if you could, do not mention it (unless i implemented it wrong, in which case, please do mention it)

when i try to read in an added element with the get(int index) function, i either get a "stack around variable was corrupted" or "read access violation" error, depending on how I try to do it.

i read a bit online and found i may have corrupted the heap somehow with malloc. also read i could find out where the error is with something called "valgrind", but it seems to only be available for linux, and i use windows.

here is my code (its rewritten, all error checks were removed to make it smaller). the place where i get the error is commented:

template<class T>
class darr
{
public:
    darr(void) {}
    ~darr(void) {
        erase(); dealloc();
    }

    bool alloc(int elemc) {
        this->elemc = elemc;
        this->size = (elemc * sizeof(T));
        this->end = (this->start + this->size);

        if (this->start)
        {
            this->start = (T*)(realloc(this->start, this->size));

            if (this->start)
            {
                this->end = (this->start + this->size);
                return true;
            }
        }
        else
        {
            this->start = (T*)(malloc(this->size));

            if (this->start)
            {
                this->end = (this->start + this->size);
                return true;
            }
        }

        return false;
    }

    bool erase(void)
    {
        for (int i = 0; i <= this->size; ++i)
        {
            *(unsigned long*)(this->start + i) = 0;
        }

        return true;
    }

    bool dealloc(void)
    {
        free(this->start);

        return true;
    }

    bool add(T obj)
    {
        void* end_temp = 0;

        if (this->end) { end_temp = this->end; }

        if (true == this->alloc(++this->elemc))
        {
            end_temp = this->end;

            for (int i = 0; i <= sizeof(obj); ++i)
            {
                *(unsigned long*)((unsigned long)(end_temp)+i) = *(unsigned long*)((unsigned long)(&obj) + i);
            }
        }

        return true;
    }

    T get(int i)
    {
        unsigned long siz = sizeof(T);
        void* i_addr = this->start + (i * siz);

        //T tempobj = 0;
        T* tempobj = (T*)(malloc(sizeof(T)));
        // without malloc - stack around var corrupted (happnens at last index in for loop, no matter what index it is)
        // with malloc - read access violation
        for (int i = 0; i <= siz; ++i)
        {
            *(unsigned long*)((unsigned long)(&tempobj)+i) = *(unsigned long*)((unsigned long)(i_addr)+i);
        }

        return *tempobj;
    }
private:
    T * start;
    void* end;
    int elemc, size;
};

回答1:


Lets take the code apart and fix it slowly. Starting with the constructor, everything should be initialized. It is very important that you initialize your variables as soon as possible:

    darr() {
        start = nullptr;
        end = nullptr;
        elemc = 0;
        size = 0;
    }

Now lets look at the method add. What should it do? Add an element to the container and retain the ones already existing. What is it doing right now? Lets see:

  1. Creating a temporary void* pointer.
void* end_temp = 0;
  1. Checking if end != nullptr, we assign end to end_temp.
if (this->end) { end_temp = this->end; }
  1. Allocate memory and increasing the elemc (which I assume is element count)
if (true == this->alloc(++this->elemc))
  1. Next?? I am not sure. I am also not sure what has this got to do with a simple task of adding the element to a container:
{
     end_temp = this->end;

            for (int i = 0; i <= sizeof(obj); ++i)
            {
                *(unsigned long*)((unsigned long)(end_temp)+i) = *(unsigned long*)((unsigned long)(&obj) + i);
            }
        }

        return true;
    }

Let's simplify and do just what we want, that is, add the element:

        if (true == this->alloc())
        {
            start[size] = obj;
            this->size++;
        }

alloc() doesn't take an argument anymore because it is always increasing by 1. size is the number of elements in the container. We just assign the element to the last index, and increment the size by 1.

Let's see get() now. What does it need to do? Get the element at an index. Let's write it simply:

T get(int i) const
{
    if (i < size)
        return start[i];
}


来源:https://stackoverflow.com/questions/62363561/array-wrapper-corrupts-stack

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!