tags:

views:

131

answers:

4

Hello every body I am looking a tool able to detect ordered function call pairs in a nested fashion as shown below:

f()   // depth 0
   f()  //depth 1
   g()
g()

At each depth of call f() there must be a call of g() forming function call pair. This is particularly important in critical section entry and exit.

+11  A: 

In C++, one option is to wrap the calls to f() and g() in the constructor and destructor of a class and only call those functions by instantiating an instance of that class. For example,

struct FAndGCaller
{
    FAndGCaller() { f(); }
    ~FAndGCaller() { g(); }
};

This can then be used in any scope block like so:

{
    FAndGCaller call_f_then_later_g; // calls f()

} // calls g()

Obviously in real code you'd want to name things more appropriately, and often you'll simply want to have the contents of f() and g() in the constructor and destructor bodies, rather than in separate functions.

This idiom of Scope Bound Resource Management (SBRM, or more commonly referred to as Resource Acquisition is Initialization, RAII) is quite common.

James McNellis
If f() throws an error, g() will never be called, but resources of class/struct will be freed.
PC2st
@PC2st: True, but if `g()` does the opposite of (or "undoes") what `f()` does, then if `f()` throws an exception you don't want to call `g()`.
James McNellis
A: 

Scan through the code (that's the hard part) and every time you see an invocation of f(), increment a counter. Every time you see an invocation of g(), decrement the counter. At the end, the counter should be back to zero. If it ever goes negative, that's a problem as well (you had a call to g() that wasn't preceded by a matching call to f()).

Scanning the code accurately is the hard part though -- with C and (especially) C++, writing code to understand source code is extremely difficult. Offhand, I don't know of an existing tool for this particular job. You could undoubtedly get clang (for one example) to do it, but while it'll be a lot easier than doing it entirely on your own, it still won't be trivial.

Jerry Coffin
The problem with this approach is that it doesn't check the levels of the `f()`s and `g()`s - it'll make sure that you have the right amount, but it won't insure that you have them mirroring each other on the same level. Also, the OP asked for a tool to use, not a way of looking at the code.
adam_0
@adam_0: at least based on the code he showed, the levels are *defined* by the calls to `f()` and `g()`. If there's more to a level than that, he probably needs to tell us what it is to get a meaningful answer. I doubt there's an existing tool that does exactly what he wants, so I'm trying to tell him how to build one.
Jerry Coffin
Another option besides clang is to use Nokia's C++ parser library that comes with Qt-Creator. It's cross-platform, self-contained (libCPlusPlus.{so,dll}), and not too difficult to get started with, but it's still far from trivial. It's quite well written and well supported as it has been used in many different projects of theirs.
Kaleb Pederson
@Jerry: The question didn't seem clear that this was the case (nor what I was thinking). If the levels are purely based on the calls, then you have the right idea. (I assumed that it was embedded in more complex code where if there was an f() inside of an if statement, there had to be a g() somewhere there as well)
adam_0
@Kaleb: Is that library also documented somewhere?
Georg Fritzsche
@Jerry: scanning is not the hardest part, especially since somebody's already done it (for each of C and C++). The hardest part is knowing what to do with things like `if (some_condition) f(); ...; if (other_condition) g();`. It's an undecidable static analysis problem.
Gilles
+2  A: 

You may abuse a for-loop for this.

#define SAVETHEDAY for (bool seen = ((void)f(), true); seen; seen = ((void)g(), false))

The comma operator always lets your functions f be executed before the dependent statement and g afterwards. E.g

SAVETHEDAY {

    SAVETHEDAY {

    }
}

Pros:

  • Makes nesting levels clear.
  • Works for C++ and C99.
  • The pseudo for-loop will be optimized away by any decent compiler.

Cons:

  • You might have surprises with break, return and continue inside the blocks, so g might not be called in such a situation.
  • For C++, this is not safe against a throw inside, again g might not be called
  • Will be frowned upon by many people since is in some sort extending the language(s).
  • Will be frowned upon by many people especially for C++ since generally such macros that hide code are thought to be evil

The problem with continue can be repaired by doing things a bit more cleverly. The first two cons can be circumvented in C++ by using a dummy type as for-variable that just has f and g in the constructor and destructor.

Jens Gustedt
Astoundingly cleaver but so useless...
Joshua
@Joshua: My English is probably not good enough to know if *cleaver* is just a typo or if you give it deeper meaning. But anyhow, for me it is not useless since I use it ``everyday'' it is a very convenient idiom to protect e.g a critical section or to ensure that some initialization code is run exactly once.
Jens Gustedt
It's just a typo. I often make that one.
Joshua
A: 

The Coccinelle tool for semantic searching and patching of C code is designed for this sort of task (see also this LWN article on the tool).

caf