Understanding C Language Rules to Avoid Code Issues

We have a product that requires LED lights to flash in sync. The area controller (in an STM32 microcontroller environment) sends wireless signals based on GPS signals to control the start time of the light flashes, achieving synchronization. A colleague implemented a function to send wireless signals, similar to the following:

int RS232_lora_sendAlignInfo(void){    uint8_t send_buf[] = {0xAA, 0xBB, 0xCC};    HAL_UART_Transmit_IT(&Uart2Handle, send_buf, 3);    return 0;}

It was found that sometimes it did not send as expected. Packet capture revealed that the intended data 0xAA, 0xBB, 0xCC was sometimes sent as 0xAA, 0xBB, 0x00. When my colleague asked me to analyze it, I smiled knowingly; this is a classic issue related to the lifecycle of local variables. The data to be sent is stored in the local variable send_buf, which is assigned to the pTxBuffPtr pointer of the serial handle in the implementation of the HAL_UART_Transmit_IT function (the length of the data to be sent is assigned to TxXferCount), and the data is handed over to the microcontroller’s interrupt function for automatic processing (provided that the send interrupt was enabled beforehand). When RS232_lora_sendAlignInfo returns, the entire stack frame of the function is reclaimed, and the 3 bytes of space occupied by send_buf are also reclaimed, causing the pTxBuffPtr pointer to point to an “invalid” memory address, becoming a “dangling pointer.” When the serial rate is relatively slow (in this case, we set the serial baud rate to 9600), the data has not been fully sent, and the contents of other function call stacks may overwrite the area where send_buf was located, leading to the remaining bytes to be sent becoming the overwritten content (0xCC becomes 0x00). If the serial rate is fast, this hidden error may be difficult to reproduce. Theoretical Core (from DeepSeek):Understanding C Language Rules to Avoid Code Issues Solution: Change the variable’s scope and lifecycle by placing the content to be sent into a global variable, similar to the following:

uint8_t g_send_buf[] = {0xAA, 0xBB, 0xCC};int RS232_lora_sendAlignInfo(void){    HAL_UART_Transmit_IT(&Uart2Handle, g_send_buf, 3);    return 0;}

Of course, it is also possible to send using a blocking method (calling HAL_UART_Transmit function), but this would reduce efficiency, as there are other module functions to implement in the product.

Leave a Comment