Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 11 Jul 2003 22:52:48 -0700
From:      Joshua Oreman <oremanj@webserver.get-linux.org>
To:        freebsd-hackers@freebsd.org
Subject:   getpwnam + getpwnam_r + LinuxThreads port = deadlock
Message-ID:  <20030712055248.GA23189@webserver.get-linux.org>

next in thread | raw e-mail | index | archive | help
Hi -hackers,

System: FreeBSD 5.0-CURRENT cvsupped around 5.0-RELEASE

I'm writing an app that links with the LinuxThreads
(/usr/ports/devel/linuxthreads) and also uses getpwnam(). The problem:
a deadlock. GDB backtrace:

(gdb) bt
#0  0x28140053 in sigsuspend () from /usr/lib/libc.so.5
#1  0x28090428 in __pthread_wait_for_restart_signal () from /usr/local/lib/liblthread.so.3
#2  0x28090548 in __pthread_suspend_old () from /usr/local/lib/liblthread.so.3
#3  0x2808d5fc in __pthread_alt_lock () from /usr/local/lib/liblthread.so.3
#4  0x28090df0 in pthread_mutex_lock () from /usr/local/lib/liblthread.so.3
#5  0x2808595b in getpwnam_r () from /usr/local/lib/liblthread.so.3
#6  0x2815405b in getpwuid_r () from /usr/lib/libc.so.5
#7  0x28153fab in getpwuid_r () from /usr/lib/libc.so.5
#8  0x28154129 in getpwnam () from /usr/lib/libc.so.5
#9  0x28085966 in getpwnam_r () from /usr/local/lib/liblthread.so.3
#10 0x2815405b in getpwuid_r () from /usr/lib/libc.so.5
#11 0x28153fab in getpwuid_r () from /usr/lib/libc.so.5
#12 0x28154129 in getpwnam () from /usr/lib/libc.so.5
#13 0x080495ca in check_pwinfo (username=0x155 <Error reading address 0x155: Bad address>,
    passwd=0x155 <Error reading address 0x155: Bad address>, group=0xbfbfeed8)
#14 0x0804a212 in handle_connection (tb=0xbfbff988)
#15 0x0804a52b in main (argc=4, argv=0xbfbff9f8)
#16 0x080494f5 in _start ()
(gdb) f 13
#13 0x080495ca in check_pwinfo (username=0x155 <Error reading address 0x155: Bad address>,
    passwd=0x155 <Error reading address 0x155: Bad address>, group=0xbfbfeed8)
43          pw = getpwnam (username);

Basically: FreeBSD implements getpwnam() as a wrapper around
getpwnam_r(), as seen in src/lib/libc/gen/getpwent.c:

struct passwd *
getpwnam(const char *name)
{
        union key key;

        key.name = name;
        return (getpw(wrap_getpwnam_r, key));
}

While LinuxThreads does the opposite, basically using getpwnam() +
mutex to make getpwnam_r, as seen in
ports/devel/linuxthreads/work/linuxthreads-2.2.3_11/getpw_r.c:

int getpwnam_r (const char *name, struct passwd *result,
                char *buffer, size_t buflen,
                struct passwd ** resptr)
{
  struct passwd * p;
  int retval;

  pthread_mutex_lock (&getpw_mutex);
  p = getpwnam (name);
  if (p == NULL) {
    *resptr = NULL;
    retval = ESRCH;
  } else
  if (convert (p, result, buffer, buflen) != 0) {
    *resptr = NULL;
    retval = ERANGE;
  } else {
    *resptr = result;
    retval = 0;
  }
  pthread_mutex_unlock (&getpw_mutex);
  return retval;
}

So basically, my app calls getpwnam(), which calls the overridden
getpwnam_r() from LinuxThreads, which calls getpwnam() from libc
again, and then calls getpwnam_r() from LinuxThreads again, and
deadlocks trying to recursively lock its own mutex.  Obviously, if
there was no mutex the stack would leak out the back of my computer
:-)

Any ideas here?

-- Josh



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030712055248.GA23189>