Bug 14685

Summary: setjmp/longjmp in threaded app cause subsequent read to run forever
Product: Base System Reporter: xfb52 <xfb52>
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   

Description xfb52 1999-11-03 15:50:00 UTC
If a program linked against libc_r is looping on a read, the read is
interrupted, and the signal handler uses a longjmp to jump back
to just before the read, the read call will go into an infinite loop.

As far as I have trace it, everything goes wrong somewhere in 
_thread_kern_poll

This is a big problem (for me) as this is exactly how python interacts
libreadline.

How-To-Repeat: Compile the following program
e.g. gcc -pthread -o readtest readtest.c

Type a few keys to see that it is working OK, and then press ^C.

I used ktrace/kdump -l to watch what happened when keys were pressed
and when ^C was pressed.  After a keypress the process ends up doing a
gettimeofday() and then a poll() but after a ^C it does the
gettimeofday() but never reaches a poll.  top shows it in a RUN state
chewing up mucho CPU.

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <termios.h>
#include <signal.h>
#include <setjmp.h>

extern int errno;
static jmp_buf jbuf;

void
onintr()
{
  printf("\nCAUGHT INT\n");
  longjmp(jbuf, 1);
}

int
main (argc, argv)
     int argc;
     char **argv;
{
  unsigned char c;
  int result;
  int flags;
  struct termios tio;
  struct sigaction act;

  act.sa_handler = onintr;
  act.sa_mask = SIGINT;
  act.sa_flags = 0;

  sigaction(SIGINT, &act, NULL);


  
  tcgetattr(fileno(stdin), &tio);
  tio.c_lflag &= ~(ICANON);

  tcsetattr(fileno(stdin), TCSANOW, &tio);
  

  while (1) {
    if (setjmp(jbuf)) {
      printf("\nIN SETJMP\n");
    }


    result = read(fileno(stdin), &c, sizeof(unsigned char));
    
    if (result == 0 || c == 4) {
      printf ("\nEOF\n");
      exit (0);
    }

    if (result == sizeof(unsigned char)) {
      printf ("\nREAD: %c\n", c);
      continue;
    }

    printf ("\nERROR: %s\n", strerror(errno));
  }
}
Comment 1 Jason Evans freebsd_committer freebsd_triage 2000-01-19 07:30:05 UTC
State Changed
From-To: open->closed

Fixed in -current.