Is it the right way to trap error

Hi,
I make my own real time assert function which can effectively attract a debugger in a program's real time :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void fatal_assert_print(const char* format, va_list arg)
{
	char buf_error[2000];
	vsprintf(buf_error, format, arg);
	std::cout << buf_error << std::endl;
}

static void (*fatal_assert_func)(const char* format, va_list arg) = fatal_assert_print;

inline void fatal_assert(bool condition, std::string error_format, ...)
{
    if(!condition) 
	{
		va_list arg;
		va_start(arg, error_format);
		fatal_assert_func(error_format.c_str(), arg); 
#ifdef DEBUG_MODE
		*((int*)123) = 0;
#else
		std::abort();
#endif
	}
}


Is it the recommended approach? Is it the best way to kill a program itself? Any help would be appreciated.

Thanks.
Last edited on
¿what's the problem with assert()?
you may also abort or throw up.
Last edited on
closed account (E0p9LyTq)
If you are using Visual Studio just compile with "JIT Debugging" enabled.

https://msdn.microsoft.com/en-us/library/5hs4b7a6.aspx?f=255&MSPPError=-2147217396

Well, lookie there, no need to enable JIT debugging, it is turned on by default.
Last edited on
Any sane debugger will allow you to intercept SIGABRT and pause program execution (and I would in fact expect this to be default behavior). EDIT: Thus, I'm hesitant to believe the assertion that assert is "not strong enough to invoke the debugger".

Even if you have a good reason to fish for an abnormal termination by triggering a segfault, why the dereference of a pointer variable in which 123 is stored rather than, say, dereferencing nullptr? More obviously, in that case, why not just raise SIGSEGV?

Additionally, your assert does not list any information such as the file, line, or function that the error originated from, or what the check that failed was. There's also no built-in way to disable it at compile-time. The assert macro has none of those issues.

All it does allow that's arguably an improvement over the assert macro is a user-defined error std::string (which is, by the by, passed by value and written to standard output rather than standard error). You could use that string parameter to print all the information listed above, but any code refactoring will require you to change every single fatal_assert line that got moved, and that becomes an inconvenience.

EDIT2: And even taking that into account, you can hackishly print user-specified messages using the assert macro like so:
assert(some_expression &&"Error message!");

-Albatross

EDIT: Didn't realize there was a reply. Whoops. Edited some pretext.
Last edited on
There's no need. Any debugger can tell exactly the line where the segfault error comes from if it occurs.

Assuming the program is run in a debugger and was compiled in a debugger-friendly manner (debug symbols, limited optimization). Even given the latter, I can think of at least one case in which you're likely to run a such a program outside of a debugger.

I have edited program_assert() macro.

program_assert knocks one issue off the list, but not the rest.

Does it work exactly like "breakpoint" featured in any C++ debugger?

Your debugger or GUI interface thereof should function roughly the same as when a segfault happens. My copy of gdb halts when that happens and I'm told Visual C++'s debugger does as well.

How?

std::raise().

Dereferencing nullptr may not be "fatal-ish" enough due to that the memory address is never used. 123 is a more valid memory address and may contain protected data, so I think this will do.

If you really want the assertion to be fatal, then why not avoid relying on undefined behavior? You yourself said that 0x7B *may* contain protected data, that means you don't trust that it always will kill your program. In fairness, dereferencing nullptr is also undefined, I was just curious why you chose one "solution" over the more obvious.

Remember that (some_expression && "Error message!") always evaluates to 1.

Nope. Wrong. No way around this one, this is just dead wrong, and I do have code that demonstrates as much. Of course, you came to the same conclusion and deleted that message just before I replied, because I like to take my time with my posts, and put as much as I can into one post rather than triple or quadruple posting.

EDIT: Probably should clarify that this was in the context of the assert macro.

-Albatross
Last edited on
nullptr cannot be a valid memory address. It's literally used as a way to say, "invalid pointer". Dereferencing a location in memory that isn't valid or isn't assigned to your process should give a segmentation fault (with a few exceptions).

Accessing the address "123" doesn't make any sense and conceptually could be a valid pointer... and thus not crash.

https://en.wikipedia.org/wiki/Assert.h
Personally, I would just use standard assert. Any modern debugger will know to jump at an failed assert (don't know of any that hasn't off the top of my head).

static_assert is perhaps an actual problem although that's for a different topic.

EDIT: Fixed some bad wording.
Last edited on
The program totally ignores assert() when running in release mode.

It's designed that way. http://pubs.opengroup.org/onlinepubs/009695399/basedefs/assert.h.html

Just make sure NDEBUG isn't defined before you include cassert or assert.h.

EDIT: Obligatory mention that you probably shouldn't use an assert check in a release build...

I have updated my fatal_assert() function. What do you think? :)

It looks like garbage. You're still assuming dereferencing a potentially valid address is a good idea, you go out of your way to provide functionality that nobody will need or even should use (va_args for a single output message), and you don't solve a single damn problem with your "solution".
Last edited on
> I have updated my fatal_assert() function. So what are your opinions?

Do not, repeat DO NOT, use it.

How many times do you have to be told that if you use it, your entire program would have undefined behaviour?
closed account (E0p9LyTq)
Just take a sledge hammer to your computer so you can let the smoke out. 100% successful in killing processes.

"closed account," you ASKED if your code was the right way to trap errors. That was the proper thing to do. Ask for advice from people with EXPERIENCE.

What you did when told it was NOT was argue and argue and tell people you know more than they do.

Here was an attempt by me to write some code that I thought at the time would be a great reusable bit of code. I was told NO in no uncertain terms, and I was able to take the advice to heart instead of endlessly argue I knew better (I don't):

http://www.cplusplus.com/forum/beginner/170108/
Last edited on
If you wanted to kill with high chance success, you would still call std::abort or std::terminate. Better yet, throw an exception. I'm not the largest fan of exceptions as a language mechanism, but this sort of thing is exactly what they were supposed to do: indicate that an exceptional and potentially fatal issue has occurred with your program, and give a way to recover from it. And really, you *do* want a way to recover. Your program not crashing is a good thing. Seriously.

Making a fatal_assert that works in release builds, I must say, is a silly idea. "Release" implies that you believe your program is in a suitable state to release. If your program reaches a state where an assert would get tripped, then your program was not suitable to release. The use of assert is to check for erroneous conditions while debugging that are usually generated from improper use of code, and debugging a release program (which gets optimized and refactored by your compiler) is a silly idea. If a released program encounters issues, then the best thing to do would be to compile a debug build and test there.

Now, it is fine to include mechanisms in a release program to record some state information and maybe some helpful metadata if your program reaches some unforseen issues. You've seen crash reporters, right? However, the use of assert (and by extension, fatal_assert) means that you have forseen those problems. Whoops.

One last thing. Undefined behavior must be paid attention to, because it inserts the worst form of ambiguity into your program. The ambiguities in the English language pale in comparison to undefined behavior. Your compiler and program are free to do whatever when they meet undefined behavior. Relying on something to happen or some meaning to be drawn when you communicate ambiguously is stupid. You may be able to make some predictions on what meaning will be drawn based on intimate knowledge of who you're communicating with (which is not the case as far as you're concerned), but that prediction cannot be generalized. So don't make it. Don't rely on undefined behavior.

TL;DR: Not writing one. Read the post.

-Albatross
Last edited on
I give up. There's no way he's not trolling.
Topic archived. No new replies allowed.