【问题标题】:Code is causing segmentation fault when allocating memory or aborts program when freeing memory代码在分配内存时导致分段错误或在释放内存时中止程序
【发布时间】:2013-08-01 18:44:40
【问题描述】:

当我尝试运行我的代码时,它会导致第 89 行的 malloc 出现分段错误,并显示“s1 = malloc(65536);”即使我将其更改为 calloc 或 realloc 也会持续存在,并且如果我有函数在第 82 行或第 86 行释放内存,它也会导致写入:

*** glibc detected *** /home/purlox/whaat: free(): invalid next size (normal): 0x00000000017b32b0 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7ff4f61aeb96]
/home/purlox/whaat[0x400904]
/home/purlox/whaat[0x4024de]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7ff4f615176d]
/home/purlox/whaat[0x400699]
======= Memory map: ========
00400000-00404000 r-xp 00000000 00:15 524713                             /home/purlox/whaat
00603000-00604000 r--p 00003000 00:15 524713                             /home/purlox/whaat
00604000-00605000 rw-p 00004000 00:15 524713                             /home/purlox/whaat
01793000-017b4000 rw-p 00000000 00:00 0                                  [heap]
7ff4f5f18000-7ff4f5f2d000 r-xp 00000000 08:05 4066792                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7ff4f5f2d000-7ff4f612c000 ---p 00015000 08:05 4066792                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7ff4f612c000-7ff4f612d000 r--p 00014000 08:05 4066792                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7ff4f612d000-7ff4f612e000 rw-p 00015000 08:05 4066792                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7ff4f6130000-7ff4f62e5000 r-xp 00000000 08:05 4067023                    /lib/x86_64-linux-gnu/libc-2.15.so
7ff4f62e5000-7ff4f64e4000 ---p 001b5000 08:05 4067023                    /lib/x86_64-linux-gnu/libc-2.15.so
7ff4f64e4000-7ff4f64e8000 r--p 001b4000 08:05 4067023                    /lib/x86_64-linux-gnu/libc-2.15.so
7ff4f64e8000-7ff4f64ea000 rw-p 001b8000 08:05 4067023                    /lib/x86_64-linux-gnu/libc-2.15.so
7ff4f64ea000-7ff4f64ef000 rw-p 00000000 00:00 0 
7ff4f64f0000-7ff4f6512000 r-xp 00000000 08:05 4067008                    /lib/x86_64-linux-gnu/ld-2.15.so
7ff4f6712000-7ff4f6713000 r--p 00022000 08:05 4067008                    /lib/x86_64-linux-gnu/ld-2.15.so
7ff4f6713000-7ff4f6715000 rw-p 00023000 08:05 4067008                    /lib/x86_64-linux-gnu/ld-2.15.so
7ff4f6715000-7ff4f671b000 rw-p 00000000 00:00 0 
7fffa991c000-7fffa993f000 rw-p 00000000 00:00 0                          [stack]
7fffa9a00000-7fffa9a01000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted (core dumped)

gdb 说 "free(str->string);"造成的,但我不确定如何。分配内存的错误只发生在一个特定的地方,我尝试将分配的内存大小更改为比现在更多或更少(例如,我尝试仅分配 8 个字节,或者我尝试分配 100 倍于现在的内存),但它仍然导致相同的分段错误。

whaat.c

#include "sstring.h"
#include <string.h>
#include <stdio.h>

int main(void) {
    char* s1,
                s2;

// 12 byte long strings
    char s3[8] = "Nequeou",
             s4[8] = "quisqua";

// 256 byte long strings
    char s5[256] = "Pellentesque venenatis rhoncus urna id tincidunt. Quisque blandit rhoncus nisi, vel facilisis odio ornare nec. Maecenas id tellus sit amet nunc auctor commodo. Proin egestas molestie malesuada. Vestibulum in lacus quis nisl ultricies cursus non ac nullam.",
             s6[256] = "Sed tristique porta lorem. Ut elementum est in magna laoreet, in lacinia ante blandit. Vestibulum condimentum sem vel ligula feugiat, vel venenatis ante placerat. Phasellus nec turpis viverra sapien vehicula sagittis vitae tincidunt lectus. Fusce posuere.";

// 65 536 byte long strings
    char s7[65536],
             s8[65536];

    s_string ss1,
                     ss2,

                     ss3,
                     ss4,

                     ss5,
                     ss6,

                     ss7,
                     ss8;

    FILE *LoremIpsum;
    int i;

    s_init(&ss3, "Nequeou ", 8);
    s_init(&ss4, "quisqua ", 8);
    s_init(&ss5, "Pellentesque venenatis rhoncus urna id tincidunt. Quisque blandit rhoncus nisi, vel facilisis odio ornare nec. Maecenas id tellus sit amet nunc auctor commodo. Proin egestas molestie malesuada. Vestibulum in lacus quis nisl ultricies cursus non ac nullam. ", 256);
    s_init(&ss6, "Sed tristique porta lorem. Ut elementum est in magna laoreet, in lacinia ante blandit. Vestibulum condimentum sem vel ligula feugiat, vel venenatis ante placerat. Phasellus nec turpis viverra sapien vehicula sagittis vitae tincidunt lectus. Fusce posuere. ", 256);
    s_init(&ss7, NULL, 65536);
    s_init(&ss8, NULL, 65536);

    LoremIpsum = fopen("Lorem ipsum", "r");
    if(LoremIpsum == NULL) {
        perror("Error opening file ");
        return 1;
    }

    fgets(s7, 65536, LoremIpsum);
    fgets(s8, 65536, LoremIpsum);
    fgets(ss7.string, 65536, LoremIpsum);
    ss7.string[65535] = ' ';
    fgets(ss8.string, 65536, LoremIpsum);
    ss8.string[65535] = ' ';

    if(fclose(LoremIpsum) == EOF) {
        perror("Error closing file ");
        return 2;
    }

    s1 = malloc(8);
    strcpy(s1, "");
    strcat(s1, s3);
    free(s1);

    s_init(&ss1, NULL, 8);
    s_strcat(&ss1, &ss3);
    s_free(&ss1);

    s_init(&ss1, NULL, 8);
    s_strcat2(&ss1, &ss3);
    s_free(&ss1);


    s1 = malloc(256);
    strcpy(s1, "");
    strcat(s1, s5);
    free(s1);

    s_init(&ss1, NULL, 256);
    s_strcat(&ss1, &ss5);
    s_free(&ss1);

    s_init(&ss1, NULL, 256);
    s_strcat2(&ss1, &ss5);
    s_free(&ss1);


    s1 = malloc(65536);
    strcpy(s1, "");
    strcat(s1, s7);
    free(s1);

    s_init(&ss1, NULL, 65536);
    s_strcat(&ss1, &ss7);
    s_free(&ss1);

    s_init(&ss1, NULL, 65536);
    s_strcat2(&ss1, &ss7);
    s_free(&ss1);

    s_free(&ss3);
    s_free(&ss4);
    s_free(&ss5);
    s_free(&ss6);
    s_free(&ss7);
    s_free(&ss8);

    return 0;
}

字符串.h

#include <stdlib.h>

typedef struct {
    unsigned int length;
    char *string;
} s_string;

s_string *s_init(s_string *str, char *array, size_t num) {
    int i;

    if(str == NULL) 
        str = malloc(sizeof(s_string));

    if(array == NULL) {
        str->length = num;

        if(num != 0)
            str->string = malloc(num);
        else
            str->string = NULL;
    } else {
        if(num == 0) {
            str->string = NULL;

            for(i = 0; array[i] != '\0'; i++) {
                str->string = realloc((void *)(str->string), i + 1);
                str->string[i] = array[i];
            }

            str->length = i;
        } else {
            str->string = malloc(num);

            str->length = num;

            for(i = 0; i < num; i++)
                str->string[i] = array[i];
        }
    }

    return str;
}

void s_free(s_string* str) {
  if(str != NULL  &&  str->string != NULL) {
    free(str->string);
    str->length = 0;
  }
}

s_string *s_strcat(s_string *destination, const s_string *source) {
    int i,
            j;

    for(i = destination->length, j = 0; j < source->length; i++, j++)
        destination->string[i] = source->string[j];

    destination->length += source->length;

    return destination;
}

// second version
s_string *s_strcat2(s_string *destination, const s_string *source) {
    int i;

    for(i = 0; i < source->length; i++)
        destination->string[i + destination->length] = source->string[i];

    destination->length += source->length;

    return destination;
}

【问题讨论】:

    标签: c memory-management segmentation-fault free


    【解决方案1】:

    考虑使用s_strcat() 进行的第一个测试:

        s_init(&ss1, NULL, 8);
        s_strcat(&ss1, &ss3);
    

    s_init() 的末尾,ss1 被初始化为分配 8 个字节的内存。

       if(array == NULL) {
            str->length = num;
    
            if(num != 0)
                str->string = malloc(num);
    

    但是,s_strcat() 被实现到分配内存的末尾,并从ss3 复制数据:

        for(i = destination->length, j = 0; j < source->length; i++, j++)
            destination->string[i] = source->string[j];
    

    该循环正在写入超出分配内存的末尾,破坏了malloc() 和朋友使用的堆数据结构。

    s_strcat2()也有类似的问题,写超出destination-&gt;length,代表分配内存的大小。

        for(i = 0; i < source->length; i++)
            destination->string[i + destination->length] = source->string[i];
    

    您可以使用valgrind 等内存调试工具更轻松地调试此类问题。 valgrind 可以帮助您识别软件中存在与内存相关的错误的代码行,例如写入未分配的内存、写入超出分配的内存以及释放未分配的内存。

    【讨论】:

    • 提及内存调试器(例如 valgrind)会使这个答案变得完美。来自我的 +1 :)
    • 谢谢,我没有意识到这一点,因为我假设源的长度总是更小,这不一定是真的,但即使在 s_strcat 和 s_strcat2 中都将其更正为检查两个长度,它仍然会导致与以前相同的错误,所以我认为这不是问题所在。我会尝试 valgrid 看看它是否可以帮助我找到问题。
    • Nvm,它现在以某种方式修复了。不知道为什么,但你可能提供了帮助。
    猜你喜欢
    • 2021-08-23
    • 2020-03-14
    • 2014-04-02
    • 2018-09-18
    • 2012-11-12
    • 1970-01-01
    • 1970-01-01
    • 2021-05-12
    • 1970-01-01
    相关资源
    最近更新 更多