Date: Sat, 12 Dec 1998 17:38:16 -0800 From: Don Lewis <Don.Lewis@tsc.tdk.com> To: Matthew Dillon <dillon@apollo.backplane.com>, Peter Edwards <peter.edwards@isocor.ie> Cc: Archie Cobbs <archie@whistle.com>, freebsd-current@FreeBSD.ORG Subject: Re: inetd: realloc/free bug Message-ID: <199812130138.RAA22963@salsa.gv.tsc.tdk.com> In-Reply-To: Matthew Dillon <dillon@apollo.backplane.com> "Re: inetd: realloc/free bug" (Dec 11, 4:31pm)
next in thread | previous in thread | raw e-mail | index | archive | help
On Dec 11, 4:31pm, Matthew Dillon wrote: } Subject: Re: inetd: realloc/free bug } I've commited my fix to inetd. As I said before, there } really isn't much to it. You simply allow signal operation } around the select() code and block signals at all other } times and you are done. No fancy pipes, no fancy global } flags, insignificantly delayed signal operation (and } nominally not delayed at all), inherent event serialization, } etc etc etc. It also has the downside of keeping inetd "active", so it can't be totally swapped out if it's not in use. This might be a bit of a concern to some folks, like those who run FreeBSD on their laptops. Your implementation is also more syscall intensive than some of the alternatives. Your patch also doesn't eliminate all the race conditions. When a signal handler is invoked, it blocks reception of the signal that triggered it, but not the reception of other signals, so it is possible for one of the signal handlers to be active when another one is invoked. This is fixable by blocking the other signals from within the handlers, at the expense of more syscalls. I hadn't thought of writing the signals to a pipe and in the past I've always used global flags. I think the pipe idea is kind of elegant because it avoids having to fiddle with the signal masks to avoid race conditions between testing and clearing the flags. Oh yeah, there is another race condition that I've never seen mentioned. In the case of TCP services where we do something like ctrl = accept(...); pid = fork(); if (pid == 0) { fiddle with fds exec(...); } close(ctrl); there is a problem if the child process runs, writes a bunch of data to the socket and exits before the parent process executes the close(). If this happens, the close() in the parent can hang for an indefinite period of time, until the client consumes the buffered data on the socket. I fixed this in BIND 4.x a few years ago using a pipe to synchronize the parent and child processes. This fix would roughly translate as the following (ignoring error checking): int pipefd[2]; char c; ctrl = accept(...); pipe(pipefd); pid = fork(); if (pid == 0) { close(pipefd[1]); /* close the write end */ /* wait for EOF */ while (read(pipefd[0], &c, 1) == -1 && errno == EINTR) ; /* nothing */ close(pipefd[0]); fiddle with fds exec(...); } close(pipefd[0]); /* close the read end */ close(ctrl); close(pipefd[1]); /* close the write end to release the child */ To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199812130138.RAA22963>