首页 > 解决方案 > 程序在 GDB 中运行,但如果正常启动会引发分段错误

问题描述

程序应该遍历最后一个 CLI 参数中指定的目录中的所有文件,并将它们的名称和 MD5 和写入database二进制文件。每次迭代一个条目。我解决了所有错误和警告,但它仍然引发分段错误。database二进制文件保持为空,但被创建。但是,它在具有相同参数的 GDB 中工作,我可以看到database填充数据。WSL Ubuntu 18.04

如何使其正常工作?

这是源文件:

#include <dirent.h>
#include <openssl/md5.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

typedef struct dbEntry {
        unsigned int id;
        char* name;
        char* type;
        unsigned int parent_id;
        unsigned char* md5;
} dbEntry;

void md5digest(FILE* file, unsigned char* dest) {
        MD5_CTX md5handler;
        int bytes;
        void* data = 0;
        unsigned char md5digest[MD5_DIGEST_LENGTH];

        MD5_Init(&md5handler);
        while ((bytes = fread(data, 1, 10, file) != 0)) {
                if (data != 0){
                        MD5_Update(&md5handler, data, 10);
                }
        }
        MD5_Final(md5digest, &md5handler);
        strcpy((char*)dest, (char*)md5digest);
}

int main(int argc, const char** argv) {
        if (strcmp(argv[1], "-s") == 0 && strcmp(argv[2], "-f") == 0 &&
            argc == 5) {
                FILE* database = fopen(argv[3], "ab+");
                DIR* dir = opendir(argv[4]);
                struct dirent* dirent = readdir(dir);
                unsigned int id = 0;
                dbEntry entry;
                while (dirent != NULL) {
                        if (dirent->d_type == 8) {
                                entry.id = id;
                                entry.name = dirent->d_name;
                                entry.type = "file";
                                entry.parent_id = 0;
                                const size_t len = strlen(argv[4]) + strlen(entry.name);
                                char* fpath = malloc(sizeof(char)*len);
                                strcpy(fpath, argv[4]);
                                strcat(fpath, entry.name);
                                printf("%s\n", fpath);
                                FILE* file = fopen(fpath, "rb");
                                if (file != NULL){
                                        md5digest(file, entry.md5);
                                        fclose(file);
                                        fwrite(&entry, sizeof(dbEntry), 1, database);
                                }
                                else{
                                      printf("Error opening file %s\n", entry.name);
                                      fpath[0] = '\0';
                                }
                                id++;
                        }
                        dirent = readdir(dir);
                }
                fclose(database);
        }
        return 0;
}

GDB 输出:

altbrace@altbrace-PC:~/csc-integrctrl/src$ ls -lh
total 148K
-rw-rw-rw- 1 altbrace altbrace    0 Apr 16 22:14 database
-rwxrwxrwx 1 altbrace altbrace  63K Apr 16 22:09 integrctrl
-rw-rw-rw- 1 altbrace altbrace 1.6K Apr 16 22:09 main.c
altbrace@altbrace-PC:~/csc-integrctrl/src$ gdb ./integrctrl
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./integrctrl...done.
(gdb) set args -s -f database /home/altbrace/
(gdb) r
Starting program: /home/altbrace/csc-integrctrl/src/integrctrl -s -f database /home/altbrace/
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
/home/altbrace/.bash_history
/home/altbrace/.bash_logout
/home/altbrace/.bashrc
/home/altbrace/.bashrc.backup
/home/altbrace/.gitconfig
/home/altbrace/.mysql_history
Error opening file .mysql_history
/home/altbrace/.profile
/home/altbrace/.python_history
/home/altbrace/.sudo_as_admin_successful
/home/altbrace/.viminfo
/home/altbrace/.vimrc
/home/altbrace/.wget-hsts
/home/altbrace/Makefile
/home/altbrace/main.c
/home/altbrace/test.py
[Inferior 1 (process 18767) exited normally]
(gdb) q
altbrace@altbrace-PC:~/csc-integrctrl/src$ ls -lh
total 148K
-rw-rw-rw- 1 altbrace altbrace  560 Apr 16 22:14 database
-rwxrwxrwx 1 altbrace altbrace  63K Apr 16 22:09 integrctrl
-rw-rw-rw- 1 altbrace altbrace 1.6K Apr 16 22:09 main.c

分段故障:

altbrace@altbrace-PC:~/csc-integrctrl/src$ ls -lh
total 148K
-rw-rw-rw- 1 altbrace altbrace  560 Apr 16 22:14 database
-rwxrwxrwx 1 altbrace altbrace  63K Apr 16 22:09 integrctrl
-rw-rw-rw- 1 altbrace altbrace 2.2K Apr 16 23:32 main.c
altbrace@altbrace-PC:~/csc-integrctrl/src$ rm database
altbrace@altbrace-PC:~/csc-integrctrl/src$ ./integrctrl -s -f database /home/altbrace/
/home/altbrace/.bash_history
Segmentation fault (core dumped)
altbrace@altbrace-PC:~/csc-integrctrl/src$

标签: csegmentation-faultgdbwindows-subsystem-for-linux

解决方案


构建程序gcc -g t.c -lcrypto -fsanitize=address显示它有一个堆缓冲区溢出:

=================================================================
==77421==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x607000000144 at pc 0x7f92565d35f3 bp 0x7fff262b40a0 sp 0x7fff262b3850
WRITE of size 65 at 0x607000000144 thread T0
    #0 0x7f92565d35f2 in __interceptor_strcat (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xa95f2)
    #1 0x55d3cc70f84c in main /tmp/t.c:49
    #2 0x7f92560a5bba in __libc_start_main ../csu/libc-start.c:308
    #3 0x55d3cc70f219 in _start (/tmp/a.out+0x1219)

0x607000000144 is located 0 bytes to the right of 68-byte region [0x607000000100,0x607000000144)
allocated by thread T0 here:
    #0 0x7f9256631538 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x107538)
    #1 0x55d3cc70f7ef in main /tmp/t.c:47
    #2 0x7f92560a5bba in __libc_start_main ../csu/libc-start.c:308

SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xa95f2) in __interceptor_strcat

您忘记添加 1 len(这是 terminating 所需的NUL)。修复此错误可能会使程序正常工作。


推荐阅读