Date: Sun, 1 Mar 1998 18:53:30 -0800 (PST) From: dwimsey@rtci.com To: freebsd-gnats-submit@FreeBSD.ORG Subject: kern/5895: Kernal dumps caused by fork? Message-ID: <199803020253.SAA22224@hub.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 5895 >Category: kern >Synopsis: Kernal dumps caused by fork? >Confidential: no >Severity: critical >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sun Mar 1 19:00:01 PST 1998 >Last-Modified: >Originator: David Wimsey >Organization: >Release: 2.2.5-STABLE >Environment: FreeBSD oldwarez.com 2.2.5-STABLE FreeBSD 2.2.5-STABLE #0: Sun Mar 1 21:23:52 EST 1998 root@oldwarez.com:/usr/src/sys/compile/ChaosKern i386 >Description: This description is not confirmed... it it simple the best I can figure from what I have to go by. When a process forks, and the spawn dies unexpectedly, it doesn't properly remove the entry from the process list, and then the kernel attempts to run the process. Which causes a page fault. There was no pattern to this until recently when I begain working on a tcp echo server. The server simply forks off a new process for each incoming connection, and goes on about its business. However, if I open a connection to the echo server, and close it abruptly (i.e. telnet 0 5000, <esc char> quit) after a few of these... the machine is well on its way to rebooting. >How-To-Repeat: Below is the source to the program that seems to have a good chance of causing it... it will reboot no matter what by the tenth closed connection on this program. Which I run as a normal user, nothing special about it. > cat sock.c #include <errno.h> /* obligatory includes */ #include <signal.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> #include <netdb.h> #define MAXHOSTNAME 256 /* code to establish a socket; originally from bzs@bu-cs.bu.edu */ int establish(unsigned short portnum) { char myname[MAXHOSTNAME+1]; int s; struct sockaddr_in sa; struct hostent *hp; memset(&sa, 0, sizeof(struct sockaddr_in)); /* clear our address */ gethostname(myname, MAXHOSTNAME); /* who are we? */ hp= gethostbyname(myname); /* get our address info */ if (hp == NULL) /* we don't exist !? */ return(-1); sa.sin_family= hp->h_addrtype; /* this is our host address */ sa.sin_port= htons(portnum); /* this is our port number */ if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0) /* create socket */ return(-1); if (bind(s,&sa,sizeof(struct sockaddr_in)) < 0) { close(s); return(-1); /* bind address to socket */ } listen(s, 3); /* max # of queued connects */ return(s); } /* wait for a connection to occur on a socket created with establish() */ int get_connection(int s) { int t; /* socket of connection */ if ((t = accept(s,NULL,NULL)) < 0) /* accept connection if there is one */ return(-1); return(t); } #define PORTNUM 5000 /* random port number, we need something */ void fireman(void); void do_something(int); main() { int s, t; if ((s= establish(PORTNUM)) < 0) { /* plug in the phone */ perror("establish"); exit(1); } signal(SIGCHLD, fireman); /* this eliminates zombies */ for (;;) { /* loop for phone calls */ if ((t= get_connection(s)) < 0) { /* get a connection */ if (errno == EINTR) /* EINTR might happen on accept(), */ continue; /* try again */ perror("accept"); /* bad */ exit(1); } switch(fork()) { /* try to handle connection */ case -1 : /* bad news. scream and die */ perror("fork"); close(s); close(t); exit(1); case 0 : /* we're the child, do something */ close(s); do_something(t); exit(0); default : /* we're the parent so look for */ close(t); /* another connection */ continue; } } } /* as children die we should get catch their returns or else we get * zombies, A Bad Thing. fireman() catches falling children. */ void fireman(void) { while (waitpid(-1, NULL, WNOHANG) > 0) ; printf( "Socket lost!" ); } /* this is the function that plays with the socket. it will be called * after getting a connection. */ //quicktag void do_something(int s) { char buf[257]; char buf2[257]; int webint, count=0; printf( "Socket %d connected!\r\n", s ); send( s, "Sup fucko\r\n\0\0", 12, MSG_PEEK ); while(1) { memcpy( buf, "\0\0\0\0\0\0\0\0\0\0\0", 10); read(s, &buf, 1); send( s, buf, strlen(buf), 0 ); printf( buf ); if( strcmp( buf, "W" ) ) { webint = call_socket( "noc.rtci.com", 80 ); send( webint, "GET /index.html HTTP1.0\n\n", 25, 0 ); while( count < 100 ) { count++; read( webint, buf2, 64 ); send( s, buf2, strlen( buf2 ), 0 ); } close( webint ); } } } int call_socket(char *hostname, unsigned short portnum) { struct sockaddr_in sa; struct hostent *hp; int a, s; if ((hp= gethostbyname(hostname)) == NULL) { /* do we know the host's */ errno= ECONNREFUSED; /* address? */ return(-1); /* no */ } memset(&sa,0,sizeof(sa)); memcpy((char *)&sa.sin_addr,hp->h_addr,hp->h_length); /* set address */ sa.sin_family= hp->h_addrtype; sa.sin_port= htons((u_short)portnum); if ((s= socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) /* get socket */ return(-1); if (connect(s,&sa,sizeof sa) < 0) { /* connect */ close(s); return(-1); } return(s); } int read_data(int s, /* connected socket */ char *buf, /* pointer to the buffer */ int n /* number of characters (bytes) we want */ ) { int bcount; /* counts bytes read */ int br; /* bytes read this pass */ bcount= 0; br= 0; while (bcount < n) { /* loop until full buffer */ if ((br= read(s,buf,n-bcount)) > 0) { bcount += br; /* increment byte counter */ buf += br; /* move buffer ptr for next read */ } else if (br < 0) /* signal an error to the caller */ return(-1); } return(bcount); } /* i= htonl(i); write_data(s, &i, sizeof(i)); and after reading data you should convert it back with ntohl(): read_data(s, &i, sizeof(i)); i= ntohl(i); */ >Fix: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199803020253.SAA22224>