| 1 | /* | 
|---|
| 2 | * Assert.hpp | 
|---|
| 3 | * | 
|---|
| 4 | *  Created on: Mar 18, 2010 | 
|---|
| 5 | *      Author: crueger | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 | #ifndef ASSERT_HPP_ | 
|---|
| 9 | #define ASSERT_HPP_ | 
|---|
| 10 |  | 
|---|
| 11 | #include<string> | 
|---|
| 12 | #include<vector> | 
|---|
| 13 |  | 
|---|
| 14 | /** | 
|---|
| 15 | * \file Helpers/Assert.hpp | 
|---|
| 16 | * <H1> ASSERT Howto </H1> | 
|---|
| 17 | * | 
|---|
| 18 | * <H2> Introduction </H2> | 
|---|
| 19 | * | 
|---|
| 20 | * ASSERT() is a small macro that allows easier debugging, when it is widely used. The custom | 
|---|
| 21 | * ASSERT macro defined in this file works mainly the same way as the assert() macro that | 
|---|
| 22 | * is defined in the Ansi-C standard, but includes a few nice additions. | 
|---|
| 23 | * | 
|---|
| 24 | * <H3> What ASSERT() does </H3> | 
|---|
| 25 | * | 
|---|
| 26 | * ASSERT can be used to make sure that a condition that always needs to be true for the code to | 
|---|
| 27 | * work correctly is holding. If you have a function that takes a value greater than 0 and a value | 
|---|
| 28 | * smaller than 0 indicates a mistake you should always do it the following way: <br> | 
|---|
| 29 | * @code | 
|---|
| 30 | * void foo(int a) // a should be greater 0 | 
|---|
| 31 | * { | 
|---|
| 32 | *  ASSERT(a>0,"Parameter passed to foo was smaller than 0"); | 
|---|
| 33 | *  ... | 
|---|
| 34 | * } | 
|---|
| 35 | * @endcode | 
|---|
| 36 | * | 
|---|
| 37 | * (Note: some people say, that assertions like these should not be used to check function parameters. | 
|---|
| 38 | * This is mainly due to the reason, that a failed assertion will show up inside the function. The buggy | 
|---|
| 39 | * code however is at a completely different place, i.e. at the callers side. Always put the | 
|---|
| 40 | * Assertions as close to the code that produces the value as possible, when looking at function | 
|---|
| 41 | * parameters however this would mean, that any code calling foo would have an ASSERT(...) before | 
|---|
| 42 | * it, which makes it easy to forget the Assertion at some places. Also this makes an easy example.) | 
|---|
| 43 | * | 
|---|
| 44 | * If the condition inside the ASSERT does not evaluate to true the user is shown a message, including | 
|---|
| 45 | * the condition that failed, the line in which the failure was observed and the message of the assertion. | 
|---|
| 46 | * In the above case that would look something like this:<br> | 
|---|
| 47 | * @code | 
|---|
| 48 | * Assertion "a>0" failed in foo.cpp in line 3. | 
|---|
| 49 | * Assertion Message: Parameter passed to foo was smaller than 0 | 
|---|
| 50 | * @endcode | 
|---|
| 51 | * | 
|---|
| 52 | * In normal conditions, i.e. when no default action is set (see below for default actions) the user | 
|---|
| 53 | * is then shown a short choice menu, on how to handle the assertion. The user can choose to abort the | 
|---|
| 54 | * program, throw an exception of type AssertionFailure that contains the file, line and message, | 
|---|
| 55 | * ignore the assertion or even to always ignore the assertion at that point (i.e. the ASSERT() macro | 
|---|
| 56 | * at this file and line is fully disabled). | 
|---|
| 57 | * | 
|---|
| 58 | * Both ASSERT() and assert() handle debugging in the same way, i.e. they are only used when the | 
|---|
| 59 | * NDEBUG macro is not defined. If the NDEBUG macro is defined, for example using a CXXFLAG then | 
|---|
| 60 | * all asserts and ASSERTs will be disabled in the compiled program. That way in a end-user version | 
|---|
| 61 | * all assertions can be removed with a single switch, thus not hassling the end-user with potential | 
|---|
| 62 | * bugs. | 
|---|
| 63 | * | 
|---|
| 64 | * <H2> Special functions of ASSERT() </H2> | 
|---|
| 65 | * | 
|---|
| 66 | * Compared to the standard assert() macro the custom ASSERT() contains a few special functions. As | 
|---|
| 67 | * first it is possible to set a global default behavior that is used anytime an assertion fails. | 
|---|
| 68 | * This default behavior can be either of Assert::Ask, Assert::Abort, Assert::Throw or Assert::ignore. | 
|---|
| 69 | * The default behavior is set using the ASSERT_DO() macro. For example if you want to check in a | 
|---|
| 70 | * unittest that wrong code at another point actually makes a certain assert fail you could set | 
|---|
| 71 | * ASSERT_DO(Assert::Throw) to make sure a exception is thrown and catch that exception using | 
|---|
| 72 | * the CPPUNIT_ASSERT_THROW() macro. The current set default behavior can be queried as a string | 
|---|
| 73 | * using the ASSERT_DEFAULT macro. | 
|---|
| 74 | * | 
|---|
| 75 | * As a second enhancement it is possible to install callback functions as hooks that will be executed | 
|---|
| 76 | * when an assertion aborts the program. These callback functions could for example be used to flush | 
|---|
| 77 | * any open streams, thus making sure files on the disk are not corrupted by a unexpected abortion. | 
|---|
| 78 | * It would also be possible to install functions that produce some kind of "coredump" of important | 
|---|
| 79 | * internal data-structures, thus giving the person looking for the bug some valuable information. | 
|---|
| 80 | * These assertion hooks should however not be used to clean up the reserved memory of the program, | 
|---|
| 81 | * because a) this memory is under normal circumstances reclaimed by the OS anyway, once the program | 
|---|
| 82 | * has aborted and b) the memory might still contain some hints that could be useful when running | 
|---|
| 83 | * the program inside a debugger and which could be destroyed by the clean-up. To use the hooking | 
|---|
| 84 | * mechanism you can simply use the ASSERT_HOOK() macro, passing this macro any kind of void function. | 
|---|
| 85 | * For example:<br/> | 
|---|
| 86 | * @code | 
|---|
| 87 | * void foo(){ | 
|---|
| 88 | *   // produce a coredump | 
|---|
| 89 | *   ... | 
|---|
| 90 | *   // close and flush all open handles | 
|---|
| 91 | *   ... | 
|---|
| 92 | * } | 
|---|
| 93 | * | 
|---|
| 94 | * int main(int argc, char **argv){ | 
|---|
| 95 | *   ASSERT_HOOK(foo); | 
|---|
| 96 | *   ... | 
|---|
| 97 | *   return 0; | 
|---|
| 98 | * } | 
|---|
| 99 | * @endcode | 
|---|
| 100 | * | 
|---|
| 101 | * All hooks will be executed in the reverse order of hooking, i.e. the function hooked last will be | 
|---|
| 102 | * executed first when the abortion is handled. It is also possible to remove a hook to any function | 
|---|
| 103 | * using the ASSERT_UNHOOK() macro and passing it the pointer to the function one wants to remove. | 
|---|
| 104 | * | 
|---|
| 105 | * Assertion hooks will only be executed when the program is terminated by an assertion using the | 
|---|
| 106 | * abort mechanism. They will not be executed when the program exits in any other way. They also | 
|---|
| 107 | * wont be executed when the assertion is ignored or an exception is thrown (even when the exception | 
|---|
| 108 | * is not caught and thus terminates the program). | 
|---|
| 109 | * | 
|---|
| 110 | * <H2> Rules for using ASSERT() </H2> | 
|---|
| 111 | * | 
|---|
| 112 | * The rules for using ASSERT() are basically the same ones that can be used as guidlines for the | 
|---|
| 113 | * standard assert() macro. So if you think you know those guidelines you can skip the following. | 
|---|
| 114 | * | 
|---|
| 115 | * <ul> | 
|---|
| 116 | * <li> ASSERT() should be used only for problems that indicate a bug, i.e. problems that can be | 
|---|
| 117 | * improved by rewriting parts of the program. ASSERT() should not be used to query problems that | 
|---|
| 118 | * can go wrong during the normal execution of the program. For example ASSERT() should not be | 
|---|
| 119 | * used to test whether a file could be opened, or memory could be reserved, as a failure of either | 
|---|
| 120 | * of those tasks can not be improved upon by rewriting the code. | 
|---|
| 121 | * <li> The condition in the ASSERT() macro should never contain any side-effects. Only call methods, | 
|---|
| 122 | * when you are absolutely certain that these methods wont have any side-effects. Calling ASSERT() | 
|---|
| 123 | * should in no way change the state of the program, because once the end-user version is produced | 
|---|
| 124 | * using the NDEBUG flag all assertions are removed and so are the conditions. If the condition did | 
|---|
| 125 | * cause a state transition, this state transition would be removed and the behavior of the end-user | 
|---|
| 126 | * and the debug version might differ. Things you should watch out for are for example<br/> | 
|---|
| 127 | * @code | 
|---|
| 128 | * ASSERT(++i,"i was zero after incrementing"); | 
|---|
| 129 | * @endcode | 
|---|
| 130 | * instead always do | 
|---|
| 131 | * @code | 
|---|
| 132 | * ++i; | 
|---|
| 133 | * ASSERT(i,"i was zero after incrementing"); | 
|---|
| 134 | * @endcode | 
|---|
| 135 | * <li> Give descriptive error messages. This one is a bit obvious but easy to do wrong, so I included | 
|---|
| 136 | * it here. An | 
|---|
| 137 | * @code | 
|---|
| 138 | * ASSERT(ptr,"Pointer was zero"); | 
|---|
| 139 | * @endcode | 
|---|
| 140 | * wont help anyone. If you do <br/> | 
|---|
| 141 | * @code | 
|---|
| 142 | * ASSERT(ptr,"Second argument of function foo should have pointed to an object of type bar, but was zero."); | 
|---|
| 143 | * @endcode | 
|---|
| 144 | * instead, people will almost immidiately know what to look for. | 
|---|
| 145 | * </ul> | 
|---|
| 146 | * | 
|---|
| 147 | * <H2> Differences between ASSERT() and assert() </H2> | 
|---|
| 148 | * | 
|---|
| 149 | * This chapter is to explain why a custom ASSERT() macro was introduced and should be used in place | 
|---|
| 150 | * of the standard assert(). Here are the main differences between ASSERT() and assert(). | 
|---|
| 151 | * | 
|---|
| 152 | * <ul> | 
|---|
| 153 | * <li> ASSERT() makes it easy to add a more verbose message about the nature of the failure. For | 
|---|
| 154 | * assert() it has become customary to add messages using constructs like | 
|---|
| 155 | * @code | 
|---|
| 156 | * assert(c>0 && "Counter should be at least 1"); | 
|---|
| 157 | * @endcode in order to add descriptions. However both the syntax and the final output for this are | 
|---|
| 158 | * a bit awkward. The custom ASSERT() handles messages in a much better way, as well as making them | 
|---|
| 159 | * mandatory instead of optional. | 
|---|
| 160 | * <li> ASSERT() leaves the user and the programmer a choice how to handle an assertion. While the | 
|---|
| 161 | * assert() macro will always abort the program, the ASSERT() macro normally gives the user a choice on | 
|---|
| 162 | * what to do. For debugging it might also be interesting how a broken assumption influences the rest | 
|---|
| 163 | * of the program, so the assertion can also be ignored. Also the Exception mechanism allows | 
|---|
| 164 | * assertions to be part of unittests, whereas they would always fail if the assert() macro was used. | 
|---|
| 165 | * <li> ASSERT() does not unwind the stack (at least when compiled using gcc). The normal assert() | 
|---|
| 166 | * exits the program, which unwinds the stack and destroys any hope for recovering a stack trace. | 
|---|
| 167 | * ASSERT() on the other hand aborts the program using a special trap function, that leaves the | 
|---|
| 168 | * stack intact. This way, when the program is run inside a debugger the stack is still available | 
|---|
| 169 | * and can be inspected. This is the main reason, why it is safe to use ASSERT() to check function | 
|---|
| 170 | * parameters, whereas assert() would give problems in such cases. | 
|---|
| 171 | * <li> ASSERT() allows for hooks to be installed when the program exits. As mentioned above this | 
|---|
| 172 | * makes it possible to produce coredumps, make sure all files are in a usable state or other tasks | 
|---|
| 173 | * that have to be performed before killing the program. | 
|---|
| 174 | * </ul> | 
|---|
| 175 | * | 
|---|
| 176 | * <H2> Tips and tricks and FAQ </H2> | 
|---|
| 177 | * | 
|---|
| 178 | * <ul> | 
|---|
| 179 | * <li> <H4> ASSERT() is broken. When I abort the program it says something about an | 
|---|
| 180 | * "Illegal instruction"</H4> | 
|---|
| 181 | * The complaints about the illegal instruction after an abortion are no need to worry. This | 
|---|
| 182 | * illegal instruction is part of the trap that is used to exit the program while leaving the stack | 
|---|
| 183 | * intact. This illegal instruction can be detected by the debugger, which means it will give you the | 
|---|
| 184 | * usual prompt once it is encountered. The illegal instruction is guaranteed not to mess up anything, | 
|---|
| 185 | * so there is no need to worry about it. | 
|---|
| 186 | * <li> <H4> When compiling the program with $NON_GCC_COMPILER and then debugging it, it will | 
|---|
| 187 | * unwind the stack. I need the backtrace however to find the bug </H4> | 
|---|
| 188 | * The mechanism to preserve the stack is compiler specific. For now only a mechanism that is supported | 
|---|
| 189 | * by gcc is implemented, because this compiler is widely used. For other compilers the program | 
|---|
| 190 | * is simply exited, and the stack is destroyed. If you need a backtrace and you cannot use gcc you | 
|---|
| 191 | * have to figure out a way to have your compiler produce a trap instruction in the program. You might | 
|---|
| 192 | * want to use google to find out how to get your compiler to do that. For many compilers a | 
|---|
| 193 | * _asm {int 3} is said to work. Also for VC++ the instruction __debugbreak() might produce a trap. | 
|---|
| 194 | * Also dividing by zero is a hack that could be used as a last hope if you don't find a way to produce | 
|---|
| 195 | * traps with your compiler even after a longer search. If you found a way to handle the traps you can | 
|---|
| 196 | * then add the macro DEBUG_BREAK for your compiler and the stack will be preserved. | 
|---|
| 197 | * <li> <H4> I have a portion of the program that should never be executed. How can I assure this | 
|---|
| 198 | * using assert.</H4> | 
|---|
| 199 | * This is a common task for assertions. For example you might have an exhaustive switch/case where | 
|---|
| 200 | * the default value indicates that something went wrong. Simply use the following construct: | 
|---|
| 201 | * @code | 
|---|
| 202 | * switch(foo){ | 
|---|
| 203 | *   case Bar: | 
|---|
| 204 | *     ... | 
|---|
| 205 | *     break; | 
|---|
| 206 | *   case Baz: | 
|---|
| 207 | *     ... | 
|---|
| 208 | *     break; | 
|---|
| 209 | *   ... | 
|---|
| 210 | *   default: | 
|---|
| 211 | *     ASSERT(0,"This switch should always be exhaustive.\nDid somebody add values to the enum?"); | 
|---|
| 212 | * } | 
|---|
| 213 | * @endcode | 
|---|
| 214 | * </ul> | 
|---|
| 215 | */ | 
|---|
| 216 |  | 
|---|
| 217 | namespace Assert{ | 
|---|
| 218 |  | 
|---|
| 219 | typedef void (*hook_t)(void); | 
|---|
| 220 |  | 
|---|
| 221 |  | 
|---|
| 222 | enum Action {Ask,Abort,Throw,Ignore,MAX_ACTION}; | 
|---|
| 223 | extern const char  ActionKeys[MAX_ACTION]; | 
|---|
| 224 | extern const char* ActionNames[MAX_ACTION]; | 
|---|
| 225 |  | 
|---|
| 226 | class AssertionFailure{ | 
|---|
| 227 | public: | 
|---|
| 228 | AssertionFailure(std::string _condition, std::string _file, int _line, std::string _message); | 
|---|
| 229 | std::string getFile(); | 
|---|
| 230 | int getLine(); | 
|---|
| 231 | std::string getMessage(); | 
|---|
| 232 |  | 
|---|
| 233 | std::ostream& operator<<(std::ostream&); | 
|---|
| 234 | private: | 
|---|
| 235 | std::string condition; | 
|---|
| 236 | std::string file; | 
|---|
| 237 | int line; | 
|---|
| 238 | std::string message; | 
|---|
| 239 | }; | 
|---|
| 240 | } | 
|---|
| 241 |  | 
|---|
| 242 | #ifndef NDEBUG | 
|---|
| 243 | #ifndef STRINGIFY | 
|---|
| 244 | #define STRINGIFY(x) #x | 
|---|
| 245 | #endif | 
|---|
| 246 |  | 
|---|
| 247 | #ifdef __GNUC__ | 
|---|
| 248 | // on gcc we know how to exit to the Debugger | 
|---|
| 249 | #define DEBUG_BREAK __builtin_trap() | 
|---|
| 250 | #else | 
|---|
| 251 | #define DEBUG_BREAK exit(1) | 
|---|
| 252 | #endif | 
|---|
| 253 |  | 
|---|
| 254 | #define ASSERT(condition,message) \ | 
|---|
| 255 | do{\ | 
|---|
| 256 | static bool ignore = false;\ | 
|---|
| 257 | if(!ignore){\ | 
|---|
| 258 | if(_my_assert::check((condition),STRINGIFY(condition),(message),__FILE__,__LINE__,ignore)){\ | 
|---|
| 259 | _my_assert::doHooks();\ | 
|---|
| 260 | DEBUG_BREAK;\ | 
|---|
| 261 | }\ | 
|---|
| 262 | } \ | 
|---|
| 263 | }while(0) | 
|---|
| 264 |  | 
|---|
| 265 | #define ASSERT_DO(action)    do{_my_assert::setDefault(action);}while(0) | 
|---|
| 266 | #define ASSERT_HOOK(hook)    do{_my_assert::addHook(hook);}while(0) | 
|---|
| 267 | #define ASSERT_UNHOOK(hook)  do{_my_assert::removeHook(hook);}while(0) | 
|---|
| 268 | #define ASSERT_DEFAULT       (_myAssert::printDefault()) | 
|---|
| 269 | #else | 
|---|
| 270 | // we need to do something, so this is the usual solution (e.g. assert.h) | 
|---|
| 271 | #define ASSERT(condition,message) (void)(0) | 
|---|
| 272 | #define ASSERT_DO(action)         (void)(0) | 
|---|
| 273 | #define ASSERT_HOOK(hook)         (void)(0) | 
|---|
| 274 | #define ASSERT_UNHOOK(hook)       (void)(0) | 
|---|
| 275 | #define ASSERT_DEFAULT            std::string("Deactivated") | 
|---|
| 276 | #endif | 
|---|
| 277 |  | 
|---|
| 278 | //! @cond | 
|---|
| 279 | class _my_assert{ | 
|---|
| 280 | public: | 
|---|
| 281 | static bool check(const bool res, | 
|---|
| 282 | const char* condition, | 
|---|
| 283 | const char* message, | 
|---|
| 284 | const char* filename, | 
|---|
| 285 | const int line, | 
|---|
| 286 | bool& ignore); | 
|---|
| 287 | static void addHook(Assert::hook_t hook); | 
|---|
| 288 | static void removeHook(Assert::hook_t hook); | 
|---|
| 289 | static void doHooks(); | 
|---|
| 290 | static void setDefault(Assert::Action); | 
|---|
| 291 | static Assert::Action getDefault(); | 
|---|
| 292 | static std::string printDefault(); | 
|---|
| 293 | private: | 
|---|
| 294 | static Assert::Action defaultAction; | 
|---|
| 295 | static std::vector<Assert::hook_t> hooks; | 
|---|
| 296 | }; | 
|---|
| 297 | //! @endcond | 
|---|
| 298 |  | 
|---|
| 299 |  | 
|---|
| 300 | #endif /* ASSERT_HPP_ */ | 
|---|