这个 valgrind 输出是什么意思,我怎样才能让它显示一些可以理解的东西?

What does this valgrind output mean, and how can I get it to display something that's understandable?

我是 C 的新手,今天向我介绍了 Valgrind。我安装了它并 运行 它在我的 C calculator/equation 解析器上,我正在努力弄清楚为什么我有分段错误(核心转储),我得到了这个:

==20== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==20==  General Protection Fault
==20==    at 0x4008E27: _dl_map_object (dl-load.c:2317)
==20==    by 0x40014DD: map_doit (rtld.c:642)
==20==    by 0x4010193: _dl_catch_error (dl-error.c:187)
==20==    by 0x4002169: do_preload (rtld.c:831)
==20==    by 0x4002169: handle_ld_preload (rtld.c:929)
==20==    by 0x4004DEE: dl_main (rtld.c:1667)
==20==    by 0x40176F4: _dl_sysdep_start (dl-sysdep.c:249)
==20==    by 0x4001BB7: _dl_start_final (rtld.c:347)
==20==    by 0x4001BB7: _dl_start (rtld.c:573)
==20==    by 0x4001267: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==20==    by 0x1: ???
==20==    by 0x1FFF0008AE: ???
==20==    by 0x1FFF0008BB: ???

当然,我不知道它是什么意思,而且我发现的关于类似错误的其他事情对我来说意义不大。谁能用像我这样的人能理解的相对简单的方式解释一下?

编辑:我通过 gdb 尝试 运行 它(@pm100 建议的屁股),只得到这个:

Program received signal SIGSEGV, Segmentation fault. 0x000000000040067b in ?? ()

编辑:因为我的代码被要求,所以在这里。我可能做错了很多。

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

void write(char** dest, char* src, int index) {
    int i = 0;
    for (i = 0; src[i] != '[=11=]'; i++) {
        dest[index][i] = src[i];
    }
    dest[index][i] = '[=11=]';
    return;
}

void crite(char** dest, char src, int index) {
    int i = 0;
    dest[index][0] = src;
    dest[index][1] = '[=11=]';
    return;
}

void evaluate(char* args) {
    int i = 0;
    int j = 0;
    const char* numbers = "1234567890";
    const char* operators = "+-*/";
    int chunk = 0;
    char** chunks = calloc(24, sizeof(char*));
    char* current = calloc(24, sizeof(char));


    for (i = 0; strchr("[=11=]\n", args[i]) == NULL; i++) {
        //printf("Args[i]:%c\n\n", args[i]);
        if (strchr(numbers, args[i]) != NULL) {
            //printf("Number added to current: %c\n\n", args[i]);
            current[j] = args[i];
            //printf("\nCurrent: %s\n", current);
            j++;
        } else if (strchr(operators, args[i]) != NULL) {
            write(chunks, current, chunk);
            chunk++;
            crite(chunks, args[i], chunk);
            chunk++;
            j = 0;
            free(current);
            current = calloc(24, sizeof(char));
            //printf("Terminated with operator and operator added.\n\n");
        } else {
            printf("ERROR: Encountered invalid token.\n\n");
            return;
        }

    }

    for (i = 0; chunks[i] != NULL; i++) 
        //printf("\n-Chunk: %s\n\n", chunks[chunk]);

    return;
}

int main(int argc, char** argv) {
    evaluate(argv[1]);
}

我编译的命令是gcc calculator.c -g -o calculator

示例命令:./calculator 1*2

更新:Valgrind 的问题是由我使用的 Windows 子系统引起的,所以只要您在 linux 上 运行 Valgrind 就应该没问题。我在 VM 中尝试过它并且它有效。

此外,感谢您帮助我解决了我的分段错误,即使这不是问题最初的问题:)

这是来自 Linux 加载程序深处的堆栈跟踪。 Valgrind 创建一个沙箱执行环境并将您的程序加载到其中,它的各种工具可以将它们自己的检测代码插入到您的指令流中。

这是异国情调的东西:非常依赖于良好的 valgrind 构建并注意正确构建被测程序。仅仅这个微小的堆栈跟踪不可能解释出了什么问题。加载程序可能在尝试加载 valgrind 时死机。或者它可能在尝试加载您的程序时死在沙箱中。问题可能出在 valgrind 二进制文件或您程序的二进制文件中,导致 Linux 加载程序失败。甚至有可能(我不知道)valgrind 包含它自己的加载程序副本,并且该副本构建不正确,因此快要死了。

更大的图景是 valgrind 不是调试您的(我期望的)小程序中的简单段错误的好工具。两件更有可能取得成果的事情是正确构建和 运行 程序,以便 gdb 生成正确的符号堆栈跟踪并简单地插入 fprintfs.

这应该使用 gdb 生成堆栈跟踪:

$ gcc calculator.c -g -o calculator
$ gdb ./calculator
(gdb) run

如果你需要命令行参数来触发错误,你可以给他们set args,例如

(gdb) set args 1*2
(gdb) run

如果您没有看到堆栈跟踪,则几乎可以肯定您的构建环境已损坏:您的编译器或 gdb 有问题。

另一种不是很优雅但仍然有效的技术是从 main() 的第一行开始添加 fprintf(stderr, ...)s 并定期添加。最后的输出告诉你执行了多远。如果您是初级程序员,在您熟悉语言、编译器和编写-编译-调试-修改周期之前,避免学习新工具会更有效率。

运行 此代码在 valgrind 下产生以下结果:

[dbush@db-centos ~]$ valgrind /tmp/x1 1*2
==1431== Memcheck, a memory error detector
==1431== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==1431== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==1431== Command: /tmp/x1 1*2
==1431== 
==1431== Invalid write of size 1
==1431==    at 0x80484B3: write (x1.c:8)
==1431==    by 0x80485E8: evaluate (x1.c:39)
==1431==    by 0x804869D: main (x1.c:61)
==1431==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==1431== 
==1431== 
==1431== Process terminating with default action of signal 11 (SIGSEGV)
==1431==  Access not within mapped region at address 0x0
==1431==    at 0x80484B3: write (x1.c:8)
==1431==    by 0x80485E8: evaluate (x1.c:39)
==1431==    by 0x804869D: main (x1.c:61)
==1431==  If you believe this happened as a result of a stack
==1431==  overflow in your program's main thread (unlikely but
==1431==  possible), you can try to increase the size of the
==1431==  main thread stack using the --main-stacksize= flag.
==1431==  The main thread stack size used in this run was 10485760.
==1431== 
==1431== HEAP SUMMARY:
==1431==     in use at exit: 120 bytes in 2 blocks
==1431==   total heap usage: 2 allocs, 0 frees, 120 bytes allocated
==1431== 
==1431== LEAK SUMMARY:
==1431==    definitely lost: 0 bytes in 0 blocks
==1431==    indirectly lost: 0 bytes in 0 blocks
==1431==      possibly lost: 0 bytes in 0 blocks
==1431==    still reachable: 120 bytes in 2 blocks
==1431==         suppressed: 0 bytes in 0 blocks
==1431== Rerun with --leak-check=full to see details of leaked memory
==1431== 
==1431== For counts of detected and suppressed errors, rerun with: -v
==1431== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 13 from 8)

所以在 write 的这一行:

dest[index][i] = src[i];

您正在取消引用 NULL 指针并试图在那里写入。有问题的 NULL 指针是 dest[index],它是 NULL,因为您使用 calloc 分配内存。这是您所做的:

char** chunks = calloc(24, sizeof(char*));
char* current = calloc(24, sizeof(char));

您将 chunks 创建为指针数组,但您没有为这些指针分配任何内容。您需要遍历每个数组元素并为每个元素分配 space:

char** chunks = calloc(24, sizeof(char*));
for (i=0; i<24; i++) {
    chunks[i] = calloc(24, sizeof(char));
}

或者,您可以在复制前在 writecrite 中分配此内存:

void write(char** dest, char* src, int index) {
    int i = 0;
    dest[index] = calloc(24, sizeof(char));
    for (i = 0; src[i] != '[=14=]'; i++) {
        dest[index][i] = src[i];
    }
    dest[index][i] = '[=14=]';
    return;
}

void crite(char** dest, char src, int index) {
    int i = 0;
    dest[index] = calloc(2, sizeof(char));
    dest[index][0] = src;
    dest[index][1] = '[=14=]';
    return;
}

当我 运行 你的程序时,我收到 gdb 关于第 8 行的投诉(我的剪切和粘贴不起作用)

您的工具链似乎有一些严重的错误

你甚至可以编写 运行 一个 hello world 程序吗?

#include <stdio.h>
int main()
{
    printf("hello world\n");
}