0

I hope this is a clear explanation of my issue I've been runnign around various manuals for a little over a week now tryign to solve this:

Recently I have been redesigning a software design for a class project after feedback and testing on the STM32 Nucleo-F334R8(my initial code was riddled with memory and timing errors)

Currently I run into two main errors:

(This issue has been resolved)

I had been using sprintf not accounting for the trailing null character writting outside of allocated memory.

When processing USART Data using USART 1 in Asynchronous mode at 115200 Baudrate:

Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c08 in memset ()

Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c08 in memset ()

Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c08 in memset ()

Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c08 in memset ()

Program received signal SIGTRAP, Trace/breakpoint trap. 0x080056b4 in std.isra ()

The value stored at the address 0x08002c08 in question is usually very large typically something like 134228385 in decimal. Also if I forcefully step through the issue the program continues to run fine and never encounters the problem again which I find strange possible cause?

UPDATE: So I've traced the memset issue around a bit and found that it occurs during my setOutputBuffer method:

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] = '$';
} ```

(This issue has been resolved)

Essentially the source of my problem was misuse of sprintf and overwritting program code with null characters

I encountered a breakpoint trap while filling the bss segment of the board's memory

And after adding Seven GPIO Ports for a 4bit mode LCD(namely PA12, PA11, PB12, PB11, PB2, PB1, PB15) and two for a two channel ADC in DMA mode (PA1, PA0):

Program received signal SIGTRAP, Trace/breakpoint trap. LoopFillZerobss () at ..\startup/startup_stm32f334x8.s:103 103 cmp r2, r3 While trying to implement LCD and ADC functionality I receive the breakpoint trap error during the LoopFillZerobss function of startup which proved fatal, particularly by stopping my USART from reporting at all(however it can still receive bytes as interrupt and process tokens etc, just refuses to transmit), After reading up into the bss segment I attempted to solve the issue by initializing as many global variables as I could to non-zero values, this did not work, the problem is observed after adding the STM32CubeMx settings for ADC and the 7 GPIO pins used in the LCD, however none of these use unitialized variables to my knowledge unless the predefined code generated by CubeMX is going beyond the bounds of the bss segment of memory and that the size of the bss segment is too large now for the board's memory (which I suspect is unlikely but can't rule out).

Essentially the idea of this project is to receive various data over USART, ADC and later I2C and display various aspects of the data over USART and LCD at currently if I discard the ADC and LCD errors my USART code functions as the memset() error is non-lethal but I suspect that leaving it there is only causing me later issues but I'm also not sure where to fix my tokenizing code, assuming it is the root of my issues.

Ezra .M
  • 11
  • 5
  • The question, as it is, is too broad. You have given little to nothing about the error description. The `No source available for "memset() at 0x8002b6c"` is just your gui telling you, it has no sources for memset while debugging. This is kind of unrelated to your problem. There are many, many more information available from the stacktrace you are debugging. `Program received signal SIGTRAP` - means you have set a breakpoint while debugging in this particular lin of code. This is also kind of unrelated to your problem, it is just a breakpoint set by your debugger. – KamilCuk Apr 27 '19 at 07:57
  • Please provide an [MCVE](https://stackoverflow.com/help/mcve). Please indent your function. It would be good to post all the source code of your project. Your `tokenize` function is flawed in many ways, you don't check `token == NULL`, you cast length to int in malloc (?), you don't check if you reached end of string `*p != '\0'`, you just keep incrementing it, you pass uninitialized `token` to `parseToken` (?). Add `fprintf(stderr, "%d", (int)length);` before `if(length > 0)` and inspect it values. Inspect the stack (function stack and variables values) that followed to the crash. – KamilCuk Apr 27 '19 at 08:00
  • [Truestudio](https://www.youtube.com/watch?v=E52v1p6CN5A) is a good IDE for stm32 projects, you can find many help online how to deal with it. – KamilCuk Apr 27 '19 at 08:03
  • Hi thanks for the reply! I'll fix the function, thought my string array is oversized for the input I am passing to it(100) but my longest expected message is ~91 characters with a ' ' termination. As far as the errors go that's all I get out of TrueSTUDIO during the debugging process, the entire program hangs briefly and reports just those errors, I will also try do a full MCVE, I was hoping my mistake would be simper, I am back on looking at the code and might have found that the tokenize function isn't my problem. – Ezra .M Apr 27 '19 at 08:47
  • I am back on looking at the code and might have found that the token value is either not properly freeing or that `free` doesn't work the way I hope it does, becuase if I check if `token == NULL` the loop only runs once meaning that the `token` pointer isn't actually freed? – Ezra .M Apr 27 '19 at 08:54
  • I've updated the tokenize function and reflected the changes in an edit, however I still run into the same memset issue however I now have a few more issues popping up which I've also added. – Ezra .M Apr 27 '19 at 08:58
  • `sprintf(token, "%.*s",(int)length,p);` writes null termination character, which means it writes out of bounds. You should allocate `length + 1` characters. Use `snprintf`, always. `token == NULL` means literally you are "Out of memory" . The IDE gives you many more information than simple "errors". Compile with optimizations disable (or with `-Og`) that way you will be able to see the stack more verbosely. – KamilCuk Apr 27 '19 at 11:01
  • I can't believe I missed that thank you so much! that's been fixed now, I'll move on to sort out the ADC issues – Ezra .M Apr 27 '19 at 11:13
  • If you are trying to parse gnss data, why don't you use existing libraries, like `minmea`. Parsing nmea sentences is easy with `sscanf`. Just `if (sscanf(input_buffer, "$GNSSA,%s,%d,%d,....\r\n", &var1, &var2 ...) == 10) { printf("This is GNSSA"); } if (sscanf(input_buffer, "%GGA,%d,%d.....") ....`. Remember to correctly handle sscanf return code and with simple `if` and `sscanf` you can fast and reliably read nmea. To tokenize a string, just use `strtok`. – KamilCuk Apr 27 '19 at 11:13
  • We are not being allowed to use external libraries and part of the testing process for our code is to be able to process incomplete GPGGA strings, would the sscanf method still work correctly if an incomplete string were received? – Ezra .M Apr 27 '19 at 11:22
  • No, it would not. That's why you receive data into a buffer until a newline is encountered (even from an interrupt context). After a newline, you schedule parsing _the whole line_, as one chunk of the data. It's normal for I/O interfaces (looking at `FILE*`) to use line-buffering options - ie. buffer up to a newline, then parse whole line. – KamilCuk Apr 27 '19 at 13:00
  • I see thanks a lot for all the help! I've found my issues all lay in the misuse of `sprintf` overwritting null characters into my program memory it all works great now that I've double checked and replaced with `snprintf` where applicable again thanks a lot! – Ezra .M Apr 27 '19 at 15:53

1 Answers1

1

Essentially the source of my problem was misuse of sprintf and overwritting program code with null characters

By ensuring to use snprintf rather than sprintf with well defined sized strings I ran into no more memory issues.

Ezra .M
  • 11
  • 5
  • you will - after some time when you fragment the heap enough. uCs and mallocs are not the best friends – 0___________ Apr 27 '19 at 16:20
  • So what's the best solution long term? Though this is would be out of scope of my current project just for interest's sake – Ezra .M Apr 28 '19 at 01:20