在函数内部进行malloc后,从函数中释放返回的指针会导致芯片崩溃

时间:2017-06-24 06:42:35

标签: c++ pointers stm32

我在主

中有这个电话
char* IDQueueString = getIDQueue();
pc.printf("[%9.6f] IDQueue: %s\r\n", t.read(), IDQueueString);
free(IDQueueString);

getIDQueue();是

char* getIDQueue(void)
{
    char* returnString;
    char idString[6];
    uint8_t pointer = 0;
    uint8_t queueLength = 0;
    returnString = (char*)malloc((uint32_t)(sizeof(char*)*128));
    if(returnString != 0){
        pc.printf("[%9.6f] MALLOC: %p, len: %d | LINE %d\r\n", t.read(), returnString, (int)(sizeof(char*)*128), __LINE__);
        for(uint8_t i = 0; i < ID_QUEUE_LENGTH; i ++){
            if(ReceivedIDs[i].id != -1){
                queueLength++;
                sprintf(idString, "%d", (int)ReceivedIDs[i].id);
                for(uint8_t j = 0; j < strlen(idString); j++){
                    returnString[pointer] = idString[j];
                    pointer++;
                }
                returnString[pointer++] = ',';
                returnString[pointer++] = ' ';
            }
        }
        if(queueLength > 0){
            returnString[pointer-2] = '.';
            returnString[pointer-1] = '\0';
        }
        if(queueLength == 0){
            returnString = (char*)"Empty!";
        }
        return returnString;
    }else{
        free(returnString);
        error("\x1b[31mMALLOC %d!\x1b[0m\r\n", __LINE__);
        return (char*)"MALLOC!";
    }
}

当它在二进制文件中达到free(IDQueueString);时,它会在指令链的某处执行:

0x08009d6c:   ldr     r6, [r1, #8]  // *0x2000a208, *0x20008500
0x08009d6e:   ldr     r0, [r2, #4]  // *0x200080d8, *0x1002db40
0x08009d70:   cmp     r2, r6        // *0x1002db40, *0x2000a208

但是它挂起在0x08009d6e(或者更确切地说是返回到一个循环自身的WIRQ循环

0x08004ffc:   b.n     0x8004ffc

我想知道是什么导致它这样做的? 显然free();导致问题,但我无法弄清问题是什么。 r1r2的值为0x00000000r00x00000009r60x5DECC885

地址0x20000001-0x2001BFFF (112KB)是SRAM1的范围,0x2001C000-0x2001FFFF (16KB)是SRAM2的范围。

我不知道0x5DECC885的价值是什么,但它可能与USB-OCD接口有关。

我假设我使用free的方式不正确但是因为我返回指向malloc();的指针,为什么我不能按照我想要的方式释放返回的指针?

2 个答案:

答案 0 :(得分:1)

你不能免除那些来自malloc的东西 - 它是&#34;未定义的行为&#34;这样做,所以取决于运行时的设计方式,实际发生的事情是&#34;一切皆有可能&#34;它可能会挂起,崩溃,通过向特朗普签署的普京发送粗鲁的信息来开始核战争,或者是&#34;很好&#34;。

您的特定情况有两种解决方案:

如果malloc失败,请返回NULL(如果我们在C ++中,则返回nullptr)。如果队列为空,则返回一个malloc&#39; d字符串,其中包含字符串&#34; Empty!&#34; (通过赋值strcpy或类似)。

或者,这只有在您知道队列不包含"Empty!""MALLOC!"等字词时才有效:在您致电free之前,请检查它是否为&# 39; t其中一个字符串(使用if(strcmp("Emtpy!", ...) != 0 && strcmp("MALLOC!", ...) != 0) free(...);

通过在已知字符串列表中包含这些字符串可以使这更容易,并且只返回该条目,然后您可以使用一个函数来检查&#34;它是一个已知的常量字符串&#34;通过比较指针值本身。 [事实上,当您正在处理的内容中存在相同的内容字符串时,这也会起作用,因为如果来自您的代码,内容字符串将具有不同的地址] - 它还有助于避免&#34的问题;哦,我更改了返回字符串的值,但没有更改自由之前的检查&#34;,因为它只是一个可供机器人使用的地方。

答案 1 :(得分:0)

每当我看到拆解列表时,我就会知道它会是愚蠢的。错误的程序逻辑 - 但编译器必须是错误的:)

在函数调用之前分配内存是一件好事。返回前应释放所有本地malloc。它使调试代码变得更容易(特别是内存泄漏)。

你有很多方式与程序的另一部分进行通信,但你选择的那个是最糟糕的。首先,将错误(如失败的mallocs)与应用程序异常(例如空名称)分开是很好的。我自己会让这个函数返回int(例如负数作为系统错误,如果OK则为零,对应用程序异常为正) - 使得处理它们更容易,并且指针通过指针返回指针。 但是你想在函数中使用malloc(并且不要自由) -

if((resultCode = getIDQueue(& IDQueueString) >= 0)
{
   // do something (you can have another switch here to deal with application exceptions like empty name for example)
   free(IDQueueString);
}
else
{
 switch (resultCode) 
 {
   case -1:
     // do something malloc failed
     break:
   case -2:
     //deal with another error 
     break;
  //...... etc etc 
   default:
     // ----
     break;
 }
}