STM32对memcpy的调用导致hardfault(对memcpy本身的调用,而不是memcpy的执行)

Posted

技术标签:

【中文标题】STM32对memcpy的调用导致hardfault(对memcpy本身的调用,而不是memcpy的执行)【英文标题】:STM32 call to memcpy causes hardfault (the call to memcpy itself, not the execution of memcpy) 【发布时间】:2021-08-30 05:29:06 【问题描述】:

情况:我正在使用一个名为嵌入式迪斯科的加密库,我有一个在我的 PC 上运行的演示,但是在将它移植到 MCU 时,我在执行库过程时遇到了一个硬故障。在错误代码中,库试图简单地将一个strobe_s 结构的内容复制到另一个strobe_s。这样做了两次:一次用于s1,一次用于s2。对于s1,库只分配dest。结构到源结构。然而,对于s2,这样的分配给出了一个硬错误。由于 Cortex-M ISA 需要对齐的内存访问,我认为用 memcpy 替换分配应该可以解决问题。然而,简单地使用调试器进入 memcpy 会导致硬故障! IE。我在 memcpy 的行上有一个断点,当进入故障处理程序时会被调用!我已经使用 memcpy 修复了代码其他部分中未对齐的内存访问......

MCU: STM32L552ZET6QU

错误代码:

下面的代码是我对原始库代码的修改,其中对*s2 的赋值被替换为memcpy。 library's github 的原始代码是:

  // s1 = our current strobe state
  *s1 = ss->strobe;
  if (!half_duplex) 
    // s2 = s1
    *s2 = ss->strobe;
  

我的修改版:

  // s1 = our current strobe state
  *s1 = ss->strobe;
  if (!half_duplex) 
    // s2 = s1
    // WARNING: The below code will give a HARD FAULT ON THE STM32L552ZE!
    // *s2 = ss->strobe;
    // Fix I tried: Use memcpy instead!
    memcpy((void*) s2, (void*)(&(ss -> strobe)), sizeof(strobe_s));
  

memcpy的参数值:

就在执行 memcpy 之前,调试器向我显示了相关变量的以下值:

Expr.   Type                Value
----------------------------------------------------
s1      strobe_s *          0x800c374   
s2      strobe_s *          0x800a497 <_fflush_r+66>    
ss      symmetricState *    0x2002f988  
&s1     strobe_s **         0x2002f690  
&s2     strobe_s **         0x2002f68c  
&ss     symmetricState **   0x2002f694

类型定义:

typedef struct symmetricState_ 
  strobe_s strobe;
  bool isKeyed;
 symmetricState;

/** Keccak's domain: 25 words of size b/25, or b/8 bytes. */
typedef union 
  kword_t w[25];
  uint8_t b[25 * sizeof(kword_t) / sizeof(uint8_t)];
 kdomain_s;

/** The main strobe state object. */
typedef struct strobe_s_ 
  kdomain_s state;
  uint8_t position;
  uint8_t pos_begin;
  uint8_t flags;
  uint8_t initiator;
  uint8_t initialized;  // strobe is initialized if this value is set to 111.
                        // This is because we cannot assume that a boolean would
                        // be set to false initially (C stuff). A uint8_t is a
                        // short value but here we do not care about security
                        // much, rather catching bugs early in a development
                        // environement.
 strobe_s;

问题:

    怎么可能只是 调用 到 memcpy 而没有在 memcpy 中实际执行一条指令会产生硬故障? 我该如何解决这个问题?

【问题讨论】:

删除 void* 强制转换,它们是不必要的,可能会抑制有用的警告。 查看导致硬故障的原因。您需要从堆栈中读取寄存器和值。或者下载 atollic studio 或 CubeMxIDE,因为它们有一个非常方便的插件,称为 nomen omen faultAnalyzer github 上的代码前面有一个断言s1s2 都不是NULL - 令人费解的是没有检查ss 不是NULL .我还建议使用sizeof(*s2) 而不是sizeof(strobe_s) - 这只是一个更安全的习惯。 @Clifford 我移除了铸件,没有出现进一步的警告。 github 上的代码确实有断言,我的代码中也有它们。我只是没有将它们带到问题中以保持代码块小。断言得到满足,ss 为非 NULL,ss == 0x2000f988 @iMrFelix :我没想到会修复它 - 否则我会发布答案。只是观察和良好实践。请注意,除非您明确启用选择性异常处理,否则任何异常都会转换为硬故障。在汇编指令级别单步进入函数调用可能会有所帮助。可能是在调用之前对参数的评估失败。 【参考方案1】:

这里:

s2      strobe_s *          0x800a497 <_fflush_r+66>   

s2是一个闪存(只读)地址。复制到只读内存在语义上都是错误的,如果该区域设置为只读,则可能会触发 MPU 故障。

我不清楚原始代码是如何工作的,或者实际上是如何工作的:

 *s1 = ss->strobe;

但是也没有引起问题。即使没有异常,它也肯定不会按预期工作。

【讨论】:

我确实注意到,在更新问题时,事实证明在调用层次结构的更高层传递了一个错误的参数(一个 strobe_s 而不是一个 ptr. 到一个 strobe_s)。由于该错误发生在离故障发生的地方很远的地方,所以我错过了! @iMrFelix 看到这个电话会很有趣。除非你被一个不明智的演员挫败,否则编译器应该已经注意到了。这就是为什么我建议不要在这种情况下进行不必要的演员表 - 它告诉编译器“不要抱怨这个,我知道我在做什么” ...除非你不这样做.通过强制转换抑制编译器警告或错误应该是最后的手段,而不是习惯性 我可以在进一步的问题编辑中添加错误代码。我总是投的原因是,例如当使用带有 char* 而不是 uint8_t* 作为有效负载的 HAL_UART_Transmit(...) 时,我碰巧总是收到签名警告。 @iMrFelix 也许不相关,只是我的好奇心。你永远不需要强制转换为 void*;这就是 void* 的目的。 STM32 HAL 接口很烂,但习惯性地铸造一切并不是解决办法。只投射你需要投射的东西,否则更喜欢类型协议。否则,正如您发现的那样,您最终会遇到难以理解的运行时错误,您可能会遇到更直接的构建错误。如果您仅在编译器需要而不是习惯性的情况下进行转换,您可以将每个转换视为您应该的偏差,而不是全局隐藏错误。 disco 库的所有握手逻辑都包含在自定义函数server_disco_connect(c_write, c_read) 中,其中c_writec_read 应该是指向选通状态的指针。我错误地直接用结构调用disco_connect。为什么编译器没有抱怨我不能说,但它肯定没有(我什至没有强制转换它们!)。如果您准备迎接挑战,我刚刚发布了一个新问题,非常感谢您的帮助! :)

以上是关于STM32对memcpy的调用导致hardfault(对memcpy本身的调用,而不是memcpy的执行)的主要内容,如果未能解决你的问题,请参考以下文章

调用任何 C 函数时的 STM32 硬故障

STM32F103因为栈空间过小导致的奇怪问题!

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

如何在 Cortex-M3 (STM32) 上从 RAM 执行功能?

STM32 Flash 写入导致多个 HardFault 错误

STM32“未定义对‘HAL_DELAY’的引用”