【问题标题】:realloc(): invalid next size: followed by a 32bit registerrealloc():下一个大小无效:后跟一个 32 位寄存器
【发布时间】:2015-06-01 10:39:39
【问题描述】:

所以我一直在用 C 编写一个 mtf 编码器,无论我做什么,我都遇到了 realloc() 错误。我已经检查了我的逻辑中是否存在错误(并且可能存在错误),方法是使用 print 语句查看我是否超出了当前 malloc 数组的边界(添加一个字符串超过我的原始数组大小)这似乎不是问题。我使用过 GDB 和 Valgrind,当 Valgrind 遇到分段错误时,GDB 给了我一个神秘的消息。这是我第一次使用动态内存,我很困惑问题是什么,下面是我的代码以及 GDB 错误:

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

int count = 0;


move_to_front(int index, char** words){
    int i;
    char *t = words[index];

    for(i = index; i>1; i--){
       words[i] = words[i-1];
    }

    words[1] = t;

}


char** reallocate_words(char** words, int* words_size_pointer){
   printf("We're entering here\n");
   printf("%d", *words_size_pointer);
   int temp = *words_size_pointer;
   char** tempor;
   temp = temp*2;
   printf("%d", temp);
   tempor = (char**) realloc(words, temp);
   int i = *words_size_pointer;
   for(i; i<temp; i++){
       tempor[i] = (char*) malloc(120);
    }
   words_size_pointer = &temp;
   return tempor;

 }

void encode_word(int* words_size_pointer, FILE *f, char* word, char** words){
    if(count == 0){
        words[1] = word;
        fputs(words[1], f);
        count++;
    }
    int i;
    for(i=0; i<=count; i++){
        if(strcmp(words[i], word) == 0){
            break;
        }
    }
    if(i>=(*words_size_pointer)){
        printf("%d\n", i);
        words = reallocate_words(words, words_size_pointer);
        words[count+1] = word;
        count++;
        fputc(count+128, f);
        fputs(words[count], f);
        move_to_front(count, words);
    }
    if(i>count){
        words[count+1] = word;
        count++;
        fputc(count+128, f);
        fputs(words[count], f);
        move_to_front(count, words);
    }
    else{
        fputc(i+128, f);
        move_to_front(i, words);
    }



}

void sep_words(char** words, char *line, int* words_size_pointer, FILE *f){
    char* x;
    int i = 0;
    x = strtok(line, " ");
    while(x != NULL){
        encode_word(words_size_pointer,f, x, words);
        x = strtok(NULL, " ");
    }   
}


void readline(FILE *f_two, FILE *f, char** words, int* words_size_pointer){
    char *line;
    size_t len = 0;
    ssize_t temp;
    int count;
    do{
    temp = getline(&line,&len,f);
    printf("%s", line);
    if(temp!= -1){
        sep_words(words, line, words_size_pointer, f_two);

    }
    }while(temp!=-1);

}


int main(int argc, char *argv[]){
    int x;
    int i;
    int j;
    x = strlen(argv[1]);
    char fi[x];
    char mtf[3] = "mtf";
    FILE *f;
    FILE *f_two;
    for(j = 0; j<(x-3); j++){
       fi[j] = argv[1][j];
    }
    strcat(fi, mtf);
    f = fopen(argv[1], "r");
    f_two = fopen(fi, "w");
    fputc(0xFA, f_two);
    fputc(0XCE, f_two);
    fputc(0XFA, f_two);
    fputc(0XDF, f_two);
    if(f == NULL){
        return 1;
    }

    char** words;
    words = (char **) malloc(20);
    for(i = 0; i<20; i++){
        words[i] = (char*) malloc(120);
    }
    int words_size = 20;
    int* words_size_pointer = &words_size;

    readline(f_two, f, words, words_size_pointer);
    return 0;
}

至于 GDB 错误:

    *** Error in `/file_loc/mtfcoding2': realloc(): invalid next size: 0x0000000000603490 ***
2040 \\This is due to print statements within my function.
Program received signal SIGABRT, Aborted.
0x00007ffff7a4acc9 in __GI_raise (sig=sig@entry=6)
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56  ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.

感谢您的宝贵时间! :)

【问题讨论】:

  • printf() 调试并非万无一失。编译器可能会重新排序代码,并且输出通常是缓冲的,因此您可能无法以这种方式精确定位错误的位置。此外,内存损坏通常会在其原因发生后显着检测到。
  • 你会建议我做什么?
  • 如果在 Linux 上,请使用 valgrind
  • 我做到了,当它遇到重新分配功能时遇到了分段错误。
  • 老实说,您应该从编译时发出完整的警告开始。 gcc 也需要设置为优化,否则不会产生好的警告:gcc -Wall -Wextra -Wpedantic -O3 应该给出好的警告。

标签: c malloc dynamic-memory-allocation realloc


【解决方案1】:

mallocrealloc 需要 字节数 作为参数。但是,您正在编写如下代码:

char** words;
words = (char **) malloc(20);
for(i = 0; i<20; i++){
    words[i] = (char*) malloc(120);

您分配了20 字节,但随后写入了 20 个指针(这可能占用了80 字节)。要解决此问题,您需要计算存储 20 个指针需要多少字节。一个安全的方法是use malloc as recommended by SO:

words = malloc(20 * sizeof *words);

您在realloc 通话中遇到了同样的问题。


此行无效:words_size_pointer = &amp;temp;。也许您的意思是 *words_size_pointer = temp; 。确保您清楚地了解这两行之间的区别。

注意。可能还有其他错误。

【讨论】:

    【解决方案2】:

    好吧,首先,您的move_to_front 正在丢弃指针。这是一个非常糟糕的内存泄漏,鉴于 C 和内存泄漏的性质,可能是您的段错误的原因(目前)。你应该这样做

    for(i = index; i > 1; i--){
        char* tmp = words[i];
        words[i] = words[i-1];
        words[i-1] = tmp;
    }
    

    否则,您所做的就是用index 处的指针覆盖从indexwords[2] 的指针。另外,你似乎喜欢从 1 而不是 0 开始你的 words 数组。那些一个接一个的错误也会伤害你。

    另外(如我之前的评论中所述),words_size_pointer = &amp;temp; 不太正确。改为这样做*words_size_pointer = temp;。第一种方式只是本地指针重新赋值,但您希望更改反映在调用者的范围内,因此您必须取消引用指针并对其进行修改。

    【讨论】:

    • 感谢您的回答!我原来的 move_to_front 函数就是这样写的。但是我的教授发布了一个示例解决方案,我基本上复制了它。而且我想我是懒惰的,我忘了编辑从 0 到 1 的单词数组索引(他从位置 1 开始所有内容)。不幸的是,尽管这些都没有帮助我的 reallocate(): invalid next size error :(
    • 你知道吗,这可能是因为words_size_pointer = &amp;temp; 这样做而不是*words_size_pointer = temp;
    • 原因是,您的方式在本地设置指针。您希望更新反映在调用者的范围内,因此您需要取消引用变量并以这种方式设置它
    • @ZackSullivan 无关,“......他从位置 1 开始一切”我希望这不是 C 语言的正式课程。如果是这样,他不会用那个咒语给你任何好处。迟早,你必须接受语言的 0..(n-1) 意识形态,越早越好。
    • @EOF 会导致未定义的行为
    【解决方案3】:

    这似乎是您在 readline 函数中调用 getline 引起的。

    char *line;
    size_t len = 0;
    ...
    temp = getline(&line,&len,f);
    

    getline 要求lineNULL(在这种情况下len 的值被忽略)或line 必须是malloccallocrealloc 返回的指针.如果line 不是NULL,并且len 不够大,则通过调用realloc 调整line 的大小。这是关键点:line 指向了一些malloc 未返回的随机地址,因此getline 尝试使用realloc 来增加缓冲区大小,因为0 字节太小了。

    这里还有缓冲区溢出:

    char mtf[3] = "mtf";
    ...
    for(j = 0; j<(x-3); j++){
       fi[j] = argv[1][j];
    }
    strcat(fi, mtf);
    

    因为您使mtf 的大小只有 3 个字节,所以它后面可能紧跟也可能不紧跟空终止符。当strcat 被调用时,如果mtf 后面没有紧跟内存中的0 字节,你最终会得到类似sample.mtf\x1b\x01X 作为输出文件名,假设你没有写太远超出结尾fi 数组使用 SIGSEGV (segfault) 使程序崩溃。以下任何一项都会纠正它:

    char mtf[4] = "mtf";
    //OR
    char mtf[] = "mtf";
    //OR
    const char *mtf = "mtf";
    

    但是,由于fi 仅由x 字节数组成,因此您最终将使用strcat 添加的空终止符写入fi[x]。这是一个问题,因为char fi[x]; 意味着您只有数组索引 0 到 x - 1 可用。使用x = strlen(argv[1]) + 1 修复此部分。

    【讨论】:

      猜你喜欢
      • 2020-12-27
      • 1970-01-01
      • 2014-10-13
      • 2015-01-22
      • 1970-01-01
      • 2011-02-25
      • 2012-10-31
      相关资源
      最近更新 更多