Is there any systematic way to avoid the "re-entry" problem? (Embedded system)

We use C to create a system on the ARM core (i.e. an embedded system). The question arises: how can we avoid the problem of re-launching formally so that we are sure that all re-login errors are deleted. This may not be a practical desire, but it is certainly important for any system.

Just for discussion, I think that drawing a UML diagram or having a complete state machine will be a good start (but how to generate it AFTER the development of the whole system?). Any suggestions on using state diagram / UML for analysis?

+4
source share
4 answers

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

The first point is to identify features that can be problematic. Reinclusion occurs either by recursive calls that can go through several nested calls and even hide using callbacks / dependencies or functions that are used in several threads.

You can draw a directed call diagram. Say, function A calls B and C, function B calls D, E and F, function C does not name anything, and so on. Draw this for each thread with multithreading. If there are cycles on the graph, then all functions that perform this cycle should be safe for re-entry. In this case, you can ignore child elements. Functions that are used in multiple threads should also be safe, but now they include all the children, because you donโ€™t know exactly where each thread is located. Everything will be complicated and complicated when the locks are used, so we will not ignore it for now.

This step, of course, can be automated with code analysis tools.

Now that the functions are identified,

  • Functions that depend only on their local data are usually safe. This is one of the nice features of functional programming.
  • Functions that depend on external data (not within scope) should be carefully studied; it is especially important to know when and where external data will be changed.
  • Functions that modify external data should raise a red flag and activate a loud siren siren, especially with multithreading.
+4
source

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 schedule calls and continue manually from there.

+4
source

A tool that can calculate huge call schedules is the DMS Software Reengineering Toolkit and its C interface. The front of C is used to analyze C code; DMS has built-in mechanisms for calculating control and analysis of data flow, point analysis and analysis of direct call and indirect call calls.

DMS is used to plot call schedules for C source code systems from 35 million lines of C code (= 250,000 functions), and then to extract information from this call schedule. The key problem in constructing large graphs like this one is to accurately calculate the point-information as practical (there are strict theory limitations ideally), so that indirect function calls are conservatively aimed at the minimum number of false-positive targets.

In your case, information to retrieve, as other authors point out, "is there a loop?" in this call schedule.

On this scale, you donโ€™t want to do it manually, and you need to do it again every time you prepare to assemble products. Therefore, the mechanization of verification will make a lot of sense.

+2
source

I would do 2 things to check your code. A thorough group review of the code (in order to search for re-entry errors, not style or other errors). Secondly, a practical attack on problems.

For instance:

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

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

Similarly, you can add debug logic to detect incorrect updates in the global state. Write code that uses locks (which claim if they were acquired when they were already saved.

Something like that:

 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 either be #defined to be the real lock code (which, of course, you will have to write) for testing, and for production they can be # undefined.

This approach only works if you find and complete all calls to your global state, but it is easy with a search.

0
source

Source: https://habr.com/ru/post/1299316/


All Articles