Security in C

I would like to use area protection in C to perform profiling.

I would like to know how much time I spend in functions. That's what I'm doing:

int function() { tic(); ... do stuff ... if (something) { toc(); return 0; } toc(); return 1; } 

I need to put a toc statement every time I exit a function. I would like to do this without having to copy the pattern. Is there a general way to do this using a macro or something else? Also, I do not want to change the way the function is called, since there are many functions that I need to profile.

thanks

+4
source share
8 answers

This does not change the way the function is called. Probably not so much if you want to be able to profile each function.

 static inline int real_function() { // previous contents of function(), with no tic or toc } int function() { tic(); int r = real_function(); toc(); return r; } 

As everyone says: use a profiler, this will save you a lot of effort in the long run. As they do not say: if your platform has one.

If this is not the case, then the easiest way to say (usually coding) is that functions should have only one exit point, and the exit point should be through your macro. Then you can manually use all your functions with the code when you enter and exit. Inherited multi-return functions can be wrapped as described above.

Also, keep in mind when you do something like this that your compiler can ruin you. You can write this:

 tic(); do_something(); int i = something_else(); toc(); return i; 

If the compiler determines that something_else has no side effects, then although something_else takes a considerable amount of time, it can turn the code into this:

 tic(); do_something(); toc(); return something_else(); 

And your profile data will underestimate the time spent on your function. Another reason it is so good to have a real profiler is that it can work with the compiler.

+5
source

You can define a macro as:

 #define TOC_RETURN(x) \ do { \ toc(); \ return x; \ } while(0) 

which should work wherever you put it. Then you can automate the replacement return *; on TOC_RETURN(*) .

+4
source

Why not use an actual profiling tool like gprof ?

+4
source

You can simply override the return through the macro: (see Disclaimer)

 #include <stdio.h> void tic() { printf("tic\n"); } void toc() { printf("toc\n"; } #define return toc(); return int foo() { tic(); return 0; } #undef return int main() { foo(); return 0; } 

Disclaimer: This can be considered ugly and hacked because:

  • It will not work for void functions unless you use return; -statements.
  • It may not be portable / standard, although it works on MSVC8.
  • You cannot define keywords.
+2
source

I would not recommend a macro for this. You look at the code only once in a while, and instead of replacing "return" with some special macro, the code becomes less readable for this purpose.

Isn't it better to do the following?

 tic(); call_function(); toc(); 

This automatically processes the "all exit points" of the function.

PS Why do not you use a profiler?

+1
source

A real profiler does not need to modify the code, just to compile it with profiling.

+1
source

I'm very late to the party, but there is another way to protect borders in C using the cleanup attribute of the GCC extension. The cleanup attribute attaches the function to a variable declaration, which runs when the variable goes out of scope. Originally designed to perform memory deallocation for dynamically allocated types, it can also be used as a means of protecting an area.

 void cleanup_toc(int *ignored __attribute__((__unused__))) { toc(); } int function(void) { tic(); int atexit __attribute__((__cleanup__(cleanup_toc))) = 0; //... do stuff ... if (something) { return 0; } return 1; } 

This solution does not use macros, but of course you can wrap this in a macro. For instance:

 #define CONCATENATE_IMPL(x, y) x ## y #define CONCATENATE(x, y) CONCATENATE_IMPL(x, y) #define ATEXIT(f) int CONCATENATE(atexit, __LINE__) __attribute__((__cleanup__(f))) = 0 int function(void) { ATEXIT(cleanup1); // These are executed in reverse order, ie ATEXIT(cleanup2); // cleanup2 will run before cleanup1. } 
+1
source

Hmm, maybe end a function call in a macro (macro family, really)? Here is one that takes no arguments and returns Retval:

 // define the wrapper for name #define DEFTIMECALL0(Retval,name) \ Retval timed##name() \ { \ Retval ret; tic(); \ ret = name(); \ toc(); \ return ret; \ } 

You will need macros for each task of the called function, with a return version of Retval and void.

Change Perhaps there’s not even a point in the definition of the wrapper function, and it’s better to just have a family of macros (again, for each version of arity and return / void) that wrap the function call in tic / toc directly on calls

Do not be afraid of instrumental profilers that essentially do this for you.

0
source

All Articles