调用strcpy后尝试释放内存会导致程序崩溃

Tag*_*agc 1 c microcontroller lpc

我知道很多人在这里抱怨strcpy,但我没有找到任何使用搜索来解决我的问题.

首先,调用strcpy本身不会导致任何类型的崩溃/分段错误.其次,代码包含在一个函数中,第一次调用这个函数它完美地运行.它只在第二次崩溃.

我正在用LPC1788微控制器编程; 内存非常有限,所以我可以看到为什么像malloc这样的东西可能会失败,但不是免费的.

函数trimMessage()包含代码,函数的目的是删除大字符串数组的一部分,如果它变得太大.

void trimMessage()
{
  int trimIndex;
  // currMessage is a globally declared char array that has already been malloc'd
  // and written to.
  size_t msgSize = strlen(currMessage);

  // Iterate through the array and find the first newline character. Everything
  // from the start of the array to this character represents the oldest 'message'
  // in the array, to be got rid of.
  for(int i=0; i < msgSize; i++)
  {
    if(currMessage[i] == '\n')
    {
      trimIndex = i;
      break;
    }
  }
  // e.g.: "\fProgram started\r\nHow are you?\r".
  char *trimMessage = (char*)malloc((msgSize - trimIndex - 1) * sizeof(char));

  trimMessage[0] = '\f';

  // trimTimes = the number of times this function has been called and fully executed.
  // freeing memory just below is non-sensical, but it works without crashing.
  //if(trimTimes == 1) { printf("This was called!\n"); free(trimMessage); }
  strcpy(&trimMessage[1], &currMessage[trimIndex+1]);

  // The following line will cause the program to crash. 
  if(trimTimes == 1) free(trimMessage);
  printf("trimMessage: >%s<\n", trimMessage);

  // Frees up the memory allocated to currMessage from last iteration
  // before assigning new memory.
  free(currMessage);
  currMessage = malloc((msgSize - trimIndex + 1) * sizeof(char));

  for(int i=0; i < msgSize - trimIndex; i++)
  {
    currMessage[i] = trimMessage[i];
  }

  currMessage[msgSize - trimIndex] = '\0';
  free(trimMessage);
  trimMessage = NULL;

  messageCount--;
  trimTimes++;
}
Run Code Online (Sandbox Code Playgroud)

谢谢所有帮助过的人.该功能现在正常工作.对于那些问我为什么要打印出一个我刚刚释放的数组的人,那只是为了表明问题发生在strcpy之后并排除了之后的任何其他代码.

最终的代码在这里,以防它对任何遇到类似问题的人都有用:

void trimMessage()
{
  int trimIndex;
  size_t msgSize = strlen(currMessage);

  char *newline = strchr(currMessage, '\n'); 
  if (!newline) return;
  trimIndex = newline - currMessage;

  // e.g.: "\fProgram started\r\nHow are you?\r".
  char *trimMessage = malloc(msgSize - trimIndex + 1);

  trimMessage[0] = '\f';
  strcpy(&trimMessage[1], &currMessage[trimIndex+1]);

  trimMessage[msgSize - trimIndex] = '\0';

  // Frees up the memory allocated to currMessage from last iteration
  // before assigning new memory.
  free(currMessage);
  currMessage = malloc(msgSize - trimIndex + 1);

  for(int i=0; i < msgSize - trimIndex; i++)
  {
    currMessage[i] = trimMessage[i];
  }

  currMessage[msgSize - trimIndex] = '\0';
  free(trimMessage);

  messageCount--;
}
Run Code Online (Sandbox Code Playgroud)

Tom*_*ner 10

如果堆已损坏或者传递无效指针,则free可以并且将崩溃.

看一下,我认为你的第一个malloc是几个字节短.您需要为空终止符保留一个字节,并且还要复制到偏移量1,因此需要为此保留另一个字节.所以会发生的情况是你的副本会在下一个堆块的开头覆盖信息(通常用于下一个堆块的长度以及是否使用它的指示,但这取决于你的RTL ).

当你接下来做一个免费的时候,它可能会尝试合并任何免费的块.不幸的是,你已经破坏了下一个块标题,此时它会有点疯狂.