繁体   English   中英

堆栈中的堆缓冲区溢出 function

[英]Heap buffer overflow in stack function

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

结构:

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

程序:

#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 (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()分配了新的 memory 并且您需要free()旧缓冲区:您不需要,如果需要, realloc()会为您执行此操作。 其次,您假设realloc()不会失败(就像您在代码中的其他任何地方所做的那样, malloc()calloc()等)。 第三,您正在转换返回值(就像您在代码中的其他任何地方所做的那样),这是您不应该的(请参阅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;

检查if (nv == NULL)应该在每次调用malloc()realloc()calloc()之后进行。

function push无效。

if语句中的这个条件

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

可能是未定义行为的原因。 为简单起见,我们假设s->cap等于1 因此,您可以只推送一个元素而无需调整动态分配的数组的大小。 所以在推送一个新值s->sz后将等于0 如果不调整数组大小,您可能无法再推送一个新值。 但是,if 语句中的条件将评估为 true,您将在分配的数组之外写入 memory。

还有这个代码片段

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

是无效的。 在 realloc 调用成功的情况下,s->v 指向的 memory 被释放(或重新使用)。 所以再次调用 free 将调用未定义的行为。 这就是是否会尝试释放已经重新分配的 memory 或新分配的 memory 将被释放。

function 推送可以定义为例如以下方式

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;
}

但无论如何,最好将数据成员sz的初始值设置为 0。在这种情况下,数据成员将反映堆栈的当前大小。

function pop的返回值不明确。 返回值 0 可以是存储在堆栈中的有效值。 function 也不得发出任何消息。 如果有消息,则由 function 的调用者决定是否发出消息。

也不需要动态分配类型stack的 object 本身。 它可以具有自动存储持续时间并且是局部变量。

当初始化堆栈的 function 也有第二个参数允许指定创建的堆栈的容量而不是使用幻数4时,情况会好得多。

下面有一个演示程序,显示了如何定义堆栈及其函数。

#include <stdio.h> 
#include <stdlib.h>

typedef struct 
{
    int *v;     /* contents of the stack */
    size_t cap;    /* capacity of v, i.e. how many elements can fit in v */
    size_t sz;     /* number of elements currently stored in v */
} stack;

int init( stack * s, size_t capacity )
{
    s->sz  = 0;
    s->cap = 0;

    s->v = calloc( capacity, sizeof( int ) );

    int success = s->v != NULL; 

    if ( success )
    {
        s->cap = capacity;;
    }       

    return success;
}

int is_empty( const stack *s )
{
    return s->sz == 0;
}

int push( stack *s, int e )
{
    int success = 0;

    if ( ( success = s->sz < 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;
}

int pop( stack *s, int *value )
{
    int success = !is_empty( s );

    if ( success )
    {
        *value = s->v[--s->sz];
    }

    return success;
}

void destroy( stack *s )
{
    free( s->v );
    s->v = NULL;
    s->cap = 0;
    s->sz = 0;
}

int main( void )
{
    stack pilha;
    init( &pilha, 4 );

    if ( is_empty( &pilha ) )
    {
        printf( "The stack is empty\n" );
    }        

    const int N = 5;

    for ( int i = 0; i < 5; i++ )
    {
        push( &pilha, i );
    }

    push( &pilha, N );

    while ( ! is_empty( &pilha ) )
    {
        int value;
        pop( &pilha, &value );
        printf( "the current top value is %d\n", value );
    }

    destroy( &pilha );

    if ( is_empty( &pilha ) )
    {
        printf("The stack isn't empty\n");
    }

    return 0;
}

程序 output 是

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM