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



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

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

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

这是另一个例子,

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 中的此类问题?

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

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

通过抽象解释,以下程序元素以新的方式解释:

[...]

  • 在多任务程序中,任何全局共享数据都可能随时更改,除非受到保护 已应用内存锁定或关键部分等机制

[...]

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

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

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

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

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

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

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

这可能会产生非常微妙的错误。任何"只要我在 8 位 CPU 上使用 8 位变量,我就不会被打断"之类的假设都是幼稚的。即使此类代码会导致在给定的 CPU 上进行原子操作,该代码也是不可移植的。

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

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

相关内容

  • 没有找到相关文章

最新更新