source: src/Helpers/Assert.hpp@ dfafe7

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since dfafe7 was cfc53b, checked in by Frederik Heber <heber@…>, 14 years ago

Added template function toString(), is included in Assert.hpp.

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