This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: How to use control-D character?


Hi Maciej,

1. input_file_open() uses ungetc(3) without checking for EOF.

2. glibc does not handle the EOF condition in the context of ungetc(3)
    correctly when input is connected to the terminal.

  The issue #1 above is obvious and only applies to EOF seen right at the
beginning.  I'll elaborate on #2.  We make this sequence of calls on
input:

getc()
ungetc()
fread()
fread()
fread()
...

The call to getc(3) collects a line of input with read(2) (that is
retained) and returns the first character.  The call to ungetc(3) pushes
the character back to the head of the line.  The call to fread(3) collects
another line of input (that is retained) with read(2) and returns the line
previously collected by getc(3).  The next call to fread(3) collects
another line of input (that is retained) with read(2) and returns the line
collected by the previous call to fread(3), etc., etc...

  Now if at any point read(2) returns EOF, then glibc records the fact (see
libio/fileops.c and look for "fp->_flags |= _IO_EOF_SEEN" assignments,
such as in _IO_file_xsgetn() that is used by fread(3)), but obviously it
still has to return the line buffered by the previous call to fread(3).
The EOF condition is expected to be triggered by the next call to fread(3)
(or, to be exact, once all the buffered characters have been consumed, up
to which point fread(3) should refrain from making further calls to
read(2)), but that doesn't happen unless the associated read(2) call
returns another EOF, because glibc actually never checks whether the
_IO_EOF_SEEN flag is set.

  The ISO C99 standard seems a bit imprecise about the interaction between
ungetc(3) and fread(3), which matters especially in the context of
line-mode devices such as terminals.  The above is my interpretation of
how these calls should behave only, that is guaranteed the glibc
maintainers will disagree with, as usual.

Imagining that I am Uli for a second, it occurs to me that he will defend glibc by saying that we ought to be calling feof() to check for the end of file condition before calling fread().


So what do you think of this patch, which appears to take care of both points (1) and (2), although it does not attempt to tidy up the #NO_APP processing ?

Cheers
  Nick
Index: gas/input-file.c
===================================================================
RCS file: /cvs/src/src/gas/input-file.c,v
retrieving revision 1.27
diff -u -3 -p -r1.27 input-file.c
--- gas/input-file.c	2 Sep 2009 07:24:19 -0000	1.27
+++ gas/input-file.c	27 Oct 2010 14:02:11 -0000
@@ -157,6 +157,15 @@ input_file_open (char *filename, /* "" m
       return;
     }
 
+  /* Check for an empty input file.  */
+  if (feof (f_in))
+    {
+      fclose (f_in);
+      f_in = NULL;
+      return;
+    }
+  gas_assert (c != EOF);
+
   if (c == '#')
     {
       /* Begins with comment, may not want to preprocess.  */
@@ -209,6 +218,9 @@ input_file_get (char *buf, int buflen)
 {
   int size;
 
+  if (feof (f_in))
+    return 0;
+  
   size = fread (buf, sizeof (char), buflen, f_in);
   if (size < 0)
     {
@@ -235,7 +247,13 @@ input_file_give_next_buffer (char *where
   if (preprocess)
     size = do_scrub_chars (input_file_get, where, BUFFER_SIZE);
   else
-    size = fread (where, sizeof (char), BUFFER_SIZE, f_in);
+    {
+      if (feof (f_in))
+	size = 0;
+      else
+	size = fread (where, sizeof (char), BUFFER_SIZE, f_in);
+    }
+
   if (size < 0)
     {
       as_bad (_("can't read from %s: %s"), file_name, xstrerror (errno));

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]