【问题标题】:Trapping uninitialized pointers [closed]捕获未初始化的指针[关闭]
【发布时间】:2015-11-10 12:33:35
【问题描述】:

我试图捕获传递给函数的错误指针。在我曾经使用的裸机嵌入式应用程序上:

assert(somePointer != NULL);

如果指针的特定内存位置初始化为零,则此方法效果很好。

我注意到 FreeRTOS 和 RTX 等其他操作系统会使用 0xA5 等模式填充内存(以进行堆栈使用高级水印)。因此,未初始化的指针将具有一些非零初始值。

当然,我意识到即使是零初始化的内存也会变成非零。因此,我希望有人有更好的方法来检测未初始化的指针。

由于这是一个嵌入式系统,我正在考虑让一个函数检查指针是否在正确的内存范围内。在 ST32F4xx 上,这将是 0x20000000 到 0x20020000,或 0x10000000 到 0x10010000 以及外设地址范围。

未初始化指针的最大原因通常是在固件库中声明为未初始化的外围句柄结构。用于帮助尽快检测到这些的 assert() 宏。

欢迎提出建议

【问题讨论】:

  • 好吧,标准要求全局变量是0/null 指针。对于局部变量,您应该使用对(大多数)未初始化的用法发出警告的编译器。其他任何东西充其量都是特定于实现的。检查花费时间和代码。通常手动验证每个指针访问是不可能的,除非您可以容忍大量惩罚(这提出了为什么不使用更便宜的 MCU 的问题)。而assert 仅在设置了NDEBUG 时才有效。无论哪种方式,您的问题都太宽泛了。
  • 只是为了论证,一个未初始化的指针仍然可以指向一个没有分配给你的进程的有意义的内存地址。那怎么样?
  • 我仍然很惊讶有人发现这是一个主要问题。在所有可能发生的错误中,取消引用 null 或其他被内存管理硬件捕获的地址甚至都不是什么大问题(除非是间歇性的)。
  • @Sourav 是的,这是正确的。这是问题的原因之一。我希望有人在 C 语言中有一个出色的策略来检测错误指针并愿意分享。
  • @Martin 我希望本地代码以 C++ try/catch 类型的方式处理错误,而不是崩溃到 MemFault 陷阱。我还可以指出,默认情况下,STM32F4xx 系列的陷阱似乎被禁用,因此只会导致一般的“硬故障”。我确实启用了所有特定的陷阱,并使用 MPU 来检测无效的访问范围。请注意,0x0 是 STM32F4xx 中的有效指针,可以在不触发内存故障的情况下取消引用。

标签: c embedded rtos


【解决方案1】:

选项一是做你正在做的事情:检查 NULL,检查它是否在正确的地址空间中,检查它是否正确对齐(如果你尝试引用非 32 位对齐的内存,ARM 会出错)。然后希望您不会遇到很多问题,因为您会得到一个可能有效的无效指针,正如 Sourav 在评论中指出的那样。

选项二是使用静态分析工具,如 Coverity,检查您使用未初始化指针的所有执行路径。根据您获取值的位置,可能找不到问题。

最后,由于您使用的是裸机,您可以直接覆盖故障处理程序。自从我使用 STM32F4 以来已经有一段时间了,但我记得你可以覆盖硬故障处理程序,所以这应该不是问题。然后你设置一个你正在测试指针的全局标志,并取消引用它。如果它触发了故障处理程序,请检查标志 - 如果已设置,请注意它是无效的并且什么也不做。

示例代码:

volatile int faultTest;
volatile int faultHappened;

_Bool validatePointer(void *p)
{
    faultTest = 1;
    faultHappened = 0;
    int n = *(int*)p;
    faultTest = 0;

    return faultHappened;
}

void fault_handler(void)
{
    if (faultTest)
    {
        faultHappened = 1;
        return;
    }
    // regular fault code
}

【讨论】:

  • 一些 ARM 允许未对齐的访问。对于某些人来说,它是一个配置选项(IP 或固件)。并且没有必要“覆盖 fualt 处理程序”,而只是提供一个。默认情况下没有。
猜你喜欢
  • 2012-02-23
  • 2021-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多