C - 数组代码中奇怪的 Valgrind 投诉
C - strange Valgrind complaint in array code
我有一个支持数组的堆栈实现,用于我的 C 操作系统课程。我已经确定了所有漏洞,但 Valgrind 仍在抱怨一些我无法理解的事情:
==8162== Invalid read of size 8
==8162== at 0x400E90: shift_left (stack.c:54)
==8162== by 0x400E90: pop (stack.c:86)
==8162== by 0x40104D: process_rpn (rpn.c:59)
==8162== by 0x4009DF: main (main.c:43)
==8162== Address 0x54f8100 is 0 bytes after a block of size 16 alloc'd
==8162== at 0x4C2AC9B: realloc (vg_replace_malloc.c:785)
==8162== by 0x400E45: resize_internal (stack.c:25)
==8162== by 0x400E45: shift_right (stack.c:40)
==8162== by 0x400E45: push (stack.c:71)
==8162== by 0x400FF3: process_rpn (rpn.c:50)
==8162== by 0x4009DF: main (main.c:43)
这发生在我的 shift_left
和 shift_right
例程中。我的导师和我都不知道哪里出了问题;这是代码。我准备在 Valgrind 中将其称为误报,但在此之前我想要另一双眼睛:
// shift internal array elements all left by one
void shift_left(stack_t* shift) {
for(int i = 0; i < shift->elements; i++) {
shift->backing[i] = shift->backing[i + 1];
shift->backing[i + 1] = 0;
}
}
其中 stack_t
是这样定义的结构:
typedef struct stack_t {
double* backing;
size_t capacity;
size_t elements;
} stack_t;
和 backing
与 malloc
或 realloc
一起分配,以防插入导致后备数组大小调整。
当元素 == 容量且 i
已达到最后一个元素的索引时,
shift->backing[i + 1]
...将索引分配的内存之外。
例如,当(在您的 valgrind 中看起来就是这种情况),capacity == elements == 2,i
将循环到 1,而 shift->backing[i + 1]
将引用 shift->backing[2]
在分配的数组之外。
您的代码不正确有多种原因:
- 您可以访问
backing
数组超出数组末尾的一个位置。
- 在复制之前覆盖第二个和后续元素。
这是更正后的版本:
// shift internal array elements all left by one
void shift_left(stack_t *shift) {
if (shift->elements > 0) {
for (int i = 1; i < shift->elements; i++) {
shift->backing[i - 1] = shift->backing[i];
}
shift->backing[shift->elements - 1] = 0;
}
}
我有一个支持数组的堆栈实现,用于我的 C 操作系统课程。我已经确定了所有漏洞,但 Valgrind 仍在抱怨一些我无法理解的事情:
==8162== Invalid read of size 8
==8162== at 0x400E90: shift_left (stack.c:54)
==8162== by 0x400E90: pop (stack.c:86)
==8162== by 0x40104D: process_rpn (rpn.c:59)
==8162== by 0x4009DF: main (main.c:43)
==8162== Address 0x54f8100 is 0 bytes after a block of size 16 alloc'd
==8162== at 0x4C2AC9B: realloc (vg_replace_malloc.c:785)
==8162== by 0x400E45: resize_internal (stack.c:25)
==8162== by 0x400E45: shift_right (stack.c:40)
==8162== by 0x400E45: push (stack.c:71)
==8162== by 0x400FF3: process_rpn (rpn.c:50)
==8162== by 0x4009DF: main (main.c:43)
这发生在我的 shift_left
和 shift_right
例程中。我的导师和我都不知道哪里出了问题;这是代码。我准备在 Valgrind 中将其称为误报,但在此之前我想要另一双眼睛:
// shift internal array elements all left by one
void shift_left(stack_t* shift) {
for(int i = 0; i < shift->elements; i++) {
shift->backing[i] = shift->backing[i + 1];
shift->backing[i + 1] = 0;
}
}
其中 stack_t
是这样定义的结构:
typedef struct stack_t {
double* backing;
size_t capacity;
size_t elements;
} stack_t;
和 backing
与 malloc
或 realloc
一起分配,以防插入导致后备数组大小调整。
当元素 == 容量且 i
已达到最后一个元素的索引时,
shift->backing[i + 1]
...将索引分配的内存之外。
例如,当(在您的 valgrind 中看起来就是这种情况),capacity == elements == 2,i
将循环到 1,而 shift->backing[i + 1]
将引用 shift->backing[2]
在分配的数组之外。
您的代码不正确有多种原因:
- 您可以访问
backing
数组超出数组末尾的一个位置。 - 在复制之前覆盖第二个和后续元素。
这是更正后的版本:
// shift internal array elements all left by one
void shift_left(stack_t *shift) {
if (shift->elements > 0) {
for (int i = 1; i < shift->elements; i++) {
shift->backing[i - 1] = shift->backing[i];
}
shift->backing[shift->elements - 1] = 0;
}
}