C 堆栈函数中的堆缓冲区溢出
因此,我创建了一个程序,使用一个名为stack的结构生成堆栈及其所有操作 结构:C 堆栈函数中的堆缓冲区溢出,c,struct,stack,dynamic-memory-allocation,function-definition,C,Struct,Stack,Dynamic Memory Allocation,Function Definition,因此,我创建了一个程序,使用一个名为stack的结构生成堆栈及其所有操作 结构: typedef struct { int *v; /* contents of the stack */ int cap; /* capacity of v, i.e. how many elements can fit in v */ int sz; /* number of elements currently stored in v */
typedef struct {
int *v; /* contents of the stack */
int cap; /* capacity of v, i.e. how many elements can fit in v */
int sz; /* number of elements currently stored in v */
} stack;
这个程序运行得很好,但是当我使用fsantize时,它说Push函数的堆上有缓冲区溢出,我不明白为什么,因为我重新分配了我需要的字节,并释放了我不需要的字节
节目:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int *v; /* contents of the stack */
int cap; /* capacity of v, i.e. how many elements can fit in v */
int sz; /* number of elements currently stored in v */
} stack;
void init(stack * s)
{
s->v = (int*) calloc(4,sizeof(int));
s->cap = 4;
s->sz = -1;
}
int is_empty(stack * s)
{
if (s->sz == -1)
return 1;
else
return 0;
}
void push(stack * s, int e)
{
if (s->sz+1 <= s->cap)
{
s->sz++;
s->v[s->sz] = e;
}
else
{
int *nv;
s->cap++;
s->sz++;
nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
s->v = nv;
s->v[s->sz] = e;
}
}
int pop(stack * s)
{
if (is_empty(s) == 0)
{
int top = s->v[s->sz];
s->sz--;
return top;
}
else
{
printf("Impossible the stack isn't empty\n");
return 0;
}
}
void destroy(stack * s)
{
//frees the stack bytes that were allocated
free(s->v);
free(s);
}
int main()
{
int i;
stack *pilha = (stack*) malloc(sizeof(stack));
init(pilha);
if (is_empty(pilha) == 1)
printf("The stack is empty\n");
pop(pilha);
for (i = 0; i<=4;i++)
push(pilha,i);
push(pilha,5);
printf("The top is:%d\n",pilha->v[pilha->sz]);
if (is_empty(pilha) == 0)
printf("The stack isn't empty\n");
destroy(pilha);
return 0;
}
推送功能无效
if语句中的条件
if (s->sz+1 <= s->cap)
这是无效的。在realloc调用成功的情况下,s->v指向的内存被释放或重新使用。因此,再次调用free将调用未定义的行为。这就是是否将尝试释放已重新分配的内存,还是将释放新分配的内存
例如,可以通过以下方式定义功能推送
int push( stack *s, int e )
{
int success = 0;
if ( ( success = s->sz+1 < s->cap ) )
{
s->v[++s->sz] = e;
}
else
{
int *nv = realloc( s->v, sizeof( int ) * ( s->cap + 1 ) );
success = nv != NULL;
if ( success )
{
s->v = nv;
++s->cap;
s->v[++s->sz] = e;
}
}
return success;
}
程序输出为
The stack is empty
the current top value is 5
the current top value is 4
the current top value is 3
the current top value is 2
the current top value is 1
the current top value is 0
The stack isn't empty
这一行:
if (s->sz+1 <= s->cap)
正确的检查方法是,如果s->sz+1s->sz++;
if (s->sz < s->cap) {
// ...
这也是错误的。首先,假设realloc分配新内存,并且需要释放旧的缓冲区:如果不需要,realloc会在需要时为您这样做。第二,您假设realloc不会在代码中的其他任何地方(malloc、calloc等)失败。第三,您在代码中的其他任何地方再次强制转换返回值,这是您不应该看到的
你应该做的是:
nv = realloc(s->v, sizeof(int)*s->cap);
if (nv == NULL) {
// Handle error, abort execution.
}
s->v = nv;
应在每次调用malloc、realloc或calloc后检查nv==NULL。调用未定义行为的不是if语句中的条件。@MarcoBonelli错误的条件是调用未定义行为的原因。确切地说,新的措辞要好得多:我照你说的做了,我想并重新输入了push到这个无效的pushstack*s,int e{s->sz++;if s->sz
s->sz++; // 4
s->v[s->sz] = e; // s->v[4] overflow!
s->sz++;
if (s->sz < s->cap) {
// ...
nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
s->v = nv;
nv = realloc(s->v, sizeof(int)*s->cap);
if (nv == NULL) {
// Handle error, abort execution.
}
s->v = nv;