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