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

backingmallocrealloc 一起分配,以防插入导致后备数组大小调整。

当元素 == 容量且 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;
    }
}