堆栈函数中的堆缓冲区溢出

问题描述 投票:0回答:2

所以我创建了一个程序,该程序使用称为栈的结构来制作栈及其所有操作。

结构:

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函数中堆上有缓冲区溢出,我不明白为什么,因为ive重新分配了我需要的字节并释放了我不需要的字节。

程序:

#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;
}
c arrays pointers memory-management
2个回答
0
投票

功能push无效。

if语句中的此条件

if (s->sz+1 <= s->cap)

调用未定义的行为。假设s-> cap等于1。因此,您可以仅推送一个元素,而无需调整数组的大小。因此,在推入新值后,s-> sz将等于0。并且,如果不调整数组大小,则可能无法推入新值。但是,if语句中的条件将计算为true,并且您将写入分配的数组之外的内存。

也是此代码段

    nv = (int*) realloc(s->v, sizeof(int)*s->cap);
    free(s->v);

无效。在成功调用realloc的情况下,释放了s-> v指向的内存(或重新使用了r)。因此,再次调用free将调用未定义的行为。那就是将尝试释放已重新分配的内存还是将释放新分配的内存。


0
投票

此行:

if (s->sz+1 <= s->cap)

包含逻辑错误:如果s->sz+1 == s->cap,则需要更多空间。例如,如果s->cap4,则只有4个元素(索引从03的空间),但是对于s->sz == 3,则输入if,结果为:

s->sz++;         // 4
s->v[s->sz] = e; // s->v[4] overflow!

正确的检查方法是if (s->sz+1 < s->cap),甚至先递增该值:

s->sz++;

if (s->sz < s->cap) {
    // ...

此:

nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
s->v = nv;

也是错误的。首先,假设realloc分配了新的内存,并且需要free旧的缓冲区:您没有,realloc()会在需要时为您执行此操作。其次,假设realloc()不会失败(就像您在代码中的其他任何地方所做的一样,malloccalloc等)。第三,您正在强制转换返回值(同样,就像在代码中的其他任何地方一样),您不应该这样做(请参阅Do I cast the result of malloc?)。

您应该做的是:

nv = realloc(s->v, sizeof(int)*s->cap);
if (nv == NULL) {
    // Handle error, abort execution.
}

s->v = nv;
© www.soinside.com 2019 - 2024. All rights reserved.