Bug 12792 - perror violates POSIX regarding ferror status
Summary: perror violates POSIX regarding ferror status
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.13
: P2 normal
Target Milestone: ---
Assignee: Ulrich Drepper
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-05-20 16:40 UTC by Eric Blake
Modified: 2014-06-27 13:18 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Eric Blake 2011-05-20 16:40:42 UTC
http://austingroupbugs.net/view.php?id=389 is an approved POSIX interpretation which states that perror() must set the stream error bit on write failure; and that if ferror() states that an error occurred, then errno after perror() must reflect the proper failure.  However, glibc violates this:

$ cat foo.c
#define _POSIX_C_SOURCE 200112L
#include <errno.h>
#include <stdio.h>

int main(int argc, char **argv)
{
  if (errno || ferror (stderr))
    return 1;
  if (argc == 1)
    {
      puts ("using fputs");
      fputs ("string\n", stderr);
    }
  else
    {
      if (argc > 2)
	{
	  printf ("using perror on %s with mode %s\n", argv[1], argv[2]);
	  if (freopen (argv[1], argv[2], stderr) != stderr)
	    return 2;
	}
      else
	{
	  puts ("using perror on inherited stderr");
	}
      perror (NULL);
    }
  printf (errno ? "errno says write failed %d\n"
	  : "errno says write succeeded\n", errno);
  puts (ferror (stderr) ? "ferror says write failed"
	: "ferror says write succeeded");

  return 0;
}
$ touch file
$ ./foo blah 2<file
using perror on inherited stderr
errno says write failed 9
ferror says write failed
$ ./foo file r
using perror on file with mode r
errno says write failed 9
ferror says write succeeded           <=== Oops - write fails to read-only file
$ ./foo /dev/full 2>/dev/full
using perror on inherited stderr
errno says write failed 28
ferror says write failed
$ ./foo /dev/full w 2>/dev/full
using perror on /dev/full with mode w
errno says write failed 25            <=== Oops - where did ENOTTY come from?
ferror says write succeeded           <=== Oops - write failed with ENOSPC
$

Meanwhile, quality of implementation argues that perror should leave errno unchanged if the subsequent ferror() reports success:

$ ./foo file
using perror on inherited stderr
Success
errno says write succeeded
ferror says write succeeded
$ ./foo file 
using perror on file with mode 
errno says write failed 22            <=== Oops, errno corrupted on success
ferror says write succeeded
$ cat file
Success
Success
$
Comment 1 Ulrich Drepper 2011-05-21 04:44:07 UTC
I fixed some problems.

But the last test in you program is wrong.  /dev/full is no TTY and therefore the stream is fully buffered and any error will only be guaranteed to show up after an fflush.