任何避免“重入”的系统方法都可以。问题? (嵌入式系统)

发布于 2024-08-19 06:05:48 字数 1436 浏览 4 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

浅唱々樱花落 2024-08-26 06:05:48

我不太确定你想要解决的问题,但让我做一个有根据的猜测。

第一点是确定可能有问题的功能。重入要么通过递归调用发生,递归调用可能会遍历多个嵌套调用,甚至被回调/依赖项注入隐藏,要么通过在多个线程中使用的函数发生。

您可以绘制有向调用图。假设函数 A 调用 B 和 C,函数 B 调用 D、E 和 F,函数 C 不调用任何内容,依此类推。多线程时为每个线程绘制此图。如果图中存在循环,则构成该循环的所有函数都需要是重入安全的。在这种情况下,您可以忽略子分支。在多个线程中使用的函数也需要安全,但现在包括所有子分支,因为您不确切知道每个线程当前所在的位置。当使用锁时,事情会变得越来越复杂,所以我们暂时忽略这一点。

这一步肯定可以通过代码分析工具自动化。

现在函数已被识别,

  • 仅依赖于函数本地数据的函数通常是安全的。这是函数式编程的优点之一。
  • 依赖于外部数据(不在函数作用域内)的函数应该仔细检查,了解外部数据何时何地发生变化尤其重要。
  • 更改外部数据的函数应该发出危险信号并激活响亮的警报器,尤其是在多线程时。

I'm not exactly sure about the problem you want to solve, but let me make an educated guess.

The first point is to identify the functions that could be problematic. A reentry happens either by recursive calls, which may go over several nested calls and even be hidden by callbacks/dependency injection, or by functions that are used within multiple threads.

You could draw a directed call graph. Say function A calls B and C, function B calls D, E and F, function C calls nothing, and so on. Draw this for each thread when multithreading. If there are cycles in the graph, then all functions making this cycle need to be reentry-safe. You can ignore subbranches in this case. Functions that are used in multiple threads need to be safe, too, but now including all subbranches, because you do not exactly know where each thread currently is. Things will get complex and complicated when locks are used, so let us ignore this for now.

This step can surely be automated by code analysis tools.

Now that the functions are identified,

  • Functions that only depend on their function-local data are usually safe. This is one of the nice properties of functional programming.
  • Functions that depend on external data (not within the function scope) should be closely examined, it is especially important to know when and where the external data is changed.
  • Functions that change external data should raise a red flag and activate a loud alarm siren, especially when multithreading.
金兰素衣 2024-08-26 06:05:48

如果您怀疑某些事情,请快速修复:

int some_func(int x, int y)
{
    static volatile int do_not_enter_twice = 0;
    assert(!(do_not_enter_twice++));

    /* some_func continued */

    do_not_enter_twice--;
    return whatever;
}

更长的答案:
使用某种工具制作调用图并从那里手动继续。

Quick fix, if you suspect something:

int some_func(int x, int y)
{
    static volatile int do_not_enter_twice = 0;
    assert(!(do_not_enter_twice++));

    /* some_func continued */

    do_not_enter_twice--;
    return whatever;
}

Longer answer:
Use some tool to make a call graph and continue manually from there.

九局 2024-08-26 06:05:48

可以计算巨大调用图的工具是DMS Software Reengineering Toolkit 及其 C 前端。
C前端用于解析C代码; DMS 具有内置机制,用于计算控制和数据流分析、指向分析以及提取直接调用和通过指针间接调用事实

DMS 已用于为 3500 万个 C 源代码系统构建调用图 行 C 代码(= 250,000 个函数),然后从该调用图中提取信息。构建这样的大型图时的一个关键问题是尽可能准确地计算信息点(完美地做到这一点存在严格的理论限制),以便间接函数调用保守地针对最少数量的误报目标。

就您而言,正如其他作者指出的那样,要提取的信息是“是否存在循环?”在此调用图中。

在这种规模下,您不想手动执行此操作,并且每次准备生产构建时都需要重新执行此操作。因此,将检查机械化是很有意义的。

A tool that can compute huge call graphs is the DMS Software Reengineering Toolkit and its C front end.
The C front end is used to parse the C code; DMS has machinery built in to compute control and data flow analysis, points-to analysis and extract call-direct and call-indirect-thru-pointer facts

DMS has been used to build call graphs for C source code systems of 35 million lines of C code (= 250,000 functions), and then to extract information from that call graph. A key issue when building large graphs like this is to compute points-to information as accurately as practical (there are hard theory limitations on doing this perfectly) so that indirect function calls are conservatively targeted to a minimal number of false positive targets.

In your case, the information to extract is, as other authors indicate, "is there a cycle?" in this call graph.

At this scale, you don't want to do this by hand, and you need to re-do it every time you get ready for a production build. So mechanizing the check would make a lot of sense.

残龙傲雪 2024-08-26 06:05:48

我会做两件事来检查你的代码。彻底的小组代码审查(目的只是发现重入错误,而不是风格或其他错误)。二是切实攻克问题。

例如:

int myfunction(int x, int y) {
    REENTRANCE_CHECK;
    ... body of function
}

现在您可以 #define REENTRANCE_CHECK 为空(用于生产)或一些检查函数永远不会重新输入的代码。在启用这些检查的情况下运行测试(如果没有测试,请在连接了调试器的设备上运行),并查看是否有任何问题。

同样,您可以添加调试逻辑来检测全局状态的错误更新。编写使用锁的代码(断言它们在已经持有时是否被获取。

类似这样的事情:

int my_global;
DEFINE_GLOBAL_LOCK(my_global);

void my_dangerous_function() {
    ...
    LOCK_GLOBAL(my_global);
    .. some critical section of code that uses my_global.
    UNLOCK_GLOBAL(my_global);
    ...
}

同样,DECLARE_GLOBAL_LOCK、LOCK_GLOBAL 和 UNLOCK_GLOBAL 可以 #define 为真正的锁定代码(当然你必须编写)测试时,对于生产,它们可以被 #define 为空。

只有当您找到并包装对全局状态的所有访问时,这种方法才有效,但这通过搜索很容易。

I'd do 2 things to check your code. Thorough group code-review (with the goal of finding reentrance mistakes only, not style or other errors). Secondly, a practical attack on problems.

For example:

int myfunction(int x, int y) {
    REENTRANCE_CHECK;
    ... body of function
}

Now you can #define REENTRANCE_CHECK to be either be empty (for production) or some code that checks the function is never re-entered. Run your tests (if you don't have tests, then run it on your device with the debugger attached) with these checks enabled, and see if anything drops off.

Similarly, you can add debug logic to detect incorrect updates to global state. Write code that uses locks (which assert if they're acquired when already held.

Something like this:

int my_global;
DEFINE_GLOBAL_LOCK(my_global);

void my_dangerous_function() {
    ...
    LOCK_GLOBAL(my_global);
    .. some critical section of code that uses my_global.
    UNLOCK_GLOBAL(my_global);
    ...
}

Again, DECLARE_GLOBAL_LOCK, LOCK_GLOBAL and UNLOCK_GLOBAL can be either #defined to be real locking code (which of course you'll have to write) for testing, and for production they can be #defined to nothing.

This approach only works if you find and wrap all accesses to your global state, but that's easy with a search.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文