[英]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->cap
为4
,则您只有4
元素的空间(索引从0
到3
),但在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.