7 ms·
Why my print didn't output before a segmentation fault
- rini17 3y agoAm I right to claim C compiler could determine the NULL pointer dereference is an undefined behavior and do anything, like completely removing the dereference?
- kahlonel 3y agoIt’s “undefined behavior” because on certain embedded systems NULL (i.e. 0) is a valid memory address that can be read/written to.
- valleyer 3y agoTechnically (which is the best kind), yes.
- LegionMammal978 3y agoAt least the print and flush will occur before whatever the compiler decides to do with the UB, unless it's one of those purely-theoretical impelementations that can prove that those functions eventually return.
- readams 3y agoI know you already know this but wanted to clarify that technically ub can "go back in time" and not print those earlier statements.
- deleted 3y ago[deleted]
- jcranmer 3y agoI/O is considered a visible side effect, so compilers can't optimize away the call to the print and flush, even if UB happens immediately afterwards.
- Dylan16807 3y agoI'm pretty sure they can. In practical terms, compilers are allowed to reorder calculations, and the print might as well not be there if it's after a crash. In theoretical terms, once UB is guaranteed to happen then your program execution is no longer valid, the entire execution, and the compiler is not bound by any rules whatsoever.
- SpaghettiCthulu 3y agoBut if the compiler can prove that the code causing the UB will be reached regardless of the IO action, could it not assume that the IO action can never be reached, progagating the UB before it?
- lights0123 3y agoCorrect, since unless the program is compiled with -nostdlib, the compiler can assume you're using its printf implementation which does not alter code flow (such as by exit(), longjmp, or exceptions in C++)
- SpaghettiCthulu 3y agoThat's still irrelevant. The compiler can look at any code like this: ``` invokeUB(); doSomething(); ``` and regardless of what `doSomething()` does (it need not be a function call), remove the call entirely if it so chooses. The reason for this is that `doSomething()` cannot be reached except after `invokeUB()`. Because undefined behaviour can be considered unreachable, `invokeUB()` can be too. Therefore, to the compiler, it is impossible to ever reach `doSomething()`, and thus it may be safely eliminated.
- gizmo686 3y agoC compilers are allowed to assume that UB never happens. This means that if there is a code path that results in UB, the compiler can "know" that path will never be taken and simply not compile it (or replace it with code that summons demons through your serial port)
- LargeTomato 3y agoNot the compiler. We don't always know if a reference is null at compile time. Especially if we have hardware that can make references invalid when they otherwise might not be.
- LorenDB 3y agoIn C++, I've absolutely had to explicitly use std::endl while debugging to make sure that my debug messages actually were visible when they were supposed to be. Using std::flush also works if you don't want to force a newline. However, in my experience, printing a newline character via std::cout does not flush the stream.
- cwillu 3y agoMay not be the issue, but if you have your stdout piped into something or redirected to a file, you'll usually get a buffered stream, not a line-buffered one, in which case the \n won't trigger a flush.
- fransje26 3y agoWell, yes, that's by design, as std::cout is buffered. If you want to have visible debug information, you can either: - call << std::flush; - use << std::endl; which is basically equivalent to << "\n" << std::flush; - use std::cerr instead of std::cout, which is unbuffered.
- Taniwha 3y agoFor those who don't know "fflush(0);" flushes ALL FILEs
- jcalvinowens 3y agoIf you use stderr, you get this for free: stderr is always unbuffered (see https://linux.die.net/man/3/stderr https://linux.die.net/man/3/stderr).
- yla92 3y agoI did not know this. Thank you. Updated my blog post!
- throwawaymaths 3y agoThis is why the default-to-teach print in ziglang is std.debug.print -- this goes to stderr and the name implies you should yank them before cutting a release
- yla92 3y agoThat makes sense. For example, with curl, I have been redirecting the output from stderr to stdout with 2>&1 and grep to filter. Now, I am seeing the dots connected why apps like curl sends the output to stderr!
- dvh 3y agoSomewhat similar, if you run program in new xterm with -hold parameter and it crashes, you won't see the segfault, you have to wrap it in parens. xterm -hold -e './a.out' - no segfault xterm -hold -e '(./a.out)' - will print segfault
- tyingq 3y agoYou can also unbuffer stdout in a wrapper then exec your program. GNU-ish systems, including Linux, usually include a command called stdbuf that does this: stdbuf -i0 -o0 -e0 /some/command Where -i is for stdin, -o is for stdout, and -e is for stderr, and the number is the buffer size.
- kahlonel 3y agoUsing setbuf(stdout,NULL) also disables the buffering.