修复可能由于 STM32 Nucleo-F334R8 上的 malloc 导致的内存覆盖错误

Posted

技术标签:

【中文标题】修复可能由于 STM32 Nucleo-F334R8 上的 malloc 导致的内存覆盖错误【英文标题】:Fixing a Memory Overwrite errors likely due to malloc on an STM32 Nucleo-F334R8 【发布时间】:2019-09-16 12:17:51 【问题描述】:

我希望这是对我的问题的清晰解释,我已经围绕各种手册运行了一个多星期,现在尝试解决这个问题:

最近在反馈和测试 STM32 Nucleo-F334R8 后,我一直在为一个班级项目重新设计软件设计(我的初始代码充满了内存和时序错误)

目前我遇到两个主要错误:

(此问题已解决)

我一直在使用 sprintf 没有考虑写入分配内存之外的尾随空字符。

在异步模式下使用 USART 1 处理 USART 数据时 115200 波特率:

程序收到信号SIGTRAP,跟踪/断点陷阱。 0x08002c08 在 memset()

程序收到信号SIGTRAP,跟踪/断点陷阱。 0x08002c08 在 memset()

程序收到信号SIGTRAP,跟踪/断点陷阱。 0x08002c08 在 memset()

程序收到信号SIGTRAP,跟踪/断点陷阱。 0x08002c08 在 memset()

程序收到信号SIGTRAP,跟踪/断点陷阱。 0x080056b4 在 std.isra()

存储在地址 0x08002c08 的值通常非常 大通常类似于十进制的 134228385。另外如果我 强行解决问题,程序继续正常运行 并且 再也不会遇到这个问题,我觉得这很奇怪 可能的原因?

更新:所以 我已经跟踪了一下 memset 问题,发现它发生了 在我的setOutputBuffer 方法中:

String>,%5d,%8s,%3d,%3d,%3d,%4d,%4d,%4d,%10.6f,%11.6f,%7.1f,%3d,%3.1f\n",uptime,timeString,temperature,pressure,humidity,acc1,acc2,acc3,latitude,longitude,altitude,current,voltage);
 ``` Which leads me to believe the issue lies in finding a value that
is being used to set the Output buffer message.

I would like advice on how to further troubleshoot these two issues
and whether there is a chance that the memset error is related the
later bss error.

My String Tokenizing code(edited):

```c void tokenize(char* in)     const char *p = in;     const char 
delim[] = ",";    char *token = NULL;     uint8_t n = 0;

  do

      size_t length = strcspn(p, delim);      if(length > 0)             if(token ==
NULL)
              token = malloc(sizeof(char)*length); // create memory space for the token
              memset(token, 0, length); // ensure initialized memory is blank
              sprintf(token, "%.*s",(int)length,p); // store the token from a substring of Input Buffer
              p+=length; // move pointer to next ','
              parseToken(token, n); // extract information from the token be it latitude, longitude etc
              memset(token, 0, length); // clear the token
              free(token); // free up the token's spot in memory
              token = NULL; // set token pointer to null
              n++;            

      


  while(*((++p)+1) != '*'); // The expected string ends with a
checksum character '*' after the last ','  ``` I've re-examined the
function and made a lot of changes now I can successfully step through
the entire function without issue, the program then returns to my main
loop, and I let it run for a while but then I suddenly run back into
the same memset issue, even without receiving any bytes over USART
here is the code for my main loop and the subsequent function calls it
makes:

```c

  while (1)   
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

      if (byteFlag)          byteRecieved();             byteFlag = 0;       

      if(msgFlag)            msgRecieved();          msgFlag = 0;        

      if(secFlag)            setOutputBuffer();          HAL_UART_Transmit(&huart1,
(uint8_t *)bufferOut, 91, 1000);          secFlag = 0;        

   ``` byteReceived: ```c if((char) byteIn == '$')
      clearInputBuffer();      else if((char) byteIn == '\n')

      msgFlag = 1;    

  else       storeChar();     ```

msgReceived: ```c if(isValid())      if (checksum()) 
          tokenize(bufferIn);             clearInputBuffer();             ```

isValid: ```c char substr[5];     strncpy(substr, (bufferIn+1), 5);
  if(!strcmp(substr, "GPGGA"))       return 1;   

  return 0; ```

checksum: ```c int checksum()    int calc_checksum = 0;  int
in_checksum;  int i = 0;  char checkstr[2];   uint8_t hasCheckSum = 0;

  for(int j = 0; j<91; j++)      if (bufferIn[j] == '*')            hasCheckSum
= 1;          i = 1;         

  if (hasCheckSum)       while (bufferIn[i] != '*')             calc_checksum ^=
bufferIn[i];          i++;               checkstr[0] = bufferIn[i+1];        checkstr[1]
= bufferIn[i+2];   else return 0;



  in_checksum = parseStr_HexToInt(checkstr);

  if (calc_checksum == in_checksum)      return 1;    else         return 0;
    ```

clearInputBuffer: ```c void clearInputBuffer()   int i = 0;

  for(i = 0; i < 100; i++)       bufferIn[i] = ' ';     bufferIn[0] = '$';
 ```

(此问题已解决)

基本上我的问题的根源是滥用sprintf 并用空字符覆盖程序代码

我在填充 bss 段时遇到了断点陷阱 主板内存

在为 4bit 模式 LCD(即 PA12, PA11、PB12、PB11、PB2、PB1、PB15)和两个用于 DMA 中的两通道 ADC 模式(PA1,PA0):

程序收到信号SIGTRAP,跟踪/断点陷阱。 LoopF​​illZerobss () at ..\startup/startup_stm32f334x8.s:103 103 cmp r2, r3 在尝试实现 LCD 和 ADC 功能时,我在 LoopF​​illZerobss 函数期间收到断点陷阱错误 被证明是致命的的创业公司,尤其是通过停止我的 USART 完全没有报告(但是 它仍然可以接收字节为 中断和处理令牌等,只是拒绝传输),之后 阅读到 bss 段我试图解决这个问题 将尽可能多的全局变量初始化为非零值, 这不起作用,添加后观察到问题 用于 ADC 的 STM32CubeMx 设置和 LCD 中使用的 7 个 GPIO 引脚, 但是据我所知,这些都没有使用统一变量 除非 CubeMX 生成的预定义代码超出 bss 内存段的边界和 bss 的大小 段现在对于主板的内存来说太大了(我怀疑是 不太可能,但不能排除)。

基本上这个项目的想法是通过 USART、ADC 和后来的 I2C 接收各种数据,并在当前通过 USART 和 LCD 显示数据的各个方面,如果我丢弃 ADC 和 LCD 错误,我的 USART 代码用作 memset( ) 错误是非致命的,但我怀疑将其留在那里只会导致我以后出现问题,但我也不确定在哪里修复我的标记化代码,假设它是我问题的根源。

【问题讨论】:

这个问题太宽泛了。您几乎没有给出错误描述。 No source available for "memset() at 0x8002b6c" 只是你的 gui 告诉你的,它在调试时没有 memset 的来源。这与您的问题无关。您正在调试的堆栈跟踪中有很多很多可用的信息。 Program received signal SIGTRAP - 表示您在调试此特定代码行时设置了断点。这也与您的问题无关,它只是您的调试器设置的断点。 请提供MCVE。请缩进你的函数。最好发布您项目的所有源代码。你的tokenize 函数在很多方面都有缺陷,你不检查token == NULL,你在malloc(?)中将长度转换为int,你不检查你是否到达字符串结尾*p != '\0',你只是不断增加它,你将未初始化的token 传递给parseToken (?)。在if(length &gt; 0) 之前添加fprintf(stderr, "%d", (int)length); 并检查它的值。检查崩溃后的堆栈(函数堆栈和变量值)。 Truestudio 是一个很好的 stm32 项目的 IDE,你可以在网上找到很多关于如何处理它的帮助。 您好,感谢您的回复!我将修复该函数,认为我的字符串数组对于我传递给它的输入来说过大(100),但我最长的预期消息是 ~91 个字符,带有 ' ' 终止。就错误而言,这就是我在调试过程中从 TrueSTUDIO 中得到的所有错误,整个程序短暂挂起并仅报告这些错误,我还将尝试做一个完整的 MCVE,我希望我的错误会更简单,我回来了在查看代码时,可能发现 tokenize 函数不是我的问题。 我重新查看代码,可能发现令牌值没有正确释放或者free 没有按我希望的方式工作,因为如果我检查是否token == NULL 循环只运行一次,这意味着 token 指针实际上并没有被释放? 【参考方案1】:

基本上我的问题的根源是滥用 sprintf 和用空字符覆盖程序代码

通过确保使用snprintf 而不是sprintf 来定义大小明确的字符串,我不再遇到内存问题。

【讨论】:

你会 - 一段时间后,当你对堆进行足够的碎片化时。 uCs 和 mallocs 不是最好的朋友 那么长期的最佳解决方案是什么?尽管出于兴趣考虑,这超出了我当前项目的范围

以上是关于修复可能由于 STM32 Nucleo-F334R8 上的 malloc 导致的内存覆盖错误的主要内容,如果未能解决你的问题,请参考以下文章

从 STM32 Nucleo-F767ZI [Ubuntu] 中的 USB 虚拟 COM 读取数据

NUCLEO STM32F334R8 上的 STMCubeIDE,新项目:FreeRTOS 硬故障

使用 HAL 的 NUCLEO-F303K8 上的 DMA 不当行为

stm32f303支持蓝牙4.0么

stm32f7的串口TX如何设置

STM32F412应用开发笔记之五:结合W5500实现以太网通讯