如何在嵌入式 C 代码库中查找与数据一致性相关的问题?

How to find issues related to Data consistency in an Embedded C code base?

让我解释一下数据一致性问题的含义。以下面的场景为例

uint16 x,y;
x=0x01FF;
y=x;

显然,这些变量是 16 位的,但如果将 8 位 CPU 用于此代码,读取或写入操作将不是原子的。因此,在两者之间可能会发生中断并更改 value.This 是一种可能导致数据不一致的情况。

这是另一个例子,

if(x>7) //x is global variable
{
 switch(x)
        {
           case 8://do something
                   break;
           case 10://do something
                   break;
           default: //do default
        }
}

在上面的摘录代码中,如果中断在 if 语句之后但 switch 语句之前将 x 的值从 8 更改为 5,我们将以默认情况结束,而不是情况 8。

请注意,我正在寻找检测此类情况的方法(但不是解决方案)

是否有任何工具可以检测嵌入式 C 中的此类问题?

据我所知,没有这样的工具。这可能是因为您无法 检测到它们。

几乎 C 代码中的每个操作都有可能在完成之前被中断。没有 16 位场景那么明显,还有这个:

uint8_t a, b;
...
a = b;

不能保证这是原子的!上面的赋值也可以转化为多个汇编程序指令,例如 1) 将 a 加载到寄存器中,2) 将寄存器存储在内存地址。除非你反汇编C代码并检查,否则你无法知道这一点。

这可能会造成非常 微妙的错误。任何 "as long as I use 8 bit variables on my 8 bit CPU, I can't get interrupted" 类型的假设都是幼稚的。即使这样的代码会导致对给定 CPU 的原子操作,该代码也是不可移植的。

唯一可靠、完全可移植的解决方案是使用某种方式的信号量。在嵌入式系统上,这可以像 bool variable 一样简单。另一种解决方案是使用内联汇编程序,但不能跨平台移植。

为了解决这个问题,C11 在语言中引入了限定符 _Atomic。然而,嵌入式系统编译器对 C11 的支持仍然很一般。

有上下文 (thread/interrupt) 感知的静态分析工具可以确定 共享数据 的使用,并且这样的工具可以识别特定的保护此类数据(或缺乏此类数据)的机制。

其中一个工具是 Polyspace Code Prover;它非常昂贵且非常复杂,并且除了上面描述的之外还有很多其他功能。具体引用(省略)白皮书 here:

With abstract interpretation the following program elements are interpreted in new ways:

[...]

  • Any global shared data may change at any time in a multitask program, except when protection mechanisms, such as memory locks or critical sections, have been applied

[...]

自从我使用它以来,它可能在很长一段时间内有所改进,但我遇到的一个问题是它在锁定-访问-解锁习惯用法上工作,您在其中向工具指定了 lock/unlock 调用的内容或宏。问题是我工作的 C++ 项目使用了一种更智能的方法,其中锁定对象(例如互斥锁、调度程序锁或中断禁用)在实例化时(在构造函数中)锁定并在析构函数中解锁,以便它自动解锁当对象超出范围时(按范围锁定)。这意味着解锁对于 Polyspace 是隐含的和不可见的。然而,它至少可以识别所有共享数据。

该工具的另一个问题是您必须指定所有线程和中断入口点以进行并发分析,在我的例子中,这些是任务和中断中的私有虚函数 类,再次使它们不可见多边形空间。这是通过有条件地使入口点 public 仅用于抽象分析来解决的,但这意味着被测试的代码不具有要 运行 的代码的确切语义。

当然,这些对于 C 代码来说都不是问题,而且根据我的经验,Polyspace 在任何情况下都更成功地应用于 C;您不太可能以适合该工具的风格编写代码,而不是该工具与您现有的代码库一起工作。