Valgrind 在 "X bytes below stack pointer" 报告 "invalid write"
Valgrind reports "invalid write" at "X bytes below stack pointer"
我是 运行 Valgrind 下的一些代码,使用 gcc 7.5 编译,目标是 aarch64(ARM 64 位)架构,启用了优化。
我收到以下错误:
==3580== Invalid write of size 8
==3580== at 0x38865C: ??? (in ...)
==3580== Address 0x1ffeffdb70 is on thread 1's stack
==3580== 16 bytes below stack pointer
这是违规代码附近的程序集转储:
388640: a9bd7bfd stp x29, x30, [sp, #-48]!
388644: f9000bfc str x28, [sp, #16]
388648: a9024ff4 stp x20, x19, [sp, #32]
38864c: 910003fd mov x29, sp
388650: d1400bff sub sp, sp, #0x2, lsl #12
388654: 90fff3f4 adrp x20, 204000 <_IO_stdin_used-0x4f0>
388658: 3dc2a280 ldr q0, [x20, #2688]
38865c: 3c9f0fe0 str q0, [sp, #-16]!
我正在尝试确定这是否是我的代码中可能存在的错误(请注意,我已经彻底检查了我的代码并且我相当有信心它是正确的),或者 Valgrind 是否会盲目地报告任何低于堆栈指针错误。
假设是后者,它看起来像是一个 Valgrind 错误,因为 0x38865c
处的违规指令使用预递减寻址模式,因此它实际上并没有写在堆栈指针下方。
此外,在地址 0x388640
执行了类似的访问(并再次使用预递减寻址模式),但 Valgrind 并未报告;主要区别在于在地址 0x388640
处使用 x
寄存器与在地址 38865c
.
处使用 q
寄存器
我还想提请注意 0x388650
处的大堆栈指针减法,这可能与此问题有任何关系,也可能没有任何关系(注意这种减法是有道理的,因为有问题的 C代码在堆栈上声明了一个大数组)。
所以,有人能帮助我理解这一点吗?我是否应该担心我的代码?
code declares a large array on the stack
should [I] worry about my code?
我认为这取决于您希望自己的代码更具可移植性。
使用这段代码,我认为它至少代表了您在 post 中提到的一件重要事情:
#include <stdio.h>
#include <stdlib.h>
long long foo (long long sz, long long v) {
long long arr[sz]; // allocating a variable on the stack
arr[sz-1] = v;
return arr[sz-1];
}
int main (int argc, char *argv[]) {
long long n = atoll(argv[1]);
long long v = foo(n, n);
printf("v = %lld\n", v);
}
$ uname -mprsv
Darwin 20.5.0 Darwin Kernel Version 20.5.0: Sat May 8 05:10:33 PDT 2021; root:xnu-7195.121.3~9/RELEASE_X86_64 x86_64 i386
$ gcc test.c
$ a.out 1047934
v = 1047934
$ a.out 1047935
Segmentation fault: 11
$ uname -snrvmp
Linux localhost.localdomain 3.19.8-100.fc20.x86_64 #1 SMP Tue May 12 17:08:50 UTC 2015 x86_64 x86_64
$ gcc test.c
$ ./a.out 2147483647
v = 2147483647
$ ./a.out 2147483648
v = 2147483648
此代码至少存在一些小的可移植性问题。这两种环境的可分配堆栈内存量差异很大。这仅适用于两个平台。还没有在我的 Windows 10 虚拟机上尝试过,但我认为我不需要这样做,因为我很久以前就被它咬过。
代码看起来没问题,写的肯定不在栈指针下面。该消息似乎是一个 valgrind 错误,可能 #432552,已标记为已修复。 OP 确认将 valgrind 升级到 3.17.0 后不会产生该消息。
除了 Valgrind 错误导致的 OP 问题之外,这个问题的标题肯定会吸引更多人(比如我)将“在堆栈指针下方的 X 字节处进行无效写入”视为合法错误。
我的建议:检查您要写入的地址是否不是另一个函数的局部变量(不存在于调用堆栈中)!
我在函数 yyparse
之外尝试写入 yyget_lloc(yyscanner)
返回的地址时偶然发现了这个问题(前者 returns 后者的局部变量地址).
我是 运行 Valgrind 下的一些代码,使用 gcc 7.5 编译,目标是 aarch64(ARM 64 位)架构,启用了优化。
我收到以下错误:
==3580== Invalid write of size 8
==3580== at 0x38865C: ??? (in ...)
==3580== Address 0x1ffeffdb70 is on thread 1's stack
==3580== 16 bytes below stack pointer
这是违规代码附近的程序集转储:
388640: a9bd7bfd stp x29, x30, [sp, #-48]!
388644: f9000bfc str x28, [sp, #16]
388648: a9024ff4 stp x20, x19, [sp, #32]
38864c: 910003fd mov x29, sp
388650: d1400bff sub sp, sp, #0x2, lsl #12
388654: 90fff3f4 adrp x20, 204000 <_IO_stdin_used-0x4f0>
388658: 3dc2a280 ldr q0, [x20, #2688]
38865c: 3c9f0fe0 str q0, [sp, #-16]!
我正在尝试确定这是否是我的代码中可能存在的错误(请注意,我已经彻底检查了我的代码并且我相当有信心它是正确的),或者 Valgrind 是否会盲目地报告任何低于堆栈指针错误。
假设是后者,它看起来像是一个 Valgrind 错误,因为 0x38865c
处的违规指令使用预递减寻址模式,因此它实际上并没有写在堆栈指针下方。
此外,在地址 0x388640
执行了类似的访问(并再次使用预递减寻址模式),但 Valgrind 并未报告;主要区别在于在地址 0x388640
处使用 x
寄存器与在地址 38865c
.
q
寄存器
我还想提请注意 0x388650
处的大堆栈指针减法,这可能与此问题有任何关系,也可能没有任何关系(注意这种减法是有道理的,因为有问题的 C代码在堆栈上声明了一个大数组)。
所以,有人能帮助我理解这一点吗?我是否应该担心我的代码?
code declares a large array on the stack
should [I] worry about my code?
我认为这取决于您希望自己的代码更具可移植性。
使用这段代码,我认为它至少代表了您在 post 中提到的一件重要事情:
#include <stdio.h>
#include <stdlib.h>
long long foo (long long sz, long long v) {
long long arr[sz]; // allocating a variable on the stack
arr[sz-1] = v;
return arr[sz-1];
}
int main (int argc, char *argv[]) {
long long n = atoll(argv[1]);
long long v = foo(n, n);
printf("v = %lld\n", v);
}
$ uname -mprsv
Darwin 20.5.0 Darwin Kernel Version 20.5.0: Sat May 8 05:10:33 PDT 2021; root:xnu-7195.121.3~9/RELEASE_X86_64 x86_64 i386
$ gcc test.c
$ a.out 1047934
v = 1047934
$ a.out 1047935
Segmentation fault: 11
$ uname -snrvmp
Linux localhost.localdomain 3.19.8-100.fc20.x86_64 #1 SMP Tue May 12 17:08:50 UTC 2015 x86_64 x86_64
$ gcc test.c
$ ./a.out 2147483647
v = 2147483647
$ ./a.out 2147483648
v = 2147483648
此代码至少存在一些小的可移植性问题。这两种环境的可分配堆栈内存量差异很大。这仅适用于两个平台。还没有在我的 Windows 10 虚拟机上尝试过,但我认为我不需要这样做,因为我很久以前就被它咬过。
代码看起来没问题,写的肯定不在栈指针下面。该消息似乎是一个 valgrind 错误,可能 #432552,已标记为已修复。 OP 确认将 valgrind 升级到 3.17.0 后不会产生该消息。
除了 Valgrind 错误导致的 OP 问题之外,这个问题的标题肯定会吸引更多人(比如我)将“在堆栈指针下方的 X 字节处进行无效写入”视为合法错误。
我的建议:检查您要写入的地址是否不是另一个函数的局部变量(不存在于调用堆栈中)!
我在函数 yyparse
之外尝试写入 yyget_lloc(yyscanner)
返回的地址时偶然发现了这个问题(前者 returns 后者的局部变量地址).