【问题标题】:A potential memory overflow but not sure what's causing it潜在的内存溢出,但不确定是什么原因造成的
【发布时间】:2020-09-15 17:47:29
【问题描述】:

我看到一个潜在的溢出:streamBuffer 是一个结构对象(FreeRTOS 库的一部分),在执行OutputToSerial() 中的以下行时,我看到streamBuffer.xHead 的值设置为一个非常大的值即使它当时没有被修改。

LONG_TO_STR(strData, txStr);
  • 请注意,我之前多次致电nRF24_ReadReg() 时没有遇到任何问题。
  • 此外,我经常看到 printf 不会打印正在打印的整个文本(在我看到潜在溢出时调用时间之前) - 而是错过了一些字符。

有什么方法可以更好地了解原因?我在寄存器中看不到任何硬故障或任何可查看的内容...

作为参考,以下是结构体的定义:

typedef struct StreamBufferDef_t /*lint !e9058 Style convention uses tag. */
{
    volatile size_t xTail;              /* Index to the next item to read within the buffer. */
    volatile size_t xHead;              /* Index to the next item to write within the buffer. */

    size_t xLength;                     /* The length of the buffer pointed to by pucBuffer. */
    size_t xTriggerLevelBytes;          /* The number of bytes that must be in the stream buffer before a task that is waiting for data is unblocked. */
    volatile TaskHandle_t xTaskWaitingToReceive; /* Holds the handle of a task waiting for data, or NULL if no tasks are waiting. */
    volatile TaskHandle_t xTaskWaitingToSend;   /* Holds the handle of a task waiting to send data to a message buffer that is full. */
    uint8_t *pucBuffer;                 /* Points to the buffer itself - that is - the RAM that stores the data passed through the buffer. */
    uint8_t ucFlags;

    #if ( configUSE_TRACE_FACILITY == 1 )
        UBaseType_t uxStreamBufferNumber;       /* Used for tracing purposes. */
    #endif
} StreamBuffer_t;
// file.c
#define PRI_UINT64_C_Val(value) ((unsigned long) (value>>32)), ((unsigned long)value)
#define LONG_TO_STR(STR, LONG_VAL) (sprintf(STR, "%lx%lx", PRI_UINT64_C_Val(LONG_VAL)))

unsigned long long concatData(uint8_t *arr, uint8_t size)
{
    long long unsigned value = 0;
    for (uint8_t i = 0; i < size; i++)
    {
        value <<= 8;
        value |= arr[i];
    }
    return value;
}

void nRF24_ReadReg(nrfl2401 *nrf, uint8_t reg, const uint8_t rxSize, uint8_t *rxBuffer, char *text)
{
    uint8_t txBuffer[1] = {0};
    uint8_t spiRxSize = rxSize;

    if (reg <= nRF24_CMD_W_REG)
    {
        txBuffer[0] = nRF24_CMD_R_REG | (reg & nRF24_R_W_MASK);
        spiRxSize++;
    }
    else
    {
        txBuffer[0] = reg;
    }

    nRF24_SendCommand(nrf, txBuffer, rxBuffer, spiRxSize);

    OutputToSerial(txBuffer, rxBuffer, spiRxSize, text);
}

void OutputToSerial(uint8_t *writeBuffer, uint8_t *readBuffer, uint8_t size, char *text)
{
    char strData[100] = {0}, rxStrData[100] = {0};
    long long unsigned txStr = concatData(writeBuffer, size);
    long long unsigned rxStr = concatData(readBuffer, size);
    LONG_TO_STR(strData, txStr);              // POTENTIAL ERROR.....!
    LONG_TO_STR(rxStrData, rxStr);

    char outputMsg[60] = {0};
    strcpy(outputMsg, text);
    strcat(outputMsg, ":          0x%s ----------- 0x%s\n");

    printf (outputMsg, strData, rxStrData);
}

// main.c
StreamBufferHandle_t streamBuffer;

【问题讨论】:

  • "%lx%lx" 作为"%lx%08lx" 更有意义。好奇,为什么不用"%llx" 打印?
  • LONG_TO_STR(STR, LONG_VAL) 最好命名为UNSIGNED_LONG_LONG_TO_STR(STR, ULLONG_VAL)
  • %llx 只打印lx
  • 海合会。您可以在我发布的 github 链接中找到相同的问题

标签: c embedded freertos


【解决方案1】:

也许还有其他问题,但LONG_TO_STR(x) 简直是一团糟。
考虑值0x123400005678 将打印为"12345678"ref code 坏了。

是的,它太糟糕的代码有long long,但没有"%llx"。很容易将它全部重写为一个干净的函数。

//#define PRI_UINT64_C_Val(value) ((unsigned long) (value>>32)), ((unsigned long)value)
//#define LONG_TO_STR(STR, LONG_VAL) (sprintf(STR, "%lx%lx", PRI_UINT64_C_Val(LONG_VAL)))

#include <stdio.h>
#include <string.h>
#include <limits.h>

// Good for base [2...16]
void ullong_to_string(char *dest, unsigned long long x, int base) {
  char buf[sizeof x * CHAR_BIT + 1]; // Worst case size
  char *p = &buf[sizeof buf - 1];  // set to last element
  *p = '\0';
  do {
    p--;
    *p = "0123456789ABCDEF"[x % (unsigned) base];
    x /= (unsigned) base;
  } while (x);
  strcpy(dest, p);
}

int main(void) {
  char buf[100];
  ullong_to_string(buf, 0x123400005678, 16);   puts(buf);
  ullong_to_string(buf, 0, 16);   puts(buf);
  ullong_to_string(buf, ULLONG_MAX, 16);   puts(buf);
  ullong_to_string(buf, ULLONG_MAX, 10);   puts(buf);
  return 0;
}

输出

123400005678
0
FFFFFFFFFFFFFFFF
18446744073709551615

【讨论】:

  • 好的,我正在尝试理解您的逻辑。 "0123456789ABCDEF"[x %(unsigned)base]; 是什么?
  • @Jarj x %(unsigned)base 获取x 的最低有效十六进制数字。该值索引字符串 "0123456789ABCDEF" 以将该值转换为其代表数字字符。
  • "0123456789ABCDEF" 和索引背后的想法是什么?在初始化char *p 时,您还缺少&amp;。我尝试运行它,但似乎它不起作用。或者我误解了它
  • @Jarj 整理了代码。示例:"0123456789ABCDEF" 是一个字符串。用"0123456789ABCDEF"[12] 索引第12 个字符会导致char 'C' 分配给*p
猜你喜欢
  • 2022-06-22
  • 2013-02-23
  • 2015-01-07
  • 1970-01-01
  • 2021-07-04
  • 2021-05-23
  • 1970-01-01
  • 1970-01-01
  • 2011-12-13
相关资源
最近更新 更多