数组包装器损坏堆栈
array wrapper corrupts stack
我的项目是一个类似于 std::vector 的动态数组包装器。它是这样工作的:
添加新元素时,如果为0,则分配内存(malloc),如果不为0,则重新分配新的大小(realloc)。大小是元素数量 * 类型大小
当获取一个已经添加的元素时,我通过将其索引乘以类型的大小并将其添加到分配内存的地址来计算地址
注意:我自己写入和读取内存,没有像 memcpy 或 memset 这样的功能。这是我的项目所必需的。我应该可以做到这一点,所以如果可以,请不要提及(除非我实施错误,在这种情况下,请提及)
当我尝试使用 get(int index)
函数读取添加的元素时,我会收到 "stack around variable was corrupted" 或 "read access violation" 错误,具体取决于我尝试的方式。
我在网上看了一点,发现我可能已经用 malloc 以某种方式破坏了堆。还读了我可以找出错误的地方是 "valgrind",但它似乎只适用于 linux,我使用 windows.
这是我的代码(重写,删除了所有错误检查以使其更小)。我得到错误的地方评论:
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;
};
让我们把代码拆开慢慢修复。从构造函数开始,一切都应该被初始化。尽快初始化变量非常重要:
darr() {
start = nullptr;
end = nullptr;
elemc = 0;
size = 0;
}
现在让我们看一下方法add
。它应该做什么?向容器中添加一个元素并保留已经存在的元素。它现在在做什么?让我们看看:
- 正在创建临时
void*
指针。
void* end_temp = 0;
- 检查是否
end != nullptr
,我们将 end
分配给 end_temp
。
if (this->end) { end_temp = this->end; }
- 分配内存并增加
elemc
(我假设是元素数)
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;
}
让我们简化并做我们想要的,即添加元素:
if (true == this->alloc())
{
start[size] = obj;
this->size++;
}
alloc()
不再接受参数,因为它总是递增 1。size
是容器中元素的数量。我们只是将元素分配给最后一个索引,并将大小增加 1。
让我们现在 get()
看看。它需要做什么?获取索引处的元素。简单写一下:
T get(int i) const
{
if (i < size)
return start[i];
}
我的项目是一个类似于 std::vector 的动态数组包装器。它是这样工作的:
添加新元素时,如果为0,则分配内存(malloc),如果不为0,则重新分配新的大小(realloc)。大小是元素数量 * 类型大小
当获取一个已经添加的元素时,我通过将其索引乘以类型的大小并将其添加到分配内存的地址来计算地址
注意:我自己写入和读取内存,没有像 memcpy 或 memset 这样的功能。这是我的项目所必需的。我应该可以做到这一点,所以如果可以,请不要提及(除非我实施错误,在这种情况下,请提及)
当我尝试使用 get(int index)
函数读取添加的元素时,我会收到 "stack around variable was corrupted" 或 "read access violation" 错误,具体取决于我尝试的方式。
我在网上看了一点,发现我可能已经用 malloc 以某种方式破坏了堆。还读了我可以找出错误的地方是 "valgrind",但它似乎只适用于 linux,我使用 windows.
这是我的代码(重写,删除了所有错误检查以使其更小)。我得到错误的地方评论:
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;
};
让我们把代码拆开慢慢修复。从构造函数开始,一切都应该被初始化。尽快初始化变量非常重要:
darr() {
start = nullptr;
end = nullptr;
elemc = 0;
size = 0;
}
现在让我们看一下方法add
。它应该做什么?向容器中添加一个元素并保留已经存在的元素。它现在在做什么?让我们看看:
- 正在创建临时
void*
指针。
void* end_temp = 0;
- 检查是否
end != nullptr
,我们将end
分配给end_temp
。
if (this->end) { end_temp = this->end; }
- 分配内存并增加
elemc
(我假设是元素数)
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;
}
让我们简化并做我们想要的,即添加元素:
if (true == this->alloc())
{
start[size] = obj;
this->size++;
}
alloc()
不再接受参数,因为它总是递增 1。size
是容器中元素的数量。我们只是将元素分配给最后一个索引,并将大小增加 1。
让我们现在 get()
看看。它需要做什么?获取索引处的元素。简单写一下:
T get(int i) const
{
if (i < size)
return start[i];
}