Hi, Scott Cheloha wrote on Fri, Jul 28, 2017 at 08:33:16PM -0500:
> Unlikely to happen during normal use, but setvbuf(3) can fail > to allocate your buffer: > > /* prog.c */ > #include <stdio.h> > > int > main(int argc, char *argv[]) > { > if (setvbuf(stdout, NULL, _IOFBF, 0)) > perror("setvbuf"); > return 0; > } > > This seems to force the allocation failure on my box: > > $ ksh -c "ulimit -d 230 ; ./prog" > > Not sure what the correct wording is for the ERRORS section. > > Is it appropriate to specify that you can only get an allocation > failure under the particular circumstances described? Or is it > better to just write the standard line?, i.e. > > "Insufficient storage space is available." > > As a reader I would want to know more precisely how the > interface can fail. Still seems kind of messy. Maybe my > wording could be improved. Your patch is obviosly wrong. If at all, the required wording would be something like The setvbuf() function may also fail and set errno for any of the errors specified for the routine malloc(3). But that isn't fair game either. Lets take a step back and look at the big picture, in four steps: 1. The setvbuf(3) function is standardized by POSIX. POSIX fails to say that setvbuf() sets ENOMEM on allocation failure, which means that doing so is implementation dependent, see paragraph 1.2 of http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap01.html and paragraph 2.3 of http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html In a nutshell, this means that POSIX provisions for error numbers are mostly advisory because implementations are allowed to differ in either direction, yet some POSIX provisions *are* mandatory. Figuring out what exactly is mandatory in each particular case is tricky. My impression is that not much care was taken when setting up the POSIX specifications for error numbers. They are often obviously incomplete and sometimes unclear. 2. The said, strictly speaking, if including the sentence shown above into ERRORS, we should also include this sentence below STANDARDS: The setvbuf() function conforms to ISO/IEC 9899:1999 ("ISO C99") and IEEE Std 1003.1-2008 ("POSIX.1"). Setting errno for malloc(3) failure is an extension to the POSIX standard. Strictly speaking, both standards must be mentioned, because not all the behaviour described in the manual is mandated by C99. For example, setting errno *at all* is already an extension to the C standard, yet it is mandated by POSIX. That said, almost none of our manual pages cite two standards in this way, and practically none properly document which error numbers are extensions. Given the sloppiness of POSIX with respect to error numbers, that hardly comes as a surprise. 3. That said, fiddling with these details is petty, there are much worse problems. For example, the existing ERRORS section in setvbuf(3) is nothing but one big lie. If the stream is not associated with a valid file descriptor, setvbuf() will *NOT* fail: schwarze@isnote $ cat setvbuf.c #include <err.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> int main(void) { char buf[16]; FILE *fp; int fd; if ((fd = open("testfile.txt", O_RDONLY)) == -1) err(1, "open"); if ((fp = fdopen(fd, "r")) == NULL) err(1, "fdopen"); if (close(fd) == -1) err(1, "close"); if (setvbuf(fp, buf, _IOFBF, 1024) != 0) err(1, "setvbuf"); if (fgets(buf, sizeof(buf), fp) == NULL) err(1, "fgets"); return 0; } schwarze@isnote $ make setvbuf cc -O2 -pipe -o setvbuf setvbuf.c schwarze@isnote $ ./setvbuf setvbuf: fgets: Bad file descriptor Note how setvbuf() suceeds and only fgets() fails. This is *not* a POSIX violation. POSIX only says: The setvbuf() function may fail if: [EBADF] The file descriptor underlying stream is not valid. Yet, this is an outright documentation bug in our manual page. 4. That said, fiddling with even that detail is petty, there are still worse problems. Consider this program: schwarze@isnote $ cat setvbuf_invalid.c #include <err.h> #include <stdio.h> int main(void) { FILE *fp; if ((fp = fopen("testfile.txt", "r")) == NULL) err(1, "fopen"); if (setvbuf(fp, NULL, _IOFBF, -1) != 0) err(1, "setvbuf"); return 0; } schwarze@isnote $ make setvbuf_invalid cc -O2 -pipe -o setvbuf_invalid setvbuf_invalid.c schwarze@isnote $ ./setvbuf_invalid setvbuf_invalid: setvbuf: Undefined error: 0 A negative buffer size is invalid and causes setvbuf() to fail, but fails to set errno. Again, that's not a POSIX violation, POSIX allows additional implementation-dependent failure scenarios, and POSIX does not require setting errno. But arguably, failure to set errno is a bug in our implementation, because setting errno would clearly be useful, and our manual even suggests that it might happen. In any case, our manual is imprecise, neither making it clear what a programmer trying to write POSIX-conforming, portable code should expect, nor making it clear what our implementation actually does. To summarize, the code is buggy (and almost certainly not only in the one aspect i demonstrated), our manual is a mess, POSIX is a mess, too, and you are applying lipstick to a pig. All this (maybe except POSIX) can be fixed, but that's a huge project because error handling is very, very messy all across the C library similar to what i described for this example. Patches of this kind are not helpful, in particular since you are clearly not (yet) understanding what you are doing. Checking such patches causes substantial work for developers and may result in erractic and inconsistent improvements at best. If someone has a year of working time to spare to tackle error handling in libc, it should be done systematically, not in such a piecemeal manner, and it needs to be done carefully. Yours, Ingo > Index: lib/libc/stdio/setvbuf.3 > =================================================================== > RCS file: /cvs/src/lib/libc/stdio/setvbuf.3,v > retrieving revision 1.4 > diff -u -p -r1.4 setvbuf.3 > --- lib/libc/stdio/setvbuf.3 26 Nov 2014 18:16:32 -0000 1.4 > +++ lib/libc/stdio/setvbuf.3 29 Jul 2017 01:27:55 -0000 > @@ -138,6 +138,10 @@ function will fail if: > The > .Fa stream > specified is not associated with a valid file descriptor. > +.It Bq Er ENOMEM > +Line or block buffering is requested, > +.Fa buf > +is NULL, and insufficient storage space is available. > .El > .Sh SEE ALSO > .Xr fclose 3 ,