Hacker News new | past | comments | ask | show | jobs | submit login
Why my print didn't output before a segmentation fault (yelinaung.com)
38 points by yla92 11 months ago | hide | past | favorite | 21 comments



If you use stderr, you get this for free: stderr is always unbuffered (see https://linux.die.net/man/3/stderr).


I did not know this. Thank you. Updated my blog post!


This 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


That 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!


In 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.


May 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.


Well, 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.


For those who don't know "fflush(0);" flushes ALL FILEs


Am I right to claim C compiler could determine the NULL pointer dereference is an undefined behavior and do anything, like completely removing the dereference?


Technically (which is the best kind), yes.


At 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.


I know you already know this but wanted to clarify that technically ub can "go back in time" and not print those earlier statements.


I/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.


C 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)


But 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?


Correct, 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++)


That'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.


I'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.


Not 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.


Somewhat 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


You 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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: