问题
In the manual about functions of buffer-using given at http://man7.org/linux/man-pages/man3/setbuf.3.html, a piece of code below is declared as invalid. However, when I try that on my machine, things go well:
#include <stdio.h>
int
main(void)
{
char buf[BUFSIZ];
setbuf(stdin, buf);
printf("Hello, world!\n");
return 0;
}
The reason given by that age is :
You must make sure that the space that buf points to still exists by the time stream is closed, which also happens at program termination.
I can't see any mistake in that piece of code. And it also goes well too. Is it right or not? Can any one explain it to me?
################################################2as @Lingxi have answered below, the buffer will be destroyed after the main function return. But stdin survive.
But, is there a default buffer left for the stdin ?
And also, can we assume that the stdin is a stream, and there is some ways to destroyed or close that stream?
回答1:
This is an example of undefined behavior. Undefined behavior is not a magic error message that pops up and tells you your program is wrong. It means your program is dangerous. The worst thing that can happen with UB is exactly what happened to you -- no visible symptoms at all. This is because the bug goes undetected, and could later lead to extremely dangerous things. For example if the read buffer is refilled during the exit code that runs after main returns (atexit handlers, C++ dtors, stdio file shutdown that happens at exit, etc.) then the return address of some other function on the stack could be clobbered, and this could lead to arbitrary code execution vulnerabilities.
When documentation for a C interface tells you you can't do something, trust it. Testing to see if it "works" is not a meaningful activity unless you're trying to figure out how to exploit such bugs.
回答2:
The error message has explained it quite clearly. In your code snippet, buf is destroyed when main returns, but the lifetime of stdin spans beyond main. During the time period after main has returned but before stdin is closed, you would have an opened stdin with an invalid buffer. This may cause problems sometimes. As an example, what do you think would happen if there is a global class object whose destructor uses stdin for input?
You may also want to have a look at this question.
回答3:
The reason this code fails is simply because the buffer is declared inside the main function, when this function ends since the buffer is local to the main function and in the stack it gets freed. This causes the atexit's stream flushing and closing to not comply with the setbuf function requirement of having a valid buffer.
Hope this helps http://en.cppreference.com/w/c/language/main_function
回答4:
Point is, main() is actually neither the first, nor the last code executed for your program. There is some "startup" code which calls main() after doing some processing and cleans up after main() returns.
One step of this cleanup is actually flushing buffers and closing files which have not been closed by the appication (these include stdin etc.). So, if you leave main(), the buffer is not yours anymore, but the cleanup might still want to access it. Just think of having the buffer given to someone else, who put something else inside. Anything can happen then, as you have no idea what he's done with memory.
Simply put: The term used in the C standard for "anything can happen" is "undefined behaviour". And take both phrases literally. @R. pointed that out quite well. Think of a car where the brakes don't work, but you get no notification and drive 200km/h (yes - Autobahn;-) downhill.
来源:https://stackoverflow.com/questions/30541589/a-valid-program-being-declared-as-invalid-by-man7-org