libc_r: threaded application could stuck in accept(2)

Ruslan Ermilov ru at FreeBSD.org
Fri May 30 12:30:37 PDT 2003


On Fri, May 30, 2003 at 08:16:41PM +0300, Ruslan Ermilov wrote:
> On Fri, May 30, 2003 at 07:07:23PM +0300, Enache Adrian wrote:
> > On Fri, May 30, 2003 at 05:35:41PM +0300, Ruslan Ermilov wrote:
> > > We had a bug in our threaded application that would mistakenly close
> > > the descriptor 0, and this triggers a bug in libc_r which I will try
> > > to describe below.
> > ...
> > > Some important notes: this bug is only applicable to descriptors
> > > 0 - 2 (stdio set), and might have something to do with the code
> > > in uthread_fd.c.  If you remove two lines that free the descriptor
> > > 0 in the attached test case, the bug won't manifest itself.
> > 
> > please have a look at
> > 
> > http://www.freebsd.org/cgi/query-pr.cgi?pr=51535
> > 
> Thanks, I had this same patch in my first version of the fix.
> Yes it works too, but do you have an insight what's going on
> without these fixes so that the 0..2 descriptors are left in
> a blocking mode?  I just can't get it where this happens.
> 
OK, I now know what's going on here.  Without patches, a
second close(0) calls _FDLOCK(0, ...) which calls
_thread_fd_table_init(0).  In this functions, the
following condition becomes false

                /* Get the flags for the file: */
                if (((fd >= 3) || (_pthread_stdio_flags[fd] == -1)) &&
                    (entry->flags = __sys_fcntl(fd, F_GETFL, 0)) == -1) {
                        ret = -1;
                }

due to _pthread_stdio_flags[0] != -1, and we succeed
to the "else" block which eventually installs the "entry"
as _thread_fd_table[0].

Then, the call to socket() calls _thread_fd_table_init(0)
again, but since it detects that the memory is already
allocated (for non-existing descriptor 0), it doesn't
try to set it to non-blocking mode.

With my patch, we just don't allow the second call to
_thread_fd_table_init(0) when descriptor 0 doesn't exist.

With your patch that resets _pthread_stdio_flags[0] to -1
on close, attempting to close(0) for the second time
evaluates the condition above to true, and then
__sys_fcntl(0, F_GETFL, 0) returns -1 (EBADF), and
then the "entry" is free()'ed.  Then, on the next socket()
call, _thread_fd_table_init(0) allocates the memory
for fd 0, and sets it to non-blocking mode.

> P.S.  I will commit both patches after the freeze is over.
> 
Your patch also fixes the bug you mentioned, so I will
commit both patches.


Cheers,
-- 
Ruslan Ermilov		Sysadmin and DBA,
ru at sunbay.com		Sunbay Software AG,
ru at FreeBSD.org		FreeBSD committer.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 187 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-hackers/attachments/20030530/58b1a9c5/attachment.bin


More information about the freebsd-hackers mailing list