[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Bug#596499: reloading /etc/resolv.conf does not work in multi-threaded applications



retitle 596499 libc6: reloading /etc/resolv.conf does not work in multi-threaded applications
reassign 596499 libc6 2.11.2-5
thanks

On Mon, 2010-09-13 at 23:23 +0200, Arthur de Jong wrote:
> From what I gathered with strace it seems that some tests are in place
> to reload /etc/resolv.conf if the file has changed (at leasts a stat()
> is done). The first time the file is loaded twice and also twice if
> the file was modified but I don't think it is reloaded by the thread
> that originally failed if it was reloaded again by another thread. My
> guess is that the cached contents of /etc/resolv.conf is thread local
> but the timestamp that is used for the stat() is global.
> 
> Anyway, I will try to make a test application to reproduce this and
> file a bugreport in glibc if the above is confirmed.

I have confirmed that this is indeed a bug in libc and not in nslcd. The
attached test reproduces the problem.

The test first makes /etc/resolv.conf invalid, starts two threads that
read and cache the incorrect resolv.conf. Then restores resolv.conf and
does two more requests with the original threads. Only the first thread
reloads resolv.conf. The test should be run as root because it moves and
modifies /etc/resolv.conf.


The output of the test on my system is:

saving /etc/resolv.conf to /etc/resolv.conf.saved...
clobbering /etc/resolv.conf...
starting threads...
  thread: starting
  thread: starting
doing a lookup with thread1 (this should error)...
  thread: do lookup
  thread: gethostbyname() returned NULL: No such file or directory
doing a lookup with thread2 (this should error)...
  thread: do lookup
  thread: gethostbyname() returned NULL: No such file or directory
restoring /etc/resolv.conf...
doing a lookup with thread1 (this should reload resolv.conf and be ok)...
  thread: do lookup
  thread: gethostbyname() returned www.debian.org
doing a lookup with thread2 (this doesn't reload resolv.conf and still errors)...
  thread: do lookup
  thread: gethostbyname() returned NULL: No such file or directory
we're done

/etc/nsswitch.conf only has "hosts: files dns" and /etc/host.conf is
unaltered. I did not have nscd running.


If you need any more info, feel free to ask. Thanks.


-- System Information:
Debian Release: squeeze/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: i386 (i686)

Kernel: Linux 2.6.34-1-686
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)
Shell: /bin/sh linked to /bin/dash

Versions of packages libc6 depends on:
ii  libc-bin                      2.11.2-5   Embedded GNU C Library: Binaries
ii  libgcc1                       1:4.4.4-14 GCC support library

Versions of packages libc6 recommends:
ii  libc6-i686                    2.11.2-5   Embedded GNU C Library: Shared lib

Versions of packages libc6 suggests:
ii  debconf [debconf-2.0]         1.5.35     Debian configuration management sy
pn  glibc-doc                     <none>     (no description available)
pn  locales                       <none>     (no description available)

-- 
-- arthur - adejong@debian.org - http://people.debian.org/~adejong --
/* compile with gcc -o libctest libctest.c -pthread */

#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>

/* global mutex */
pthread_mutex_t global_mutex=PTHREAD_MUTEX_INITIALIZER;

/* worker thread that just does simple hostname lookups */
static void *helper(void *arg)
{
  pthread_cond_t *cond=(pthread_cond_t *)arg;
  struct hostent *host;
  fprintf(stderr,"  thread: starting\n");
  pthread_mutex_lock(&global_mutex);
  while (1)
  {
    /* block until signalled */
    pthread_cond_wait(cond,&global_mutex);
    /* do a lookup */
    fprintf(stderr,"  thread: do lookup\n");
    host=gethostbyname("www.debian.org");
    if (host==NULL)
      fprintf(stderr,"  thread: gethostbyname() returned NULL: %s\n",strerror(errno));
    else
      fprintf(stderr,"  thread: gethostbyname() returned %s\n",host->h_name);
  }
}

int main(int argc,char *argv[])
{
  pthread_t thread1, thread2;
  pthread_cond_t cond1=PTHREAD_COND_INITIALIZER;
  pthread_cond_t cond2=PTHREAD_COND_INITIALIZER;
  FILE *fp;
  /* save /etc/resolv.conf */
  fprintf(stderr,"saving /etc/resolv.conf to /etc/resolv.conf.saved...\n");
  unlink("/etc/resolv.conf.saved");
  rename("/etc/resolv.conf","/etc/resolv.conf.saved");
  /* clobber /etc/resolv.conf */
  fprintf(stderr,"clobbering /etc/resolv.conf...\n");
  fp=fopen("/etc/resolv.conf","w");
  fprintf(fp,"start\n");
  fclose(fp);
  /* start threads and aquire global lock */
  fprintf(stderr,"starting threads...\n");
  pthread_create(&thread1,NULL,helper,&cond1);
  pthread_create(&thread2,NULL,helper,&cond2);
  sleep(1);
  pthread_mutex_lock(&global_mutex);
  /* perform a lookup with thread1 (this should error) */
  fprintf(stderr,"doing a lookup with thread1 (this should error)...\n");
  pthread_cond_signal(&cond1);
  pthread_mutex_unlock(&global_mutex);
  sleep(1);
  pthread_mutex_lock(&global_mutex);
  /* perform a lookup with thread2 (this should error) */
  fprintf(stderr,"doing a lookup with thread2 (this should error)...\n");
  pthread_cond_signal(&cond2);
  pthread_mutex_unlock(&global_mutex);
  sleep(1);
  pthread_mutex_lock(&global_mutex);
  /* restore /etc/resolv.conf */
  fprintf(stderr,"restoring /etc/resolv.conf...\n");
  unlink("/etc/resolv.conf");
  rename("/etc/resolv.conf.saved","/etc/resolv.conf");
  sleep(1);
  /* perform a lookup with thread1 (this should reload resolv.conf and be ok) */
  fprintf(stderr,"doing a lookup with thread1 (this should reload resolv.conf and be ok)...\n");
  pthread_cond_signal(&cond1);
  pthread_mutex_unlock(&global_mutex);
  sleep(1);
  pthread_mutex_lock(&global_mutex);
  /* perform a lookup with thread2 (this doesn't reload resolv.conf and still errors) */
  fprintf(stderr,"doing a lookup with thread2 (this doesn't reload resolv.conf and still errors)...\n");
  pthread_cond_signal(&cond2);
  pthread_mutex_unlock(&global_mutex);
  sleep(1);
  pthread_mutex_lock(&global_mutex);
  /* we're done */
  fprintf(stderr,"we're done\n");
  return 0;
}

Attachment: signature.asc
Description: This is a digitally signed message part


Reply to: