|
Message-ID: <20220625125110.GV1320090@port70.net> Date: Sat, 25 Jun 2022 14:51:10 +0200 From: Szabolcs Nagy <nsz@...t70.net> To: Nick Peng <pymumu@...il.com> Cc: musl@...ts.openwall.com Subject: Re: BUG: Calling readdir/dirfd after vfork will cause deadlock. * Nick Peng <pymumu@...il.com> [2022-06-25 11:40:17 +0800]: > Description: After vfork, calling functions such as readdir/dirfd may > cause deadlock. GNU C is OK. why do you think "GNU C is OK"? is this from some real software? opendir after vfork is documented to be invalid in glibc: https://www.gnu.org/software/libc/manual/html_mono/libc.html#Low_002dlevel-Directory-Access the standard is actually much stricter than the glibc manual: posix conforming code must not call any libc api after vfork other than _exit or the exec* familiy of functions. (as-safe is not enough, but opendir is not even as-safe) since the example is multi-threaded even using fork would be invalid, but i think both musl and glibc makes that work (as an extension to the standard). > Also tested on x86-64 with musl, no deadlock, but > seems never exit, slower than GNU C. > Version: latest, musl-1.2.3 > OS: debian bullseye 64bit OS. and asus router > CPU: raspberrypi aarch64, mips32 > Reproduce Code: > > #include <dirent.h> > #include <pthread.h> > #include <stdint.h> > #include <stdio.h> > #include <stdlib.h> > #include <sys/types.h> > #include <sys/wait.h> > #include <unistd.h> > #include <string.h> > > pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; > pthread_cond_t cond = PTHREAD_COND_INITIALIZER; > > struct tlog_log *logs = NULL; > int do_exit = 0; > > void *test(void *arg) > { > int i = 0; > > for (i = 0; i < 10000000; i++) { > char *b = malloc(4096); > memset(b, 0, 4096); > free(b); > } > do_exit = 1; > return NULL; > } > > void lockfunc() > { > char path_name[4096]; > DIR *dir = NULL; > struct dirent *ent; > > snprintf(path_name, sizeof(path_name), "/proc/self/fd/"); > dir = opendir(path_name); > if (dir == NULL) { > goto errout; > } > > while ((ent = readdir(dir)) != NULL) { > } > > closedir(dir); > > return; > errout: > if (dir) { > closedir(dir); > } > > return; > } > > void *test_fork(void *arg) > { > int count = 0; > while (do_exit == 0) { > printf("test fork count %d\n", count++); > int pid = vfork(); > if (pid < 0) { > return NULL; > } else if (pid == 0) { > lockfunc(); > _exit(0); > } > > int status; > waitpid(pid, &status, 0); > } > > return NULL; > } > > int main(int argc, char *argv[]) > { > pthread_attr_t attr; > pthread_t threads[10]; > pthread_t fork_test; > int i; > int ret; > > pthread_attr_init(&attr); > > ret = pthread_create(&fork_test, &attr, test_fork, NULL); > > for (i = 0; i < 10; i++) { > ret = pthread_create(&threads[i], &attr, test, NULL); > if (ret != 0) { > return 1; > } > } > > for (i = 0; i < 10; i++) { > void *retval = NULL; > pthread_join(threads[i], &retval); > } > > void *retval = NULL; > pthread_join(fork_test, &retval); > printf("exit\n"); > getchar(); > return 0; > } > > > Log: > pi@...pberrypi:~/code/tinylog/test $ ./test > test fork count 0 > test fork count 1 <-- lock here > ^C > > gdb backtrace: > x0000000000409524 in __lock () > (gdb) bt > #0 0x0000000000409524 in __lock () > #1 0x0000000000406278 in __libc_malloc_impl ()
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.