bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

undefined behavior in closeout, aggravated by libsigsegv


From: Eric Blake
Subject: undefined behavior in closeout, aggravated by libsigsegv
Date: Fri, 17 Jul 2009 20:47:17 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

I'm seeing the following in cygwin with m4 1.4.12, due to an interaction 
between the closeout module and libsigsegv:

$ echo hi > file
$ build/src/m4 >&- file
build/src/m4: internal error detected; please report this bug to <bug-
address@hidden>: Segmentation fault

I've traced it to the fact that m4 uses the closeout module, which does the 
following:

calls close_string (stdout)
=> fclose (stdout)
detects that pending data was lost, so call error()
=> fflush (stdout)

According to POSIX, using stdout after it has been passed to fclose is 
undefined behavior.  Normally, cygwin is able to do just fine when flushing an 
already closed fd (basically, there is a fault under the hood, but the fault is 
trapped and silently ignored).  But when libsigsegv is thrown in the mix, the 
fault is now caught by libsigsegv instead of cygwin, in a manner visible to the 
application.

$ cat foo.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#ifdef libsigsegv
#include <sigsegv.h>
int
handler (void *addr, int bad)
{
  abort ();
}
#endif

void
die ()
{
  int i;
  i = fclose (stdout);
  fprintf (stderr, "fclose %d, errno %d\n", i, errno);
  errno = 0;
  i = fflush (stdout);
  fprintf (stderr, "fflush %d, errno %d\n", i, errno);
}

int main ()
{
  close (1);
  atexit (die);
#ifdef libsigsegv
  sigsegv_install_handler (handler);
#endif
  fputc ('1', stdout);
  return 0;
}
$ gdb -o foo foo.c -lsigsegv
$ ./foo
fclose -1, errno 9
fflush 0, errno 0
$ gdb -o foo foo.c -Dlibsigsegv -lsigsegv
$ ./foo
fclose -1, errno 9
Aborted (core dumped)
$


I'm not sure if there is a bug in libsigsegv, such that the under-the-hood 
fault is now exposed to the application.  At any rate, there is currently a 
thread on the cygwin list about a crash under Windows 2008 R2 64-bit, where 
Windows has tightened the rules on what forms a valid SEH exception chain and 
the cygwin handler was violating those rules; and that thread has also raised 
the concern that libsigsegv may be making the same mistakes by trying to 
override cygwin's handler:

http://cygwin.com/ml/cygwin/2009-07/msg00630.html
http://cygwin.com/ml/cygwin/2009-07/msg00635.html

Contrast this to a run on Solaris without libsigsegv, where the fflush at least 
sets errno to EBADF on an attempt to manipulate a closed stream (but has the 
wrong return status):
% ./foo
fclose -1, errno 9
fflush 0, errno 9

If nothing else, cygwin should probably be taught to recognize a previously 
closed file up front, rather than depending on catching an internal fault, and 
set errno to EBADF instead of claiming success.


But even if cygwin is improved to not trigger an internal fault, and/or 
libsigsegv changed to not interfere with cygwin's detection of internal faults, 
it seems that the real root cause is that gnulib has caused the application to 
perform undefined behavior during the atexit() handler, and that we should fix 
this before it trips up other platforms.  What's the best way to do that?  Have 
close_stdout call freopen("/dev/null","w",stdout) prior to calling error()?  
Convince the glibc folks to change error() to not call fflush(stdout) if fileno
(stdout) is closed?  Rewrite close_stdout to open-code the error-printing 
actions instead of calling error()?  Something else?

-- 
Eric Blake






reply via email to

[Prev in Thread] Current Thread [Next in Thread]