【问题标题】:Memory corruption when freeing allocated string释放分配的字符串时内存损坏
【发布时间】:2017-05-22 13:57:36
【问题描述】:

当我尝试运行该程序时,我收到错误 malloc(): memory corruption。 该错误并非直接来自此函数,它发生在我尝试在此函数之后执行 malloc() 时。如果我删除了 free(ch) 行,它可以正常工作,所以我猜想当我尝试释放它时会发生损坏。 main() 是我如何使用该函数的示例。

char * makeInt(int val){ 
  char *res = malloc(5);
  char l [5] = "";
  sprintf(l,"%d",val);
  if(val < 10){
    strcat(res,"000");
    strcat(res,l);
  }
  else if(val < 100){
    strcat(res,"00");
    strcat(res,l);
  }
  else if(val < 1000){
    strcat(res,"0");
    strcat(res,l);
  }
  else if( val < 10000){
    strcat(res,l);
  }
  res[4] = '\0';
  return res;
}


  char * makeString(char *ch){
  int t = strlen(ch);
  char *chaine = malloc(t+4);
  char *nb = makeInt(t);
  strcat(chaine,nb);
  strcat(chaine,ch);
  chaine[t+4] = '\0';
  free(ch);
  return chaine;
}

int main(){
    char *path = malloc(100);
// here we do many operations on path, when i call makeString, path contains something
        path = makeString(path);
    }

编辑:抱歉,我发布的时候太晚了,我忘记了一些信息。 我添加了 makeInt()。关于包含,我将它们包含在我的代码中,但我认为错过的包含不会导致内存损坏,因为它会编译。此外,当我调用 makeString() 时,路径包含一个字符串。我在代码中的不同位置使用 makeString()。当我添加 free(ch) 时出现错误,但我不明白为什么释放 main 中分配的内存会导致内存损坏。

【问题讨论】:

  • strcat(chaine,nb); as chaine 内容尚未定义。 path 也一样。
  • 在 makeString() 中,您尝试确定“ch”的长度...在调用 makeString() 之前未初始化...正如上面确定的 @chux,malloc() 确实不初始化它为你分配的内存......要么你必须这样做,要么调用 calloc() 代替。
  • 发布的代码缺少#include 语句,因此无法编译。 (我们中的许多人不想猜测您的实际代码包含什么。
  • 您应该注意函数的返回类型以及您分配给什么类型的类型。例如,函数strlen() 返回一个size_t,并且发布的代码将其分配给int 类型。如果你在编译时打开警告,那么你的编译器会告诉你这些你应该在代码中修复的问题
  • C 数组索引是基于 0 的,所以这个 chaine[t+4] = '\0'; 写入数组的过去。

标签: c malloc free corruption


【解决方案1】:

贴出的代码包含一定的逻辑错误,例如:

strcat(chaine,nb);

但初始字符串必须有一个 NUL 字节,否则不知道会返回什么值(即未定义的行为)

malloc() 的返回值在第一个字符中可能有也可能没有 NUL 字节。

这可能是发布的代码导致段错误事件的原因。

(您可以通过使用calloc() 而不是malloc() 来解决这个特定问题

另外,makeString() 的参数未初始化为任何特定的以 NUL 结尾的字符串。所以将该参数传递给strlen() 是未定义的行为

(因为遇到的第一个 NUL 字节很可能超出了 'path 数组的末尾)

一些建议:

  1. 阅读该代码使用的任何系统函数的手册页。
  2. 单步执行任何代码(最好使用调试器)以查看其实际作用。

这里是可能适合您的代码版本。

#include <stdio.h>  // printf(), sprintf()
#include <stdlib.h> // malloc()
#include <string.h> // strlen(), strcat()

// prototypes
char * makeString(char *ch);


char * makeString(char *ch)
{
    // EDIT: this line was wrong: char *chaine = malloc(sizeof(ch) + 7)  // large enough to handle any int value
    char *chaine = malloc(strlen(ch) + 7);

    sprintf( chaine, "%4lu", strlen( ch ) );
    strcat( chaine, " " );
    strcat( chaine, ch );

    return chaine;  // the caller must call `free()`
} // end function: makeString


int main( void )
{
    char *path = "my path string";
    path = makeString(path);
    printf( "%s\n", path );
    free(path);
} // end function: main

输出是:

  14 my path string

【讨论】:

  • char *chaine = malloc(sizeof(ch) + 7); 错误。
  • 请重新考虑您的 malloc。指针的大小与此无关。你也应该使用snprintf 来避免缓冲区溢出(int 值可以超过 7 !)
  • 我更正了调用malloc()的问题
  • @M.M,由于所有字符串的长度都是已知的,因此使用“sprintf()”是一种安全操作。如果它们的长度未知,那么我会使用 snprintf(),并使用不同的格式字符串。
  • @user3629249 它会产生脆弱的代码 - 例如,如果有人更改 main 以从文件中读取字符串,然后其他人提供了一个包含 100,000 个字符长的字符串的文件,那么 @987654334 @ 突然出现缓冲区溢出。 IMO 最好默认使函数的正确性自包含
猜你喜欢
  • 2012-07-27
  • 2012-06-28
  • 2011-08-21
  • 2014-01-07
  • 2021-08-14
  • 1970-01-01
  • 1970-01-01
  • 2015-07-07
  • 1970-01-01
相关资源
最近更新 更多