我的 C 程序以 segfault 结尾 - valgrind
让我们有一个基本的失败计划:
#include <iostream>
void fail() {
int *p1;
int *p2(NULL);
int *p3 = p1;
if (p3) {
std::cout << *p3 << std::endl;
}
}
int main() {
fail();
}
构建它(添加 -g 以包含调试信息):
g++ -g -o main main.cpp
跑:
$ ./main
Segmentation fault (core dumped)
$
让我们用 valgrind 调试它:
$ valgrind ./main
==8515== Memcheck, a memory error detector
==8515== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==8515== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==8515== Command: ./main
==8515==
==8515== Conditional jump or move depends on uninitialised value(s)
==8515== at 0x400813: fail() (main.cpp:7)
==8515== by 0x40083F: main (main.cpp:13)
==8515==
==8515== Invalid read of size 4
==8515== at 0x400819: fail() (main.cpp:8)
==8515== by 0x40083F: main (main.cpp:13)
==8515== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==8515==
==8515==
==8515== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==8515== Access not within mapped region at address 0x0
==8515== at 0x400819: fail() (main.cpp:8)
==8515== by 0x40083F: main (main.cpp:13)
==8515== If you believe this happened as a result of a stack
==8515== overflow in your program's main thread (unlikely but
==8515== possible), you can try to increase the size of the
==8515== main thread stack using the --main-stacksize= flag.
==8515== The main thread stack size used in this run was 8388608.
==8515==
==8515== HEAP SUMMARY:
==8515== in use at exit: 72,704 bytes in 1 blocks
==8515== total heap usage: 1 allocs, 0 frees, 72,704 bytes allocated
==8515==
==8515== LEAK SUMMARY:
==8515== definitely lost: 0 bytes in 0 blocks
==8515== indirectly lost: 0 bytes in 0 blocks
==8515== possibly lost: 0 bytes in 0 blocks
==8515== still reachable: 72,704 bytes in 1 blocks
==8515== suppressed: 0 bytes in 0 blocks
==8515== Rerun with --leak-check=full to see details of leaked memory
==8515==
==8515== For counts of detected and suppressed errors, rerun with: -v
==8515== Use --track-origins=yes to see where uninitialised values come from
==8515== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
$
首先我们关注这个块:
==8515== Invalid read of size 4
==8515== at 0x400819: fail() (main.cpp:8)
==8515== by 0x40083F: main (main.cpp:13)
==8515== Address 0x0 is not stack'd, malloc'd or (recently) free'd
第一行告诉我们,段错误是由读取 4 个字节引起的。第二行和第三行是调用堆栈。这意味着无效读取是在 main.cpp 的第 8 行的 fail()
函数上执行的,该函数由 main.cpp 的第 13 行调用。
看看 main.cpp 的第 8 行,我们看到了
std::cout << *p3 << std::endl;
但是我们先检查指针,那有什么不对?让我们检查另一个块:
==8515== Conditional jump or move depends on uninitialised value(s)
==8515== at 0x400813: fail() (main.cpp:7)
==8515== by 0x40083F: main (main.cpp:13)
它告诉我们第 7 行有一个单元化变量,我们读到它:
if (p3) {
这指向了我们检查 p3 而不是 p2 的行。但 p3 怎么可能未初始化?我们通过以下方式初始化:
int *p3 = p1;
Valgrind 建议我们重新运行 --track-origins=yes
,让我们这样做:
valgrind --track-origins=yes ./main
valgrind 的论点就在 valgrind 之后。如果我们把它放在我们的程序之后,它将被传递给我们的程序。
输出几乎相同,只有一个区别:
==8517== Conditional jump or move depends on uninitialised value(s)
==8517== at 0x400813: fail() (main.cpp:7)
==8517== by 0x40083F: main (main.cpp:13)
==8517== Uninitialised value was created by a stack allocation
==8517== at 0x4007F6: fail() (main.cpp:3)
这告诉我们在第 7 行创建的未初始化值是在第 3 行创建的:
int *p1;
它指导我们未初始化的指针。