Stripping specific functions on compile time - c

I'm writing a C program that uses a custom logging function to debug my program. Whenever I compile my program as a release version, I want all of my logging functions to be stripped from the code so it won't show up if someone tries to disassemble it.
Take the following example:
#include <stdio.h>
void custom_logging_function(char* message)
{
// Do something here
}
int main()
{
custom_logging_function("Hello world"); // This call should be removed.
return 0;
}
How could I make it so that the custom_logging_function and it's arguments aren't compiled into my program without having to write include guards everywhere throughout my code? Thank you

You can use pre-processor flags, for example:
#include <stdio.h>
#ifdef DEBUG
void custom_logging_function(char* message)
{
// Do something here
}
#else
#define custom_logging_function(x) ((void) 0)
#endif
int main()
{
custom_logging_function("Hello world"); // This call should be removed.
return 0;
}
With this code you will have to tell the "debug" target to define DEBUG, if you want to define something specifically for the "release" target you can replace #ifdef DEBUG with #ifndef NDEBUG and add the NDEBUG flag to the "release" definitions.
Edit:
Changed #define custom_logging_function(x) 0 to #define custom_logging_function(x) ((void) 0) inspired by #JoachimPileborg his answer.

Assuming you only want the logging calls to happen in a debug-build of your application, and not the release build you send to customers, you can still use the preprocessor and conditional compilation for it. It can be made vert simple though by using macros instead of having checks at every call.
Something like this in a heder file:
#ifdef _DEBUG
void custom_logging_function(char* message);
#else
# define custom_logging_function(message) ((void) 0)
#endif
You could use an empty macro body for the release-macro, but that can cause some compilers to give "empty statement" warnings. Instead I use an expression casted to void (to tell the compiler that the result of the expression will not be used). Any smart compiler will not include the expression after optimization.

Related

Is there a way to expand macro based on command line arguments? [duplicate]

Following program compiles successfully and print 1000 without even calling a foo() function from our main() function. How is it possible?
#include<stdio.h>
void foo()
{
#define ans 1000
}
int main() {
printf("%d", ans);
return 0;
}
#defineis run by the preprocessor which is staged before the compiler. After the preprocessor is done, the code will look like this:
/* Everything that is inside stdio.h is inserted here */
void foo()
{
}
int main() {
printf("%d", 1000);
return 0;
}
And this is what actually get compiled.
The preprocessor is very important to make header files work. In them, you see this structure:
#ifndef foo
#define foo
/* The content of the header file */
#endif
Without this, the compiler would complain if a header file is included more than once. You may ask why you would want to include a header file more than once. Well, header files can include other header files. Consider this macro, which is useful for debugging. It prints the name of the variable and then the value. Note that you would have to do a separate version for different types.
#define dbg_print_int(x) fprintf(stderr, "%s = %d", #x, x)
This is pretty versatile, so you may want to include it in a header file for own use. Since it requires stdio.h, we include it.
/* debug.h */
#include <stdio.h>
#define dbg_print_int(x) fprintf(stderr, "%s = %d", #x, x)
What happens when you include this file and also include stdio.h in you main program? Well, stdio.h will be included twice. That's why debug.h should look like this:
/* debug.h */
#ifndef DEBUG_H
#define DEBUG_H
#include <stdio.h>
#define dbg_print_int(x) fprintf(stderr, "%s = %d", #x, x)
#endif
The file stdio.h has the same construct. The main thing here is that this is run before the compiler. The define is a simple replacement command. It does not know anything about scope or types. However, as you can see here, there is some basic logic built into it. Another thing that the preprocessor does is to remove all the comments.
You can read more about the C preprocessor here: http://www.tutorialspoint.com/cprogramming/c_preprocessors.htm
The #define is processed by the preprocessor before the compiler does anything. It is a simple text replacement. The preprocessor doesn't even know if the line of code is inside or outside a function, class or whatever [Ref: https://stackoverflow.com/a/36968600/5505997]. Clearly you do not need to call the function to set the value and obviously you will not get any error during compile.
As others have stated, #define is a preprocessor directive, not C source code. See Wiki here.
Point being, in your code #define ans 1000 is not a variable definition, meaning that even if you were calling foo() in the main, you would still not be setting "ans" at runtime, because it is simply not a variable. It is just telling the preprocessor what to do with the "label" "ans", when it finds it in your source code.
In this example, the main() will essentially be calling an empty foo() function:
int main()
{
foo(); // Calls an empty function
printf("%d", ans); // ans will have been substituted by 1000 by the time you start executing you code
return 0;
}
The definition of "ans" will simpy not exist anymore by the time you start executing you main(). This is what the preprocessor does (in part). It finds all the #defines declared in your entire source code and tries to find places in your code where you have used these defines. If you have not used them, it moves on (don't care), if you have, it substitutes the label by the actual defined value.

How to override assert macro in C?

I want to create my own version of assert in which it does some log prints in case assert was called in NDEBUG mode.
I tried to do the LD_PRELOAD trick and redefine the assert macro but it seems to ignore the macro definition completely and overriding __assert_fail is irrelevant since it isn't called in case of NDEBUG.
How can I override the libc assert macro?
I do not want to create a different function since assert is already used heavily in the project.
Had the same problem using gcc on Cygwin/Windows and on Linux.
My solution is to overwrite the (weak) definition of the actual assertion failed handling function. Here is the code:
/*!
* Overwrite the standard (weak) definition of the assert failed handling function.
*
* These functions are called by the assert() macro and are named differently and
* have different signatures on different systems.
* - On Cygwin/Windows its __assert_func()
* - On Linux its __assert_fail()
*
* - Output format is changed to reflect the gcc error message style
*
* #param filename - the filename where the error happened
* #param line - the line number where the error happened
* #param assert_func - the function name where the error happened
* #param expr - the expression that triggered the failed assert
*/
#if defined( __CYGWIN__ )
void __assert_func( const char *filename, int line, const char *assert_func, const char *expr )
#elif defined( __linux__ )
void __assert_fail ( const char* expr, const char *filename, unsigned int line, const char *assert_func )
#else
# error "Unknown OS! Don't know how to overwrite the assert failed handling function. Follow assert() and adjust!"
#endif
{
// gcc error message style output format:
fprintf( stdout, "%s:%d:4: error: assertion \"%s\" failed in function %s\n",
filename, line, expr, assert_func );
abort();
}
The C99 rationale provides a sample on how to redefine the assert in a good way on page 113:
#undef assert
#ifdef NDEBUG
#define assert(ignore) ((void)0)
#else
extern void __gripe(char *_Expr, char *_File, int _Line, const char *_Func);
#define assert(expr) \
((expr) ? (void)0 :\
__gripe(#expr, _ _FILE_ _,_ _LINE_ _,_ _func_ _))
#endif
I'd include assert.h right before this code to make sure assert.h is used.
Also notice that it calls a function that would do reporting logic, so that your code would be smaller.
It is a pretty simple thing to do, since assert is a macro. Given that you have this code:
#define NDEBUG
#include <assert.h>
int main( void )
{
assert(0);
return 0;
}
Then just do:
#ifdef NDEBUG
#undef assert
#define assert(x) if(!(x)){printf("hello world!");} // whatever code you want here
#endif
Note that this has to be done after #include <assert.h> though.
So if you want to stick your own definition into a common header file, and then use that header file to modify existing code, then your header file have to be included after assert.h.
my_assert.h
#include <assert.h>
#include <stdio.h>
#ifdef NDEBUG
#undef assert
#define assert(x) if(!(x)){printf("hello world!");}
#endif
main.c
#define NDEBUG
#include <assert.h>
#include "my_assert.h"
int main( void )
{
assert(0); // prints "hello world!"
assert(1); // does nothing
return 0;
}
An attempt to try to override the assert() macro in a large codebase can be difficult. For example, suppose you have code like:
#include <assert.h>
#include "my_assert.h"
#include "foo.h" // directly or indirectly includes <assert.h>
After this, any use of assert() will again use the system assert() macro and not the one that you have defined in "my_assert.h" (this is apparently part of the C design of the assert macro).
There are ways to avoid this, but you have to use nasty tricks like putting your own assert.h header in the include path before the system assert.h, which is somewhat error prone and non-portable.
I'd recommend using a different named macro than assert, and use regex tricks or a clang-rewriter to rename the various assert macros in your codebase to an assert macro that you can control. Example:
perl -p -i -e 's/\bassert\b *\( */my_assert( /;' `cat list_of_filenames`
(then adding "my_assert.h" or something like it to each of the files modified)
You can check if NDEBUG is defined and if it is then print whatever logs you want to print.

How to use external macro in function body?

I'm writing a function that should have two versions: a debug version and non-debug version. Which one of the two functions is used should be decided by the caller.
I want something like this:
caller.c
// comment out the following line when not necessary anymore
#define MY_FUNC_DEBUG
#include "my_func.h"
// some code that calls my_func()
my_func.h
void my_func(void);
my_func.c
void my_func()
{
// lots of code
#ifdef MY_FUNC_DEBUG
// debug code
#endif
// more code
}
This obviously won't work, because my_func.c is compiled separately from caller.c, therefore it can't know what macros it defined.
How can I make this work easily? I wouldn't want to write the two versions of my_func separately, because they share most of their code.
Assuming that you are using gcc, this problem can be easily solved by defining the macro at compile time via the -D option in both files.
In your example you could compile both files using -D MY_FUNC_DEBUG when you want the debug code to be activated and nothing otherwise. There is not need for defining MY_FUNC_DEBUG in caller.c.
Make the debugging code in my_func() switchable at run-time.
my_func.h
#ifndef MY_FUNC_H_INCLUDED
#define MY_FUNC_H_INCLUDED
extern int my_func_debug(int level);
extern void my_func(void);
#endif
my_func.c
#include "my_func.h"
static int debug = 0;
int my_func_debug(int level)
{
int rv = debug;
debug = level;
return rv;
}
void my_func(void)
{
...
#ifdef MY_FUNC_DEBUG
if (debug)
...debug...
#endif
...
}
caller.c
void consumer(void)
{
int old = my_func_debug(9);
my_func();
my_func_debug(old);
}
Discussion
The outline code means that you can have one copy of the source for my_func.c, but it can be compiled with debug included, or with it excluded. The consumer code (caller.c) can request the level of debugging it wants, but whether that does anything useful depends on whether the copy of my_func.o (my_func.obj on Windows) was compiled with debug included. You get one source file; you get to choose which variant of the object file is included in the program with caller.o. And at runtime you can request debugging.
Note that my_func_debug() is unconditionally defined; it just doesn't do anything very useful if the my_func.c code is not compiled with -DMY_FUNC_DEBUG.

C puzzle: how will you print something on console?

/*you cannot change anything from here below*/
main()
{
exit(0);
}
/*you cannot change anything from here up*/
This was asked during an interview.
I was told to print something on console.
anybody?
Really surprised that nobody posted this yet:
#include <stdio.h>
#if 0
/*you cannot change anything from here below*/
main()
{
exit(0);
}
/*you cannot change anything from here up*/
#endif
int main()
{
printf("Hello, World!");
return 0;
}
Prints at runtime and no undefined behavior whatsoever.
weird question...
int main(void)
{
printf("hello");
return 0;
}
#define main int lol
/*you cannot change anything from here below*/
main()
{
exit(0);
}
/*you cannot change anything from here up*/
#include <stdio.h>
#define exit(c) return puts("foobar"),0
over main
One implementation defined way would be to use the pragma directives to print during compilation.
#pragma message "Compiling " __FILE__ "..."
Or, you could do this with some macros and a printf (but not without introducing UB in some aspect or the other) at runtime.
#define exit(x) printf("Hello, world!")
int main() {
exit(0);
return 0; /* if pre-C99 */
}
#include <stdio.h>
#pragma message("Some foobar")
#error This is an error message
int main()
{
exit(0);
}
I think the interviewer wanted to know if you're aware of the #error directive ... just my 2 cents.
Most answers involve the #define c-preprocessor instruction to change what the program means. Most compilers also support something like
#pragma startup foo()
details depend on the compiler vendor. You can make code run BEFORE main(*) is called that way.
#define exit(x) (printf("Bye"))
int main(int argc,char* argv)
{
exit(0);
getchar();
return 0;
}
Solution 1.
This works without any preprocessor directives in cl and gcc, although I've not tested to make sure I'm not using any extensions:
#include <stdio.h>
static void exit() {
printf("Hello world");
}
/*you cannot change anything from here below*/
main()
{
exit(0);
}
/*you cannot change anything from here up*/
I think it's valid but I can't remember if masking a standard library function is allowed or not.
Solution 2
As several other answers have specified, you can use preprocessor directives, eg:
#define main or exit to be something that calls ifdef
use #if 0 to prevent the existing code being compiled
using #pragma message or #error to print a message at compile time
using #pragma startup to use a different function as main or to run start-up code before main.
Solution 3
If your compiler supports any C++ features in addition to C, there are many answers:
Declare a class with a constructor and a static variable of that type
Put the existing "main" function into a separate namespace (or class definition) and write a different global main
Solution 4
I also looked for any way of forcing a run-time error (stack overflow, out of memory, null dereference, tc), which would normally cause the program to print something, but couldn't find any way that didn't involve running extra code, in which case the extra code might as well be printf.
If you interpreted the question to mean you could not or were not allowed to edit the file by commenting out /* */ or using #ifdef _COMMENT_ME_OUT__ #endif respectively above and below the section you are not allowed to edit and then introducing a new main, then you should give an answer of using another .c file.
If you cannot find a workaround to edit that file, then use a different c file.

Can you #define a comment in C?

I'm trying to do a debug system but it seems not to work.
What I wanted to accomplish is something like this:
#ifndef DEBUG
#define printd //
#else
#define printd printf
#endif
Is there a way to do that? I have lots of debug messages and I won't like to do:
if (DEBUG)
printf(...)
code
if (DEBUG)
printf(...)
...
No, you can't. Comments are removed from the code before any processing of preprocessing directives begin. For this reason you can't include comment into a macro.
Also, any attempts to "form" a comment later by using any macro trickery are not guaranteed to work. The compiler is not required to recognize "late" comments as comments.
The best way to implement what you want is to use macros with variable arguments in C99 (or, maybe, using the compiler extensions).
A common trick is to do this:
#ifdef DEBUG
#define OUTPUT(x) printf x
#else
#define OUTPUT(x)
#endif
#include <stdio.h>
int main(void)
{
OUTPUT(("%s line %i\n", __FILE__, __LINE__));
return 0;
}
This way you have the whole power of printf() available to you, but you have to put up with the double brackets to make the macro work.
The point of the double brackets is this: you need one set to indicate that it's a macro call, but you can't have an indeterminate number of arguments in a macro in C89. However, by putting the arguments in their own set of brackets they get interpreted as a single argument. When the macro is expanded when DEBUG is defined, the replacement text is the word printf followed by the singl argument, which is actually several items in brackets. The brackets then get interpreted as the brackets needed in the printf function call, so it all works out.
ะก99 way:
#ifdef DEBUG
#define printd(...) printf(__VA_ARGS__)
#else
#define printd(...)
#endif
Well, this one doesn't require C99 but assumes compiler has optimization turned on for release version:
#ifdef DEBUG
#define printd printf
#else
#define printd if (1) {} else printf
#endif
On some compilers (including MS VS2010) this will work,
#define CMT / ## /
but no grantees for all compilers.
You can put all your debug call in a function, let call it printf_debug and put the DEBUG inside this function.
The compiler will optimize the empty function.
The standard way is to use
#ifndef DEBUG
#define printd(fmt, ...) do { } while(0)
#else
#define printd(fmt, ...) printf(fmt, __VA_ARGS__)
#endif
That way, when you add a semi-colon on the end, it does what you want.
As there is no operation the compiler will compile out the "do...while"
Untested:
Edit: Tested, using it by myself by now :)
#define DEBUG 1
#define printd(fmt,...) if(DEBUG)printf(fmt, __VA_ARGS__)
requires you to not only define DEBUG but also give it a non-zer0 value.
Appendix:
Also works well with std::cout
In C++17 I like to use constexpr for something like this
#ifndef NDEBUG
constexpr bool DEBUG = true;
#else
constexpr bool DEBUG = false;
#endif
Then you can do
if constexpr (DEBUG) /* debug code */
The caveats are that, unlike a preprocessor macro, you are limited in scope. You can neither declare variables in one debug conditional that are accessible from another, nor can they be used at outside function scopes.
You can take advantage of if. For example,
#ifdef debug
#define printd printf
#else
#define printd if (false) printf
#endif
Compiler will remove these unreachable code if you set a optimization flag like -O2. This method also useful for std::cout.
As noted by McKay, you will run into problems if you simply try to replace printd with //. Instead, you could use variadric macros to replace printd with a function that does nothing as in the following.
#ifndef DEBUG
#define printd(...) do_nothing()
#else
#define printd(...) printf(__VA_ARGS__)
#endif
void do_nothing() { ; }
Using a debugger like GDB might help too, but sometimes a quick printf is enough.
I use this construct a lot:
#define DEBUG 1
#if DEBUG
#if PROG1
#define DEBUGSTR(msg...) { printf("P1: "); printf( msg); }
#else
#define DEBUGSTR(msg...) { printf("P2: "); printf( msg); }
#endif
#else
#define DEBUGSTR(msg...) ((void) 0)
#endif
This way I can tell in my console which program is giving which error message... also, I can search easily for my error messages...
Personally, I don't like #defining just part of an expression...
It's been done. I don't recommend it. No time to test but the mechanism is kind of like this:
#define printd_CAT(x) x ## x
#ifndef DEBUG
#define printd printd_CAT(/)
#else
#define printd printf
#endif
This works if your compiler processes // comments in the compiler itself (there's no guarantee like the ANSI guarantee that there are two passes for /* comments).

Resources