7

I was puzzled by the following question: How to keep the advantage of the "static" label but still be able to debug production code on site?

Not once it happens that unintended behavior is occurring at the customer site, and only there . In many cases, having the option to perform a debug can save a lot of effort and provide a very quick response. Such a debug usually involves checking function behavior, which brings us to the "static" definition.

Static functions cannot be debugged from a debug shell, like putting breakpoints or executing it. On the other hand, defining all functions as public causes code structure and optimization grief.

I'm aware of options like compiling at least two different builds, one with static and one without, but this fits well with automation tests, not with the final production build that goes out eventually.

Will appreciated some insights from your side, mainly on how you resolved (if any) this dilemma. Or rephrasing the question to: "What is more important?"

A good discussion on "static" in C here.

Community
  • 1
  • 1
EdwardH
  • 1,523
  • 2
  • 12
  • 20
  • 1
    Do you mean that you are not able to set breakpoints in functions declared as `static`? In C, `static` functions are just normal functions, but they can not be called from other "translation units". Nothing should prevent debugging, remote or local, of them, unless they have been optimized away. – Some programmer dude Mar 08 '12 at 09:27
  • 1
    You can define a global pointer to your static function and use its value to set a breakpoint on the static function. You can even make this pointer `volatile` to prevent the compiler from eliminating it as unused. – Alexey Frunze Mar 08 '12 at 10:05
  • @JoachimPileborg From what I know, static functions will not enter the symbol table (even if flagged using the compiler), therefore, debugging is not possible (like a breakpoint). – EdwardH Mar 08 '12 at 10:35
  • @Alex Interesting approach, this is a self managed symbol table. If we are to do it for all the source, we need the module (file) to register its functions to such an entity. But from what I heard, the compiler may optimize such a static function to be inline, is reading a static function address safe? – EdwardH Mar 08 '12 at 10:41
  • 1
    It sure is in the symbol table for the (simple I admit) test programs I just made. What's your target and host platforms? And your debugger? – Some programmer dude Mar 08 '12 at 10:42
  • I see nothing unsafe here. But indeed nothing prevents the compiler from generating multiple instances of a function (inline and non-inline, e.g. the one the pointer will point to). – Alexey Frunze Mar 08 '12 at 11:01
  • @JoachimPileborg Target is VxWorks, working on a Windows host. The map file which contains all the symbol tables do not include static functions. For this discussion context, I'm using the vxWorks shell commands which include debugging tools... but I do not need the debugger to check out the symbol table. – EdwardH Mar 08 '12 at 11:17
  • The vxWorks guys like Diab but gcc is supported; is it possible to get everything built with gcc? If so you can use the -fno-inline argument to suppress inline expansion. I don't know offhand whether (and under what conditions) Diab inlines. – torek Mar 08 '12 at 11:42

3 Answers3

3

I think the fundamental question is not "Do you ship with 'static' or not?", it is "Do you test exactly what you ship ?" For embedded code, if you are doing the majority of your testing on a Debug build, and then shipping a Release version compiled with different options, you are essentially shipping untested code to your customer. When you are running that close to the hardware, small changes in timing or memory access patterns (which the optimizer can easily introduce) can cause big changes in the behavior of the system.

My current strategy is to ship the Debug version, configured for as much optimization as I can stand when debugging. No Static functions, make as much state visible to the debugger as possible.

Yes, I give away some possible compiler-generated efficiencies, but as long as I ensure the Debug version is fast enough to meet its requirements, that's not a problem. And the payoff is that the code I ship is exactly the same code I've been testing with the whole release cycle - no optimizer-generated surprises.

AShelly
  • 34,686
  • 15
  • 91
  • 152
  • It is worth mentioning that "static" usage is not only related to efficiency, it is in many ways an Object Oriented concept (like declaring and implementing a proper separation, so other coders will not bypass defined API/s). Your new question raised deserves a separate topic here, there are several pros and cons to consider. – EdwardH Mar 09 '12 at 09:34
  • Leaving a function out of the corresponding header is nearly as good as declaring it static when it comes to encapsulation and visibility. Naming can help also. "Why are you calling `module1DoSomething_private()` from Module2.c?" is a good question to ask in a review... – AShelly Mar 09 '12 at 18:24
1

Some debuggers can debug "static" functions. Sometimes static functions are expanded in line at the call site, though, which makes the debugger's job difficult, and some debuggers just give up.

(Inline expansion at the call site is not actually a property specific to "static", it's just that compilers are more likely to do this because they "know more" about the function—specifically, that the name is not visible outside the current translation unit, so the function's code can be omitted entirely if all its calls are expanded in-line.)

It was once common to use a macro:

#ifndef STATIC
#  define STATIC static
#endif
...
STATIC void somefunc() { ... }

and then turn the macro into "nothing" for debug builds. That works pretty well, but it's even better to find a debugger smart enough to handle static functions even when they are expanded inline.

torek
  • 448,244
  • 59
  • 642
  • 775
  • The macro solves the problem for the in-house testing period, but does not fit well when the problem is at the customer site and only there. Some times, putting a debug version will eliminate the problem. – EdwardH Mar 08 '12 at 10:48
1

Can you put a breakpoint in the publicly accessible function that calls the static function? Then you could check the arguments going in and the return values at least. If the problem only occurs at a customer site, and your unit tests / integration tests don't show problems for the inputs you expect those functions to receive, the problem is probably that these functions are getting inputs (or sequence of inputs, if the function is stateful somehow) you did not anticipate, meaning the actual problem may be outside the static functions you're looking at.

If you already suspect that you know which static function contains the problem, and you know what sort of inputs you suspect cause the problem, you could put a simple unit test function in the release build just to check for the bug you suspect. Of course, this gets complicated if this function directly controls, e.g a six-ton crane, in which case you might have to write two versions of the function, one with a mockup for controlling the crane, and run your tests on that.

Least likely but not impossible, never rule out a compiler inconsistency between release and debug builds. We all like to think compilers are infallible, me included, but stuff happens. And I see in your response to torek that giving the customer a debug build sometimes fixes the problems...

Sam Skuce
  • 1,666
  • 14
  • 20
  • Debugging the API of a module is not always enough, especially when you already suspect a problem in a private function. I fully agree with your point for exercising the needed tests, however, this is not always applicable in an embedded environment. Many times we are talking about sequencing and asynchronous handling of events which unit testing may not cover. – EdwardH Mar 09 '12 at 09:40