How to override assert macro in C? - 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.

Related

C Preprocessor include directive

When I include another source(I.e stdio.h) the preprocessor is smart enough to include only the functions that I am using in my code?
Example: Assuming this small program, would be ease to include only what I am using, and what the printf functions uses, including them recursively, but what about bigger programs?
#include <stdio.h>
int main(void) {
printf("Hello World\n");
return 0;
}
No. On the contrary:
#include performs textual replacement: it opens the file and copies all1 of its contents into your main C file. In the process it executes all preprocessor instructions in the included file. Amongst other things, this means that it will recursively include all files that are #included in the header.
#include does not know and does not care which part of the included file you end up using.
1 As mentioned, preprocessor instructions are executed in the included file. This can modify what gets included. For example, assume the following header file header.h:
#ifndef HEADER_H
#define HEADER_H
#ifdef NDEBUG
# define LOG(...) ((void) 0)
#else
# define LOG(...) log_message(__FILE__, __LINE__, __VA_ARGS__)
inline void log_message(const char* filename, int line, ...) {
// Logging code omitted for brevity.
}
#endif
// other stuff
#endif
Now, if your main.c file looks as follows:
#define NDEBUG
#include "header.h"
int main(void) {
// …
LOG("hello");
}
… then, after preprocessing, your main.c file would looks something like this (I’m omitting some irrelevant stuff):
# 1 "main.c"
# 1 "./header.h" 1
# 13 "./header.h"
// other stuff
# 3 "main.c" 2
int main(void) {
// …
((void) 0);
}
… in other words, only the part of header.h that corresponds to #ifdef NDEBUG was included, not the part in the #else clause. If we had included header.h without defining NDEBUG, then the included header code would have contained the definition of log_message.
As others have said, #include will paste verbatim the entire file you are targeting. However you normally include headers, which tend to look like
extern int a (int b);
extern char * c (void);
static inline int d (int e, int f) {
...
}
extern void * g (void * h);
...
The code above occupies exactly zero memory (unless you start using one of the inline functions), since it is entirely composed of instructions for the compiler and nothing else.

GCC __func__ gets evaluated to an empty string

Given the following code in a project I'm working on:
/* Pre-definitions in a pre-definitions file to be included in the project */
#ifdef WIN32
#define __FUNCNAME__ __FUNCTION__
#else
#define __FUNCNAME__ __func__
#endif
/* My definitions */
#define MAC() \
MAC1()
#define MAC1() \
myPrintFunction(__FUNCNAME__)
/* My print function */
void myPrintFunction(const char * functionName)
{
printf("\n func name: %s \n",functionName);
}
/* Macro usage example function */
void myFunction()
{
if (some_condition)
{
MAC();
}
}
The function name is presented as an empty string.
Any idea why, and how can I fix it?
Code compiled and tested on Linux machine, using GCC compiler.
Use __func__ out of the box. It's been part of the C standard since C99. Change your compiler settings to use at least that standard.
Note that __func__ is not a macro but a predefined identifier which takes the form such that writing it anywhere within a function body is exactly equivalent to using it at that point, having first written
static const char __func__[] = "function-name";
just after the opening brace of a function body.
Formally the behaviour of your current code is undefined. Any symbol containing two consecutive underscores is reserved by the system. (That includes macro names, function names, and variable names.)
Your code as presented gives the expected result (once I'd added the necessary includes and main):
#include <stdio.h>
#ifdef WIN32
#define __FUNCNAME__ __FUNCTION__
#else
#define __FUNCNAME__ __func__
#endif
/* My definitions */
#define MAC() \
MAC1()
#define MAC1() \
myPrintFunction(__FUNCNAME__)
void myPrintFunction(const char * functionName)
{
printf("\n func name: %s \n",functionName);
}
int main()
{
MAC();
}
I compiled this using gcc -std=c11 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds with no warnings.
You should really post a complete (but minimal) example that actually compiles, along with the compiler flags you used, as something must certainly be different to explain the symptoms you describe.
Also, when writing statements as macros, you may find it helpful to use the do {...} while (0) idiom to avoid unexpected expansions changing the control flow.

Stripping specific functions on compile time

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.

Define constant inside #ifdef in C

I want to define a constant depending on the OS in use.
As such:
#include <stdio.h>
#ifdef _Win32 //Used for system("cls") command
#include <process.h>
#define CLEAR "system(\"cls\")"
#endif
#ifdef __APPLE__
#define CLEAR "system(\"clear\")"
#endif
int main()
{
CLEAR;
}
Xcode gives me an error stating that expression result unused at
#define CLEAR "system(\"clear\") and inside the main function.
I am on a Mac.
Use:
#define CLEAR system("clear")
not
#define CLEAR "system(\"clear\")"
You get the error because your macro call is substituted with:
"system(\"clear\")";
which is a useless expression statement (the expression being the string here) like for example:
0; // valid but pointless
try altering your main function as such:
int main()
{
int rc;
rc = CLEAR;
return rc;
}
You need to catch the return value of the system() call and use it
#define CLEAR system("clear")
and not
#define CLEAR "system(\"clear\")"
The compiler will create a new C code (called pre-processor code) in which will replace the macro name by its content.
so if you define macro in this way:
#define CLEAR "system(\"clear\")"
You will get in the new code (pre-processor code) generated by the Compiler:
int main()
{
"system(\"clear\")";
}
You can see the code generated by the compiler (pre-processor code) with gcc -E

Define with only 1 argument

I'm reading external C code, and I found the following line of code:
#define __MAIN_C__
where #define is given only one "argument" (namely __MAIN_C__).
Is this just a placeholder, or can it have a function?
That #define will define __MAIN_C__ to no value (thanks to n.m. and a simple test program). It's a shortcut when you need something #defined when you don't care what it's defined to. In that case, somewhere in your code, you'd probably just see:
#ifdef __MAIN_C__
And that doesn't care what specific value it has, as long as it's defined (and perhaps nonzero).
You'll very often see this for include guards, like so:
#ifndef MYHEADER_H
#define MYHEADER_H
// stuff here
#endif
This is similar to doing this in the compile flags:
gcc -D__MAIN_C__ main.c
If you want to see that it's defined to nothing, try to compile this and watch it fail:
#include <stdio.h>
#define TEST
int main(int argc, char *argv[])
{
printf("%d\n", TEST);
return 0;
}
Yes, this can accomplish something. If you look, there's a pretty decent chance you'll find something like: #ifdef __MAIN_C__ somewhere -- this just checks whether the symbol has been defined, regardless of the value (if any) given.
A define in this case simply sets MAIN_C. No value is assigned, but the preprocessor will interperet MAIN_C as "true". Generally, defines like these are used to include or exclude code before compilation, using something like the following:
#define WIN32
#ifdef WIN32
//some win32-specific code
#else
//some other code
#endif
This definition makes __MAIN_C__ to expand (roughly speaking) to nothing.
A possible use:
#ifdef __MAIN_C__
foo(bar);
#endif
Another one:
#ifdef PLAIN_OLD_OS
#define __MAIN_C__
#else
#define __MAIN_C__ __os_specific_attribute(dllsomething)
#endif
__MAIN_C__ int main (int argc, char* argv[]) {

Resources