Take the 2-minute tour ×

In C and C++ assert is a very heavyweight routine, writing an error to stdout and terminating the program. In our application we have implemented a much more robust replacement for assert and given it its own macro. Every effort has been made to replace assert with our macro, however there are still many ways assert can be reintroduced (e.g., from internal third-party libraries, naïve injection, etc.)

Any suggestions on how we can reduce, limit or even eradicate uses of assert? The best answer will be one the compiler can catch for us so we don't have to babysit the code base as much as we do currently.

share|improve this question
What exactly is wrong with assert() terminating the program? –  Alex B Dec 4 '09 at 0:53
Well, for one, the program terminates leaving assert() only valid for OMG YOU BROKE THE UNIVERSE errors. Wouldn't it suck to be the user and have the program crash because your count of TPS report headers is off by one? Maybe you just want it to log the failed assertion so the user can continue what they're doing. Maybe you want to be send the assert failure rather than relying on the puzzled and annoyed user to know to do that. –  Schwern Dec 4 '09 at 0:56
If your users are running debug builds, you have more serious problems. Assertions and logging are entirely different things, and should not be confused. –  Tim Sylvester Dec 4 '09 at 0:59
Sounds to me like you're using assert when you should be using exceptions. Assert is a debugging tool. It's not for program logic. That's why when you build in release mode, assert is compiled to nothing. –  Cogwheel Dec 4 '09 at 1:09
Out of curiosity, why was the question downvoted? It seems like a good question, worth learning the answer to even if the premises it's built on are no good. –  Platinum Azure Dec 4 '09 at 2:09

10 Answers 10

up vote 13 down vote accepted

I'm not sure I really understand the problem, actually. Asserts are only expensive if they go off, which is fine anyway, since you're now in an exception situation.

assert is only enabled in debug builds, so use the release build of a third-party library. But really, asserts shouldn't be going off every moment.

share|improve this answer
They don't go off every moment, but given the size of our application we want to do more than simply disappear in the event an assertion fails. The ability to handle an assertion failure more gracefully provides a huge benefit to both QE and development. –  fbrereto Dec 4 '09 at 1:11
@fbrereto: You should throw exceptions instead of calling assert. –  Frank Dec 6 '09 at 4:06

it would depend (at least in part) on what you're changing. Assuming that you don't mind it printing out its normal message, and mostly want to get rid of it calling abort(), you could consider leaving assert() alone, and instead defining your own version of abort(). In theory, doing that isn't portable -- but in reality, abort() is a fairly normal function in the standard library, and if you link your own instead, you get its behavior. Sometimes (especially some Microsoft linkers) you have to do a bit of work to get the linker to cooperate in replacing their abort() with yours, but it's rarely very difficult.

share|improve this answer

It can be handy to improve upon the built-in assertion facility (to provide stack traces, core dumps, who knows). In that case, if you're having problems getting your developers to follow whatever standards you have (like "instead of assert() use SUPER_ASSERT()" or whatever), you can just put your own assert.h header in the include path ahead of the compiler's runtime directory of headers.

That'll pretty much guarantee that anyone using the standard assert() macro will get a compiler error or get your assertion functionality (depending on what you have your assert.h header do).

share|improve this answer
Ah, the directory path preemption is clever! –  fbrereto Dec 4 '09 at 17:07
SUPER_ASSERT - hove you read John Robbins book? I picked up John's habit of asserting everything all the time - from state to parameters to return values. My code can't fart or sneeze without me knowing about it. It literally debugs itself (I spend less that 2 minutes under a debugger when tracing problems). I really pity people who don't use them. You can tell who they are - they are the ones concentrating intensely while starring at the debugger for hours throughout the day (or the ones adding all those useless printfs). –  jww Jan 17 at 10:55
@noloader: yes I have most (maybe all) of John Robbin's books. Definitely good stuff. –  Michael Burr Jan 17 at 11:02

I think your question is totally valid. If you have you have implemented you own error handling you may want to

  1. Always trigger asserts even in release builds.
  2. Implement better error reporting in case an assert triggers. You may want to send error reports or write to log files.

That being said, I don't see any solution that always works.

  • If you are lucky, the 3rd party libraries use ASSERT macros that you can redefine yourself as long as the file defining this macro has some sort of #pragma once or #ifndef __HEADERFILE_H__ #define __HEADERFILE_H__ provision against multiple inclusion. Include the header file separately, redefine ASSERT and you're good.

  • If they directly include assert.h or cassert you can only patch the code I guess. Make minimal code changes, save the changes as patch files and when you update the library hope that the patches still work. Add the patches to version control.

    If this doesn't work, rethink the question if you really need internal asserts in 3rd party libraries. Ship release builds only, this gets rid of the asserts, and add your ASSERTs to check for correctness inside your code. Check for validity of return values. If such an ASSERT is triggered, you can still dive into the 3rd party code to see what caused the problem.

share|improve this answer

I think the question is valid.

My very own assert expands to asm("int3") if triggered, which is equivalent to a breakpoint. I also found that vastly more useful for debugging than a simple termintation.

I simply called it "ASSERT()" instead of the normal "assert()" and avoided the use of assert() at all.

share|improve this answer

The most obvious approach would seem to be to give your own version of assert its own name, slightly different from assert(). Then you can search the text, look at linker messages, etc., for the literal string "_assert" and you know you have a problem when you see it.

In my own code, I always use Assert(), which expands to my own function that performs an assertion, or expands to ((void)0) for the release build. The compiler will turn the ((void)0) expression into nothing, but it still counts as an expression. Thus

Assert(3 == x);

will turn into


and the semicolon has a place to go.

By the way, I once worked on a GUI application where the assert was a special GUI modal popup dialog. You had three choices: Ignore, Ignore forever, or Break. Ignore would ignore the assert and keep running. Ignore forever would set a flag, and until you restarted the program in the debugger, that assert would not fire anymore. Break would allow the assert to break into the debugger.

I don't remember how they guaranteed that each assert had its own flag. Maybe when you wrote the Assert() call you had to specify a unique integer? It would be nice if it was more automatic than that. I'm pretty sure that the actual implmentation was a bit vector, and it would set the bit when you chose ignore forever.

share|improve this answer
Or, after writing "myAssert", instead of looking for "assert" everywhere, just "#define assert myAssert" and let the preprocessor do the work. I DO NOT ADVOCATE THIS, I'm just saying it can be done. –  Beta Dec 4 '09 at 1:02
@Beta:In most cases, that #define would work -- but for assert it really won't. Since the meaning of assert() can change (even in a single source file) based on whether NDEBUG is defined, it can/will be #undef'd and #define'd again behind your back. –  Jerry Coffin Dec 4 '09 at 1:20
@Jerry Coffin: I'm out of my depth here (and my impression is that there's no safety once macros are at war) but couldn't one undefine NDEBUG, either in a header or in the makefiles (or both)? Wouldn't that stop casual attempts to assert? –  Beta Dec 4 '09 at 2:15
The whole purpose of NDEBUG is to allow you to compile some code one way for your "debug" build, and another way for your "release" build. For example, the debug build has asserts, and the release build has nothing at all for asserts. So, defining NDEBUG for all builds means you get only a release build and no debug build. We actually want asserts in our debug build. I use asserts heavily in my code; they cost exactly nothing in the release build, so they are a great tool. –  steveha Dec 4 '09 at 2:54

If source code is under your control :

#define NDEBUG
// before
#include <assert.h> 
// or other header that includes assert.h

Or using precompiled header or compile options to define NDEBUG

For third-part binaries, using release version of them?

share|improve this answer

assert() is usually #define'd to be ((void)0) for release code (#define NDEBUG), so there is no overhead at all.

When using a testing version, is the performance overhead hurting your ability for the testing to be realistic?

share|improve this answer
Pleas see my comment to GMan –  fbrereto Dec 4 '09 at 1:11
A valid implementation of assert() cannot be defined to be empty for release code. For example, something like assert(x), y=0; is legitimate code, but would produce a syntax error if assert() became nothing in a release. A correct implementation would become something like ((void *)0) when NDEBUG was defined. –  Jerry Coffin Dec 4 '09 at 1:12
You can just use ((void)0), not need for pointer. :) –  GManNickG Dec 4 '09 at 1:32
@Gman:Quite right -- my fingers "know" about casts to 'void *', but not 'void'... –  Jerry Coffin Dec 4 '09 at 1:37
corrected to use 0; –  Cade Roux Dec 4 '09 at 1:47

You seem to be missing the fact that the third-party code is most likely written under the assumption of "standard" assert behavior. I.e. the code expects the program to terminate on failed assertion. The code that follows the assertion normally cannot and will not work correctly if the asserted condition is broken. In 99 cases out of 100 it will not work at all. In 99 cases out of 100 it will simply crash, i.e. the program will terminate anyway.

To believe that by overriding the assert behavior in third-party code you will somehow make the program live longer is naive at best.

share|improve this answer
To assume the OP didn't already know that is naive at best. Did it ever cross your mind, that core dump, a stack trace, even a normal crash will provide more useful information for debugging? –  hirschhornsalz Dec 4 '09 at 12:16
@hirschhornsalz - I don't know many people who can read crash dumps effectively. Plus, its never appropriate for a third party library to crash your program. The library should either either process the request or they fail the call - crash (or shit all over themselves) is not an appropriate choice. –  jww Jan 17 at 11:06

Find assert in the library headers (assuming they're real files on your file system) and replace it with an invalid thing

// #define assert(condition) ... /* old definition */
#define assert(condition) ((condition) & "PLEASE DO NOT USE ASSERT" = 42)
share|improve this answer
And remember to do that again (and again ...) everytime you upgrade your compiler. –  pmg Dec 4 '09 at 1:00
For "an invalid thing" I like to use: #pragma error The great thing is that this has almost the same effect whether the compiler supports it as a feature, or not. And it pretty clearly identifies that you intend an error there. –  steveha Dec 4 '09 at 1:01
@steveha: I'm not sure you can use a #pragma error in a #define. I can't point to the location in the standard immediately, but I do not think it does what you think it does. –  fbrereto Dec 4 '09 at 1:09
@fbrereto: you're right: C99, § says: "The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one, but all pragma unary operator expressions within it are then processed as specified in 6.10.9 below." A "pragma unary operator" is a _Pragma, not a #pragma. –  Jerry Coffin Dec 4 '09 at 1:17
Sorry, I had to downvote this. Fiddling with system-wide library headers is a really, really bad idea, since it will potentially break every other program that you compile, or even the standard library itself. –  Daniel Albuschat Jul 29 at 5:15

Your Answer


