Eric Blake wrote on 2011-02-10: > POSIX requires that this program have an identical first and last line: > > #include <stdio.h> > #include <string.h> > #include <errno.h> > int main (void) { > char *err = strerror(1000); > printf ("%s\n", err); > errno = 2000; > perror ("hi"); > printf ("%s\n", err); > return 0; > } > > but on cygwin 1.7.7, the perror() corrupts the buffer returned by > strerror(). We should probably fix that in gnulib as part of our perror > module.
Yes, but first let's see which other problems there are. The program below tests whether strerror's buffer is read-write (i.e. whether it is overwritten by subsequent strerror calls) and, when compiled with -DPERROR, whether perror calls clobber the strerror buffer. The result is: read-write buffer? perror reuses strerror buffer? glibc yes no OpenBSD yes no OSF/1 yes no Cygwin 1.5 yes yes Cygwin 1.7 yes yes mingw yes no That's the situation without gnulib. With gnulib, there are three problems in toto: 1) The strerror_r replacement, when EXTEND_STRERROR_R is defined, clobbers the strerror function's buffer, which it shouldn't. 2) The perror replacement uses strerror, thus clobbering the strerror buffer. 3) On Cygwin, perror clobbers the strerror buffer. The fix for 1) should be to move most of lib/strerror.c to lib/strerror_r.c. The fix for 2) should be to change lib/perror.c to call strerror_r. The fix for 3) should be to change m4/perror.m4 to enable the replacement on Cygwin. I think the three fixes should be applied in this order, bottom-up. Bruno ==================================== foo.c ==================================== #include <errno.h> #include <stdio.h> #include <string.h> int main () { const char *msg1; const char *msg2; const char *msg3; msg1 = strerror (ENOENT); printf ("msg1 before: %s\n", msg1); msg2 = strerror (-4); printf ("msg2 before: %s\n", msg2); msg3 = strerror (1729576); printf ("msg3 before: %s\n", msg3); freopen ("/dev/null", "w", stderr); #ifdef PERROR errno = EACCES; perror (""); errno = -5; perror (""); errno = 153272; perror (""); #else strerror (EACCES); strerror (-5); strerror (153272); #endif printf ("msg1 after: %s\n", msg1); printf ("msg2 after: %s\n", msg2); printf ("msg3 after: %s\n", msg3); return 0; } ===============================================================================