From dfb5fe2dee1b64c57c3df7fc4c0ecb7ad0450730 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Sat, 24 Nov 2001 10:17:24 +0000 Subject: Move the FAQ. Add a docs dir. Add in a report on thread support. -Erik --- docs/threads.txt | 2275 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2275 insertions(+) create mode 100644 docs/threads.txt (limited to 'docs/threads.txt') diff --git a/docs/threads.txt b/docs/threads.txt new file mode 100644 index 000000000..2d5d9e623 --- /dev/null +++ b/docs/threads.txt @@ -0,0 +1,2275 @@ +uClibc thread-safety analysis +By Steve Thayer +with updates by Erik Andersen + +Introduction: + +The purpose of this document is to identify the things that need to be done +to the uClibc C library in order to make it thread-safe. The goal is to be +able to use a pthreads thread implementation under uClinux, using the uClibc +C library. To help identify the things that require changing, I used David R. +Butenhof's book Programming With POSIX Threads, the source code for the +glibc 2.1.3 C library, and the source code for the C library included in the +Proventhreads distribution. + +References: + +Butenhof, David R., Programming With POSIX Threads, Addison Wesley Longman, Inc., Reading, MA, ISBN 0-201-63392-2, 1997. + + +The GNU C library is available from the Free Software Foundation +http://www.gnu.org/software/libc/libc.html + +Proventhreads is part of the Inferno Operating system. +http://www.vitanuova.com/inferno/index.html + + +1. Stdio: + +1.1 Buffer access mutexes + + The following functions are required in order to protect shared + I/O buffers from being accessed by more than one thread at a time. + None of these functions are currently implemented in the uClibc + library, so they must be added. + + flockfile <--- + ftrylockfile <--- + funlockfile <--- + +1.2 Functions that must use buffer access mutexes, according to Butenhof + + The following functions are identified by Butenhof as needing to use + buffer access mutexes. This does not represent all functions that + need to use the mutexes. + + getc <--- + getchar <--- + putc <--- + putchar <--- + +1.3 Functions from glibc (libio) that use buffer access mutexes + + The following functions are functions found in glibc that currently + use the buffer access mutexes. Comments in brackets represent + status of uClibc with regard to these functions. Most of these + functions aren't even supported under uClibc, so no work is required. + The rest may require the access mutex. (These must be analyzed on a + case-by-case basis.) + + clearerr <--- + feof <--- + ferror <--- + fputc <--- + fputwc + freopen <--- + freopen64 + fseek <--- + fseeko + fseeko64 + ftello + ftello64 + fwide + getc + getchar + getwc + getwchar + iofclose + iofflush + iofgetpos + iofgetpos64 + iofgets + iofgetws + iofputs + iofputws + iofread + iofsetpos + iofsetpos64 + ioftell + iofwrite + iogetdelim + iogets + ioputs + ioseekoff + ioseekpos + iosetbuffer + iosetvbuf + ioungetc + ioungetwc + oldiofclose + oldiofgetpos + oldiofgetpos64 + oldiofsetpos + oldiofsetpos64 + peekc + putc + putchar + putwc + putwchar + rewind <--- + +1.4 Functions from Proventhreads that use buffer access mutexes + + See description above. This applies only to the C library included + in the proventhreads distribution. + + clearerr <--- + fclose <--- + fflush <--- + fgetc <--- + __getc + fgetline + fgetpos <--- + fgets <--- + fpurge + fputc <--- + __putc + fputs <--- + fread <--- + freopen <--- + fscanf <--- + fseek <--- + ftell <--- + fwalk + fwrite <--- + getc + getchar <--- + putc + putchar <--- + puts <--- + putw + refill + rewind <--- + scanf <--- + setvbuf <--- + ungetc <--- + vfprintf <--- + vscanf <--- + +1.5 Unlocked buffer access + + These functions get used in situations where speed is important, + and locking isn't necessary, or for use in a section of code that + is already locked. For example, a for-loop that makes multiple calls + to getc could make an exlicit call to flockfile outside the loop, and + then use getc_unlocked within the loop for speed. That way, the lock + only needs to be grabbed and released once, rather than for each call. + + getc_unlocked <--- + getchar_unlocked <--- + putc_unlocked <--- + putchar_unlocked <--- + +1.6 Additional unlocked calls made in glibc + + These are additional functions (not mentioned by Butenhof) that the + glibc library uses for unlocked buffer access. Though not strictly + necessary, these may be nice to have in uClibc. + + fileno_unlocked <--- + clearerr_unlocked <--- + feof_unlocked <--- + ferror_unlocked <--- + fputc_unlocked <--- + fgetc_unlocked <--- + fflush_unlocked <--- + fread_unlocked <--- + fwrite_unlocked <--- + fgets_unlocked <--- + fputs_unlocked <--- + +1.7 Additional unlocked calls made in Proventhreads + + Proventhreads only provides the four unlocked function calls above. + + + + +2. Thread-safe functions: + + There are some functions in the C library standard that are + simply not thread-safe and cannot be thread-safe using their + current interface. For example, any function that returns a + pointer to static data, or requires static context between + calls. To resolve this problem, new functions were added to + the standard that perform the same basic task, but use a new + interface that does not require static data. These functions + share their name with the old unsafe functions, but have an + "_r" appended to the name. By definition, these functions are + reentrant and thread-safe. It is important to note that these + functions to do not depend on and can be used even + if threading is not supported. + +2.1 User and terminal identification: + + getlogin_r + ctermid (1) + ttyname_r <--- + + 1. ctermid is a special case. The signature has not changed, but a + requirement has been added that its parameter point to a structure + of exactly L_ctermid bytes. + +2.2 Directory searching + + readdir_r <--- + +2.3 String token + + strtok_r + +2.4 Time representation + + asctime_r + ctime_r + gmtime_r + localtime_r + +2.5 Random number generation + + rand_r <--- + +2.6 Group and user database + + getgrgid_r <--- + getgrnam_r <--- + getpwuid_r + getpwnam_r + +2.7 Additional thread-safe functions implemented by glibc + + The following is a list of additional functions implemented by glibc + that also provide thread-safe functionality. Most of these functions + are not supported by uClibc, so there is no need to implement the + thread-safe version. Those that do apply, but have not been + implemented yet are highlighted. + + __fgetpwent_r + fgetpwent_r + __ttyname_r + getttyname_r + __getmntent_r + getmntent_r <--- + ecvt_r + fcvt_r + qecvt_r + qfcvt_r + hcreate_r + hdestroy_r + hsearch_r + __getspent_r + getspent_r + __getspnam_r + getspnam_r + __sgetspent_r + sgetspent_r + __fgetspent_r + fgetspent_r + __gethostbyaddr_r + gethostbyaddr_r <--- + __gethostbyname2_r + gethostbyname2_r + __gethostbyname_r + gethostbyname_r <--- + __gethostent_r + __getnetbyaddr_r + getnetbyaddr_r <--- + __getnetent_r + getnetent_r <--- + __getnetbyname_r + getnetbyname_r <--- + __getprotobynumber_r + getprotobynumber_r <--- + __getprotoent_r + getprotoent_r <--- + __getprotobyname_r + getprotobyname_r <--- + __getservbyname_r + getservbyname_r <--- + __getservbyport_r + getservbyport_r <--- + __getservent_r + getservent_r <--- + __getrpcent_r + getrpcent_r <--- + __getrpcbyname_r + getrpcbyname_r <--- + __getrpcbynumber_r + getrpcbynumber_r <--- + ether_aton_r + ether_ntoa_r + __getnetgrent_r + __internal_getnetgrent_r + getnetgrent_r + __getaliasent_r + getaliasent_r + __getaliasbyname_r + getaliasbyname_r + __nscd_getpwnam_r + __nscd_getpwuid_r + nscd_getpw_r + __nscd_getgrgid_r + __nscd_getgrnam_r + nscd_getgr_r + __nscd_gethostbyaddr_r + __nscd_gethostbyname2_r + __nscd_gethostbyname_r + nscd_gethst_r + __getutent_r <--- + getutent_r <--- + getutent_r_unknown + getutid_r_unknown + getutline_r_unknown + __getutid_r + getutid_r <--- + __getutline_r + getutline_r <--- + getutent_r_file + getutid_r_file + getutline_r_file + internal_getut_r + getutent_r_daemon + getutid_r_daemon + getutline_r_daemon + __ptsname_r + ptsname_r + + +2.8 Additional thread-safe functions implemented by Proventhreads + + See description above. This applies only to the C library included + in the proventhreads distribution. + + inet_ntoa_r <--- + gethostbyaddr_r <--- + gethostbyname_r <--- + gethostent_r + getnetbyaddr_r <--- + getnetbyname_r <--- + getnetent_r <--- + getprotobynumber_r <--- + getprotoent_r <--- + getprotobyname_r <--- + getservbyname_r <--- + getservbyport_r <--- + getservent_r <--- + + +3. List of functions in uClibc that use static data structures + + The following is a list of static data structures found in uClibc, + and the functions that use them. In most cases, static data is not + thread-safe, since multiple threads can access the same data at the + same time. This is an attempt to identify all of the static data that + is not considered thread-safe. Some of these problems will get + resolved by the changes outlines above. + + crypt/crypt.c: + + static struct crypt_data __crypt_data; + + crypt + setkey + encrypt + + -------------------------------------------------------------------- + + crypt/md5.c: + + static unsigned char PADDING[64] <--- + + NOTE: This is okay, but should use the const keyword. + + -------------------------------------------------------------------- + + inet/addr.c: + + static char buf[16]; + + inet_ntoa <--- + + -------------------------------------------------------------------- + + inet/getnetent.c: + + static FILE *netf = NULL; + static char line[BUFSIZ+1]; + static struct netent net; + static char *net_aliases[MAXALIASES]; + + setnetent <--- + endnetent <--- + getnetent <--- + + NOTE: setnetent and endnetent are not implemented in glibc. + Proventhreads uses pthread mutexes to protect this static data. + + -------------------------------------------------------------------- + + inet/getproto.c: + + static FILE *protof = NULL; + static char line[BUFSIZ+1]; + static struct protoent proto; + static char *proto_aliases[MAXALIASES]; + static int proto_stayopen; + + setprotoent <--- + endprotoent <--- + getprotoent <--- + getprotobyname <--- + getprotobynumber <--- + + NOTE: setprotoent and endprotoent are not implemented in glibc. + Proventhreads uses pthread mutexes to protect this static data. + + -------------------------------------------------------------------- + + inet/getservice.c: + + static FILE *servf = NULL; + static char line[BUFSIZ+1]; + static struct servent serv; + static char *serv_aliases[MAXALIASES]; + static int serv_stayopen; + + setservent <--- + endservent <--- + getservent <--- + getservbyname <--- + getservbyport <--- + + NOTE: setservent and endservent are not implemented in glibc. + Proventhreads uses pthread mutexes to protect this static data. + + -------------------------------------------------------------------- + + net/resolv.c: + + static int id = 1; + static int ns = 0; + + dns_lookup <--- + + NOTE: dns_lookup is not implemented by glibc or Proventhreads. + + static struct hostent h; + static char namebuf[256]; + static struct in_addr in; + static struct in_addr *addr_list[2]; + + gethostbyname <--- + + static struct hostent h; + static char namebuf[256]; + static struct in_addr in; + static struct in_addr *addr_list[2]; + + gethostbyaddr <--- + + static struct hostent h; + static struct in_addr in; + static struct in_addr *addr_list[2]; + static char line[80]; + + read_etc_hosts <--- + + NOTE: dns_lookup is not implemented by glibc or Proventhreads. + + -------------------------------------------------------------------- + + inet/rpc/auth_none.c: + + static struct auth_ops ops + static struct authnone_private + + authnone_create <--- + authnone_marshal <--- + + NOTE: This file makes a lot of use of this static variable and + also a global allocated authentication structure. Care should + be taken in fixing this to make it thread-safe. + + -------------------------------------------------------------------- + + inet/rpc/auth_unix.c: + + static struct auth_ops auth_unix_ops + + authunix_create <--- + marshal_new_auth <--- + + NOTE: This file makes a lot of use of this static variable and + also a global allocated authentication structure. Care should + be taken in fixing this to make it thread-safe. + + -------------------------------------------------------------------- + + inet/rpc/bindresvport.c: + + static short port; + + bindresvport <--- + + -------------------------------------------------------------------- + + inet/rpc/clnt_perror.c: + + static char *buf; + static struct rpc_errtab rpc_errlist[] + static struct auth_errtab auth_errlist[] + + NOTE: These static structures all have #if 0 around them, so they + do not get compiled in. Hopefully, we don't have to worry about + them right now, but prehaps a comment should be added to the code + indicating that it is not thread-safe. + + -------------------------------------------------------------------- + + inet/rpc/clnt_raw.c: + + static struct clntraw_private + static struct clnt_ops client_ops + + clntraw_create <--- + clntraw_call <--- + clntraw_freeres <--- + + NOTE: This file makes a lot of use of these static variables and + also a global allocated client structure. Care should + be taken in fixing this to make it thread-safe. + + -------------------------------------------------------------------- + + inet/rpc/clnt_simple.c: + + static struct callrpc_private + + callrpc <--- + + -------------------------------------------------------------------- + + inet/rpc/clnt_tcp.c: + + static struct clnt_ops tcp_ops + + clnttcp_create + + NOTE: This static structure is just a group of function pointers. + It could probably be made const, but this might affect the function + signature. This should be investigated further. + + -------------------------------------------------------------------- + + inet/rpc/clnt_udp.c: + + static struct clnt_ops udp_ops + + clntudp_bufcreate + + NOTE: This static structure is just a group of function pointers. + It could probably be made const, but this might affect the function + signature. This should be investigated further. + + -------------------------------------------------------------------- + + inet/rpc/getrpcent.c: + + static char RPCDB[] <--- + + NOTE: This is okay, but should use the const keyword. + + -------------------------------------------------------------------- + + inet/rpc/pmap_clnt.c: + + static struct timeval timeout <--- + static struct timeval tottimeout <--- + + NOTE: These are okay, but should use the const keyword. + + -------------------------------------------------------------------- + + inet/rpc/pmap_getport.c: + + static struct timeval timeout <--- + static struct timeval tottimeout <--- + + NOTE: These are okay, but should use the const keyword. + + -------------------------------------------------------------------- + + inet/rpc/pmap_rmt.c: + + static struct timeval timeout <--- + + NOTE: This is okay, but should use the const keyword. + + -------------------------------------------------------------------- + + inet/rpc/rpc_dtablesize.c: + + static int size; + + _rpc_dtablesize <--- + + -------------------------------------------------------------------- + + inet/rpc/rpc_prot.c: + + static struct xdr_discrim reply_dscrm[3] <--- + + NOTE: This is okay, but should use the const keyword. + + -------------------------------------------------------------------- + + inet/rpc/svc.c: + + static SVCXPRT **xports; + static SVCXPRT *xports[NOFILE]; + static struct svc_callout + + xprt_register <--- + xprt_unregister <--- + svc_getreqset <--- + svc_register <--- + svc_unregister <--- + svc_callout <--- + + NOTE: This is intricate code, and care should be taken when making + this thread-safe. + + -------------------------------------------------------------------- + + inet/rpc/svc_auth.c: + + static struct svcauthsw <--- + + NOTE: This is okay, but should use the const keyword. + + -------------------------------------------------------------------- + + net/rpc/svc_raw.c: + + static struct svcraw_private + static struct xp_ops server_ops + + svcraw_create <--- + svcraw_recv <--- + svcraw_reply <--- + svcraw_getargs <--- + svcraw_freeargs <--- + + NOTE: This is intricate code, and care should be taken when making + this thread-safe. + + -------------------------------------------------------------------- + + inet/rpc/svc_simple.c: + + static struct proglst + static SVCXPRT *transp; + + registerrpc <--- + universal <--- + + NOTE: This is intricate code, and care should be taken when making + this thread-safe. + + -------------------------------------------------------------------- + + inet/rpc/svc_tcp.c: + + static struct xp_ops svctcp_op + static struct xp_ops svctcp_rendezvous_op + + svctcp_create <--- + makefd_xprt <--- + + NOTE: This static structure is just a group of function pointers. + It could probably be made const, but this might affect the function + signature. This should be investigated further. + + static struct timeval wait_per_try + + readtcp <--- + + NOTE: This looks like a bug. This static timeout value is passed + by reference to a select() call. According to the linux man page + for select: + + "On Linux, timeout is modified to reflect the amount of + time not slept; most other implementations do not do this. + This causes problems both when Linux code which reads + timeout is ported to other operating systems, and when + code is ported to Linux that reuses a struct timeval for + multiple selects in a loop without reinitializing it. + Consider timeout to be undefined after select returns." + + Unless the implementation of select is different than that of Linux, + this needs to be fixed! + + -------------------------------------------------------------------- + + inet/rpc/svc_udp.c: + + static struct xp_ops svcudp_op (1) + + svcudp_bufcreate + + 1: This static structure is just a group of function pointers. + It could probably be made const, but this might affect the function + signature. This should be investigated further. + + -------------------------------------------------------------------- + + inet/rpc/xdr.c: + + static char xdr_zero[BYTES_PER_XDR_UNIT] <--- + + NOTE: This is okay, but should use the const keyword. + + static u_long crud[BYTES_PER_XDR_UNIT] + + NOTE: This looks like it doesn't matter what's in this array. + + -------------------------------------------------------------------- + + inet/rpc/xdr_float.c: + + static struct sgl_limits <--- + static struct dbl_limits <--- + + NOTE: These are okay, but should use the const keyword. + + -------------------------------------------------------------------- + + inet/rpc/xdr_mem.c: + + static struct xdr_ops xdrmem_ops (1) + + xdrmem_create + + 1: This static structure is just a group of function pointers. + It could probably be made const, but this might affect the function + signature. This should be investigated further. + + -------------------------------------------------------------------- + + inet/rpc/xdr_rec.c: + + static struct xdr_ops xdrrec_ops (1) + + xdrrec_create + + 1: This static structure is just a group of function pointers. + It could probably be made const, but this might affect the function + signature. This should be investigated further. + + -------------------------------------------------------------------- + + inet/rpc/xdr_stdio.c: + + static struct xdr_ops xdrstdio_ops (1) + + xdrstdio_create + + 1: This static structure is just a group of function pointers. + It could probably be made const, but this might affect the function + signature. This should be investigated further. + + -------------------------------------------------------------------- + + ld.so-1/d-link/boot1.c: + + static char *_dl_malloc_addr + static char *_dl_mmap_zero + static char *_dl_not_lazy + static char *_dl_warn + static char *_dl_trace_loaded_objects + + _dl_boot <--- + _dl_malloc <--- + _dl_fixup <--- + + These are all part of the shared library loader, and are not + used by applications directly. Therefore, fixing these is not + a high priority item. + + -------------------------------------------------------------------- + + ld.so-1/d-link/readelflib1.c: + + static caddr_t _dl_cache_addr + static size_t _dl_cache_size + + _dl_map_cache <--- + _dl_unmap_cache <--- + _dl_load_shared_library <--- + + These are all part of the shared library loader, and are not + used by applications directly. Therefore, fixing these is not + a high priority item. + + -------------------------------------------------------------------- + + ld.so-1/d-link/string.h: + + static char local[22] + + _dl_simple_ltoa <--- + _dl_simple_ltoahex <--- + + These are all part of the shared library loader, and are not + used by applications directly. Therefore, fixing these is not + a high priority item. + + -------------------------------------------------------------------- + + ld.so-1/d-link/arm/elfinterp.c: + + static char *_dl_reltypes[] <--- + + NOTE: This is okay, but should use the const keyword. + + -------------------------------------------------------------------- + + ld.so-1/d-link/i386/elfinterp.c: + + static char *_dl_reltypes[] <--- + + NOTE: This is okay, but should use the const keyword. + + These are all part of the shared library loader, and are not + used by applications directly. Therefore, fixing these is not + a high priority item. + + -------------------------------------------------------------------- + + ld.so-1/d-link/m68k/elfinterp.c: + + static char *_dl_reltypes[] <--- + + NOTE: This is okay, but should use the const keyword. + + These are all part of the shared library loader, and are not + used by applications directly. Therefore, fixing these is not + a high priority item. + + -------------------------------------------------------------------- + + ld.so-1/d-link/sparc/elfinterp.c: + + static char *_dl_reltypes[] <--- + + NOTE: This is okay, but should use the const keyword. + + These are all part of the shared library loader, and are not + used by applications directly. Therefore, fixing these is not + a high priority item. + + -------------------------------------------------------------------- + + ld.so-1/libdl/dlib.c: + + static int dl_init + + _dlopen <--- + + static int __attribute__ ((unused)) foobar1 (1) + + NOTE: The comment for this says it all: "This is a real hack." ;-) + + + static char *type[] <--- + + NOTE: This is okay, but should use the const keyword. + + These are all part of the shared library loader, and are not + used by applications directly. Therefore, fixing these is not + a high priority item. + + -------------------------------------------------------------------- + + ld.so-1/util/ldconfig.c: + + static header_t magic <--- + + NOTE: This is okay, but should use the const keyword. + + static liblist_t *lib_head + + cache_dolib <--- + cache_write <--- + + This is not actually part of the C library, and is not built by + default, so fixing these is not a high priority item. + + -------------------------------------------------------------------- + + misc/internals/tempname.c: + + static uint64_t value; + + __gen_tempname <--- + + -------------------------------------------------------------------- + + misc/locale/locale.c: + + static char C_LOCALE_NAME[]="C"; <--- + + NOTE: This is okay, but should use the const keyword. + + static struct SAV_LOADED_LOCALE sav_loaded_locale [1] + static struct SAV_LOADED_LOCALE * old_locale + + setlocale <--- + + NOTE: Can different threads use different locales? I don't see + why not. + + -------------------------------------------------------------------- + + misc/locale/localeconv.c: + + static struct lconv result; + + localeconv <--- + + NOTE: This function returns a pointer to a static data structure. + + static char *blank = ""; <--- + static char *decimal = "."; <--- + + NOTE: These are okay, but should use the const keyword. + + -------------------------------------------------------------------- + + misc/mntent/mntent.c: + + static char buff[MNTMAXSTR]; + static struct mntent mnt; + + getmntent <--- + + -------------------------------------------------------------------- + + misc/regex/regex.c: + + static char re_syntax_table[CHAR_SET_SIZE]; + static int done = 0; + + init_syntax_table <--- + + static int debug; + + <--- + + NOTE: This is used to turn on debugging, and is used in several + functions. It will need to be fixed if you want differing debug + levels per thread. + + static char reg_unset_dummy; + + <--- + + static fail_stack_type fail_stack; + + regex_compile <--- + <--- + <--- + <--- + <--- + <--- + <--- + <--- + <--- + <--- + <--- + <--- + <--- + <--- + <--- + + static int regs_allocated_size; + + regs_grow_registers <--- + + static register_info_type *reg_info; + static register_info_type *reg_info_dummy; + static unsigned failure_id; + static struct re_pattern_buffer re_comp_buf; + + <--- + + NOTE: This is just a NASTY file for static variables. A lot of + work needs to be done here to clean this up. But I'm not even + sure if it matters. This code is taken directly from glibc. + + This code is also very large (adds over 30k to the C library + all by itself). This file needs a complete rewrite. + + -------------------------------------------------------------------- + + misc/syslog/syslog.c: + + static pthread_once__t _once_block = pthread_once_init; + static pthread_mutex_t _syslog_mutex; + + NOTE: I think these are okay. ;-) + + static int LogFile = -1; + static int connected; + static int LogStat = 0; + static int LogFacility = LOG_USER; + static int LogMask = 0xff; + static char truncate_msg[12] + static struct sockaddr SyslogAddr; + + NOTE: These are already protected. + + -------------------------------------------------------------------- + + misc/time/asctime.c: + + static char timebuf[26]; + + asctime + + -------------------------------------------------------------------- + + misc/time/ctime.c: + + static char cbuf[26]; + + ctime + + -------------------------------------------------------------------- + + misc/time/gmtime.c: + + static struct tm tmb; + + gmtime + + -------------------------------------------------------------------- + + misc/time/localtime.c: + + static struct tm tmb; + + localtime + + -------------------------------------------------------------------- + + misc/time/mktime.c: + + static tz_rule tz_rules[2]; + + tzset <--- + + static time_t localtime_offset; + + mktime <--- + + -------------------------------------------------------------------- + + misc/time/tm_conv.c: + + static int moffset[] <--- + + NOTE: This is okay, but should use the const keyword. + + -------------------------------------------------------------------- + + misc/utmp/utent.c: + + static int ut_fd = -1; + + setutent <--- + endutent <--- + getutent <--- + getutid <--- + getutline <--- + pututline <--- + utmpname <--- + + static struct utmp utmp; + + __getutent <--- + + -------------------------------------------------------------------- + + pwd_grp/__getgrent.c: + + static char line_buff[GR_MAX_LINE_LEN]; + static char *members[GR_MAX_MEMBERS]; + static char *line_buff = NULL; + static char **members = NULL; + static struct group group; + + __getgrent <--- + + -------------------------------------------------------------------- + + pwd_grp/fgetpwent.c: + + static char line_buff[PWD_BUFFER_SIZE]; + static struct passwd pwd; + + fgetpwent + + -------------------------------------------------------------------- + + pwd_grp/getpwnam.c: + + static char line_buff[PWD_BUFFER_SIZE]; + static struct passwd pwd; + + getpwnam + + -------------------------------------------------------------------- + + pwd_grp/getpwuid.c: + + static char line_buff[PWD_BUFFER_SIZE]; + static struct passwd pwd; + + getpwuid + + -------------------------------------------------------------------- + + pwd_grp/grent.c: + + static int grp_fd = -1; + + setgrent <--- + endgrent <--- + getgrent <--- + + -------------------------------------------------------------------- + + pwd_grp/pwent.c: + + static int pw_fd = -1; + + setpwent <--- + endpwent <--- + getpwent_r <--- + + NOTE: Yeah, this looks weird, but getpwent_r isn't completely + thread-safe. + + static char line_buff[PWD_BUFFER_SIZE]; + static struct passwd pwd; + + getpwent <--- + + -------------------------------------------------------------------- + + stdio/tmpnam.c: + + static char tmpnam_buffer[L_tmpnam]; + + tmpnam + + -------------------------------------------------------------------- + + stdlib/atexit.c: + + static vfuncp __atexit_table[__UCLIBC_MAX_ATEXIT]; + static int __atexit_count = 0; + + atexit_handler <--- + atexit <--- + + -------------------------------------------------------------------- + + stdlib/bsearch.c: + + static int _bsearch; + + bsearch <--- + + -------------------------------------------------------------------- + + stdlib/putenv.c: + + static char **mall_env = 0; + static int extras = 0; + + putenv <--- + + -------------------------------------------------------------------- + + stdlib/random.c: + + static long int seed1 = 1; + static long int seed2 = 1; + static long int seed3 = 1; + + random (1) + srandom (1) + + 1: I'm not sure if it matters if these are static, since they + are random number seeds. Who cares if more than one thread changes + their value? + + -------------------------------------------------------------------- + + stdlib/setenv.c: + + static pthread_once__t _once_block = pthread_once_init; (1) + static pthread_mutex_t _setenv_mutex; (1) + static char **last_environ = NULL; (1) + + 1: Obviously, nothing to do here. (Unless I change the way we + deal with threads). + + -------------------------------------------------------------------- + + stdlib/malloc/avlmacro.h + + static objname *__Avl_##objname##pr##_new_node; + + Avl_Tree_no_replace <--- + + NOTE: This will take a bit of study to figure out if it needs fixing. + + -------------------------------------------------------------------- + + stdlib/malloc/malloc.c: + + //static mutex_t malloc_lock = MUTEX_INITIALIZER; <--- + + NOTE: Basically, thread support in malloc is broken and must be + fixed. It looks like the infrastructure is there, but more + investigation is required. + + -------------------------------------------------------------------- + + stdlib/malloc-930716/malloc.c: + + static int heapsize; + static int initialized; + static size_t pagesize; + + inititalize <--- + morecore <--- + malloc <--- + + -------------------------------------------------------------------- + + stdlib/malloc-930716/valloc.c: + + static size_t pagesize; + + valloc <--- + + -------------------------------------------------------------------- + + string/config.c: + + static char *args[16]; + static char cfgbuf[128]; + + cfgread <--- + + -------------------------------------------------------------------- + + string/strerror.c: + + static char retbuf[48]; + static char retbuf[33]; + + strerror <--- + main <--- + + -------------------------------------------------------------------- + + string/strsignal.c: + + static char retbuf[28]; + + strsignal <--- + main <--- + + -------------------------------------------------------------------- + + string/strtok.c: + + static char *save = 0; + + strtok <--- + + -------------------------------------------------------------------- + + sysdeps/linux/common/kernel_version.c: + + static int __linux_kernel_version = -1; + + __get_linux_kernel_version (1) + + 1: This static value never actually gets updated! This a bug. + + -------------------------------------------------------------------- + + sysdeps/linux/i386/bits/huge_val.h: + + static __huge_val_t __huge_val <--- + static __huge_valf_t __huge_valf <--- + static __huge_vall_t __huge_vall <--- + + NOTE: These are okay, but should use the const keyword. + + -------------------------------------------------------------------- + + sysdeps/linux/i386/bits/nan.h: + + static union { ... } __nan_union <--- + + NOTE: This is okay, but should use the const keyword. + + -------------------------------------------------------------------- + + sysdeps/linux/m68k/bits/huge_val.h: + + static union { ... } __huge_val <--- + static union { ... } __huge_valf <--- + static union { ... } __huge_vall <--- + + NOTE: These are okay, but should use the const keyword. + + -------------------------------------------------------------------- + + sysdeps/linux/m68k/bits/nan.h: + + static union { ... } __nan_union <--- + + NOTE: This is okay, but should use the const keyword. + + -------------------------------------------------------------------- + + sysdeps/linux/sh/bits/huge_val.h: + + static __huge_val_t __huge_val <--- + static __huge_valf_t __huge_valf <--- + + NOTE: These are okay, but should use the const keyword. + + -------------------------------------------------------------------- + + sysdeps/linux/sh/bits/nan.h: + + static union { ... } __nan_union <--- + + NOTE: This is okay, but should use the const keyword. + + -------------------------------------------------------------------- + + sysdeps/linux/sparc/bits/huge_val.h: + + static __huge_val_t __huge_val <--- + static __huge_valf_t __huge_valf <--- + + NOTE: These are okay, but should use the const keyword. + + -------------------------------------------------------------------- + + sysdeps/linux/sparc/bits/nan.h: + + static union { ... } __nan_union <--- + + NOTE: This is okay, but should use the const keyword. + + -------------------------------------------------------------------- + + termios/tcgetsid.c: + + static int tiocgsid_does_not_work; + + tcgestsid <--- + + -------------------------------------------------------------------- + + termios/ttyname.c: + + static char dev[] = "/dev"; + + ttyname <--- + + NOTE: This is okay, but should use the const keyword. + + static char name[NAME_MAX]; + + ttyname <--- + + -------------------------------------------------------------------- + + test/testsuite.h: + + static int failures + + error_msg <--- + done_testing <--- + init_testsuite <--- + + -------------------------------------------------------------------- + + unistd/getcwd.c: + + static char *path_buf; + static int path_size; + static dev_t root_dev; + static ino_t root_ino; + static struct stat st; + + getswd <--- + recurser <--- + search_dir <--- + + -------------------------------------------------------------------- + + unistd/getopt.c: + + static int sp = 1; + + getopt <--- + + -------------------------------------------------------------------- + + unistd/getpass.c: + + static char buf[PWD_BUFFER_SIZE]; + + getpass <--- + + NOTE: This function returns a pointer to a static data structure. + This seems like it requires an _r version of this function. Glibc + does the same thing. Oops! So much for thread-safe glibc! + + -------------------------------------------------------------------- + + unistd/gnu_getopt.c: + + static char *nextchar; + static enum ordering; + static int first_nonopt; + static int last_nonopt; + + _getopt_initialize <--- + _getopt_internal <--- + exchange <--- + + static struct option long_options[] <--- + + NOTE: This is okay, but should use the const keyword. + + -------------------------------------------------------------------- + + unistd/sysconf.c: + + static long int ret_vals[_UCLIBC_SYSCONF_NUM_VALID_ARGS]; + + find_or_add_in_table <--- + main <--- + + NOTE: I'm not sure if this needs to be multi-threaded or not. + + -------------------------------------------------------------------- + + unistd/sysconf_src.c: + + static long int ret_vals[_UCLIBC_SYSCONF_NUM_VALID_ARGS]; + + find_or_add_in_table <--- + main <--- + + NOTE: I'm not sure if this needs to be multi-threaded or not. + + -------------------------------------------------------------------- + + unistd/sysconf_i386.c: + + static long int ret_vals[_UCLIBC_SYSCONF_NUM_VALID_ARGS]; + + find_or_add_in_table <--- + main <--- + + NOTE: I'm not sure if this needs to be multi-threaded or not. + + -------------------------------------------------------------------- + + +4. List of functions that use global variables + + The following is a list of functions that make use of global + variables. Since multiple threads can access the same global + variable at the same time, access should be considered unsafe. + This is an attempt to identify all the areas where global + variables are used. This does not necessarily mean that each + of these is unsafe. It just means that there is a potential + for them to be unsafe. If this code never runs in more than + one thread, then there's no problem. More ivestigation will be + required to determine if changes are really required. + + Global variable: + + __environ (misc/internals/__uClibc_main.c) + + __uClibc_main.c: + + __uClibc_main (1) + + 1: This should only get executed once, so it is probably fine. + + stdlib/getenv.c: + + getenv <--- + + stdlib/putenv.c: + + putenv <--- + + stdlib/setenv.c: + + setenv <--- + unsetenv <--- + + test/args/arg_test.c: + + main <--- + + unistd/execl.c: + + execl <--- + + unistd/execlp.c: + + execlp <--- + + unistd/execv.c: + + execv <--- + + unistd/execvp.c: + + execvep <--- + + -------------------------------------------------------------------- + + Global variable: + + __uClibc_cleanup (misc/internals/__uClibc_main.c) + + stdlib/abort.c: + + abort <--- + + stdlib/atexit.c: + + atexit_handler <--- + atexit <--- + exit <--- + + NOTE: Not sure if multiple threads can be in this code or not. + + -------------------------------------------------------------------- + + Global variable: + + environ (misc/internals/__uClibc_main.c) + + NOTE: This is a weak alias for __environ, but it doesn't ever get + used in the uClibc library. + + -------------------------------------------------------------------- + + Global variable: + + timezone (misc/time/tm_conv.c) + + misc/time/tm_conv.c: + + __tm_conv <--- + + -------------------------------------------------------------------- + + Global variable: + + re_max_failures (misc/regex/regex.c) + + misc/regex/regex.c: + + DOUBLE_FAIL_STACK <--- + regex_compile <--- + + -------------------------------------------------------------------- + + Global variable: + + re_syntax_options (misc/regex/regex.c) + + misc/regex/regex.c: + + re_set_syntax <--- + re_compile_pattern <--- + re_comp <--- + + -------------------------------------------------------------------- + + Global variable: + + __IO_list (stdio/stdio.c) + + stdio/stdio.c: + + fflush <--- + __fopen <--- + fclose <--- + + -------------------------------------------------------------------- + + Global variable: + + _fixed_buffers (stdio/stdio.c) + + stdio/stdio.c: + + _alloc_stdio_buffer <--- + _free_stdio_buffer_of_file <--- + __init_stdio <--- + + -------------------------------------------------------------------- + + Global variable: + + _free_buffer_index (stdio/stdio.c) + + stdio/stdio.c: + + _alloc_stdio_buffer <--- + _free_stdio_buffer_of_file <--- + __init_stdio <--- + + -------------------------------------------------------------------- + + Global variable: + + _free_file_list (stdio/stdio.c) + + stdio/stdio.c: + + __init_stdio <--- + _alloc_stdio_stream <--- + _free_stdio_stream <--- + + -------------------------------------------------------------------- + + Global variable: + + _stderr (stdio/stdio.c) + + ld.so-1/util/ldconfig.c: + + warn <--- + error <--- + usage <--- + + ld.so-1/util/ldd.c: + + warn <--- + error <--- + is_bin <--- + main <--- + + misc/locale/locale.c: + + setlocale <--- + + misc/regex/regex.c: + + printchar <--- + + stdio/perror.c: + + perror <--- + + stdlib/malloc/alloc.c: + + calloc_dbg <--- + malloc_dbg <--- + free_dbg <--- + + stdlib/malloc/malloc.c: + + __hunk_alloc (1) + __malloc_init (1) + malloc (1) + + 1: These are commented out with C++ style comments. + + stdlib/malloc-simple/alloc.c: + + calloc_dbg <--- + malloc_dbg <--- + free_dbg <--- + + string/strsignal.c: + + psignal <--- + + test/args/arg_test.c: + + main <--- + + test/assert/assert.c: + + main <--- + + unistd/getopt.c: + + Err <--- + + unistd/getpass.c: + + getpass <--- + + unistd/gnu_getopt.c: + + _getopt_internal <--- + + unistd/sysconf.c: + + main <--- + + unistd/sysconf_src.c: + + main <--- + + unistd/sysconf_i386.c: + + main <--- + + -------------------------------------------------------------------- + + Global variable: + + _stdin (stdio/stdio.c) + + include/stdio.h: + + getchar <--- + + include/bits/stdio.h: + + getchar <--- + getchar_unlocked <--- + + stdio/scanf.c: + + scanf <--- + vscanf <--- + + stdio/stdio.c + + gets <--- + getchar <--- + + sysdeps/linux/i386/bits/stdio.h: + + getchar <--- + getchar_unlocked <--- + + sysdeps/linux/m68k/bits/stdio.h: + + getchar <--- + getchar_unlocked <--- + + sysdeps/linux/sh/bits/stdio.h: + + getchar <--- + getchar_unlocked <--- + + sysdeps/linux/sparc/bits/stdio.h: + + getchar <--- + getchar_unlocked <--- + + unistd/getpass.c: + + getpass <--- + + -------------------------------------------------------------------- + + Global variable: + + _stdio_streams (stdio/stdio.c) + + stdio/stdio.c: + + __init_stdio <--- + _free_stdio_stream <--- + + -------------------------------------------------------------------- + + Global variable: + + _stdout (stdio/stdio.c) + + include/stdio.h: + + putchar <--- + + include/bits/stdio.h: + + vprintf <--- + putchar <--- + putchar_unlocked <--- + + ld.so-1/util/ldconfig.c: + + warn <--- + error <--- + + ld.so-1/util/ldd.c: + + warn <--- + error <--- + main <--- + + stdio/printf.c: + + printf <--- + vprintf <--- + + stdio/stdio.c: + + puts <--- + _uClibc_fread <--- + putchar <--- + + sysdeps/linux/i386/bits/stdio.h: + + vprintf <--- + putchar <--- + putchar_unlocked <--- + + sysdeps/linux/m68k/bits/stdio.h: + + vprintf <--- + putchar <--- + putchar_unlocked <--- + + sysdeps/linux/sh/bits/stdio.h: + + vprintf <--- + putchar <--- + putchar_unlocked <--- + + sysdeps/linux/sparc/bits/stdio.h: + + vprintf <--- + putchar <--- + putchar_unlocked <--- + + test/pwd_grp/test_grp.c: + + main <--- + + test/pwd_grp/test_pwd.c: + + main <--- + + -------------------------------------------------------------------- + + Global variable: + + dns_caught_signal (inet/resolv.c) + + inet/resolv.c: + + dns_catch_signal <--- + dns_lookup <--- + + -------------------------------------------------------------------- + + Global variable: + + nameserver (inet/resolv.c) + nameservers (inet/resolv.c) + + inet/resolv.c: + + open_nameservers <--- + close_nameservers <--- + resolve_name <--- + gethostbyname <--- + res_query <--- + gethostbyaddr <--- + + -------------------------------------------------------------------- + + Global variable: + + searchdomain (inet/resolv.c) + searchdomains (inet/resolv.c) + + inet/resolv.c: + + dns_lookup <--- + + -------------------------------------------------------------------- + + Global variable: + + _net_stayopen (inet/getnetent.c) + + inet/getnetbyad.c: + + getnetbyaddr <--- + + inet/getnetbynm.c: + + getnetbyname <--- + + inet/getnetent.c: + + setnetent <--- + endnetent <--- + + -------------------------------------------------------------------- + + Global variable: + + rpcdata (inet/rpc/getrpcent.c) + + inet/rpc/getrpcent.c: + + _rpcdata <--- + + -------------------------------------------------------------------- + + Global variable: + + _null_auth (inet/rpc/rpc_commondata.c) <--- + + NOTE: _null_auth is never actually initialized. It never gets written, + only read. So it should be thread safe. But it should be declared + as a const if that is the case. It should also be initialized. + + inet/rpc/auth_none.c: + + authnone_create + + inet/rpc/auth_unix.c: + + authunix_create + + inet/rpc/clnt_raw.c: + + clntraw_call + + inet/rpc/clnt_tcp.c: + + clnttcp_call + + inet/rpc/clnt_udp.c: + + clntudp_call + + inet/rpc/pmap_rmt.c: + + clnt_broadcast + + inet/rpc/svc_auth.c: + + _authenticate + + inet/rpc/svc_tcp.c: + + svctcp_create + + -------------------------------------------------------------------- + + Global variable: + + rpc_createerr (inet/rpc/rpc_commondata.c) + + inet/rpc/clnt_generic.c: + + clnt_create <--- + + inet/rpc/clnt_perror.c: + + clnt_spcreateerror <--- + + NOTE: This piece of code has an "#if 0" around it. + + inet/rpc/clnt_simple.c: + + callrpc <--- + + inet/rpc/clnt_tcp.c: + + clnttcp_create <--- + + inet/rpc/clnt_udp.c: + + clntudp_bufcreate <--- + + inet/rpc/pmap_getport.c: + + pmap_getport <--- + + -------------------------------------------------------------------- + + Global variable: + + svc_fdset (inet/rpc/rpc_commondata.c) + + inet/rpc/svc.c: + + xprt_register <--- + xprt_unregister <--- + svc_getreq <--- + + inet/rpc/svc_run.c: + + svc_run <--- + + NOTE: Be careful to also fix the uses of the "svc_fds" #define. + + -------------------------------------------------------------------- + + Global variable: + + pl (inet/rpc/svc_simple.c) + + registerrpc <--- + + NOTE: proglst is set up to point at pl, so it needs fixing as well. + (See proglst earlier in this document.) + + -------------------------------------------------------------------- + + Global variable: + + _sigintr (signal/signal.c) + + signal/bsd_sig.c: + + __bsd_signal <--- + + signal/sigintr.c: + + siginterrupt <--- + + -------------------------------------------------------------------- + + Global variable: + + __Avl_Block_tfree_mem_tree (stdlib/malloc/malloc.c) + + stdlib/malloc/malloc.c: + + __free_mem_del_block <--- + bl_alloc <--- + __malloc_init <--- + + NOTE: This code is very tricky stuff. + + -------------------------------------------------------------------- + + Global variable: + + __Avl_Block_tptrs_tree (stdlib/malloc/malloc.c) + + stdlib/malloc/malloc.c: + + __bl_free <--- + __malloc_init <--- + free <--- + _realloc_no_move <--- + realloc <--- + + -------------------------------------------------------------------- + + Global variable: + + __bl_last (stdlib/malloc/malloc.c) + + stdlib/malloc/malloc.c: + + COMBINE_BLOCKS <--- + SPLIT_BLOCK <--- + bl_mapnew <--- + bl_alloc <--- + __malloc_init <--- + + -------------------------------------------------------------------- + + Global variable: + + __free_h (stdlib/malloc/malloc.c) + + stdlib/malloc/malloc.c: + + __hunk_alloc <--- + __hunk_free <--- + __malloc_init <--- + + -------------------------------------------------------------------- + + Global variable: + + __malloc_initialized (stdlib/malloc/malloc.c) + + stdlib/malloc/malloc.c: + + __malloc_init <--- + malloc <--- + free <--- + _realloc_no_move <--- + + -------------------------------------------------------------------- + + Global variable: + + __total_h (stdlib/malloc/malloc.c) + + stdlib/malloc/malloc.c: + + __hunk_alloc <--- + __malloc_init <--- + + -------------------------------------------------------------------- + + Global variable: + + errno (sysdeps/linux/common/errno.c) + + sysdeps/linux/common/errno.c: + + __errno_location <--- + + NOTE: Obviously, errno gets used all over the place. I won't list + them all here. + + -------------------------------------------------------------------- + + Global variable: + + ___brk_addr (sysdeps/linux/i386/__init_brk.c) + + sysdeps/linux/i386/__init_brk.c: + + __init_brk <--- + + sysdeps/linux/i386/brk.c: + + brk <--- + + sysdeps/linux/i386/sbrk.c: + + sbrk <--- + + -------------------------------------------------------------------- + + Global variable: + + optarg (unistd/getopt_vars.c) + + extra/locale/gen_ctype_from_glibc.c: + + main (1) + + ld.so-1/util/ldconfig.c: + + main (1) + + unistd/getopt.c: + + getopt <--- + + unistd/gnu_getopt.c: + + _getopt_internal <--- + main (1) + + 1: Probably not required unless this program is run on multiple + threads. + + -------------------------------------------------------------------- + + Global variable: + + opterr (unistd/getopt_vars.c) + + ld.so-1/util/ldconfig.c: + + main (1) + + unistd/getopt.c: + + Err <--- + getopt <--- + + unistd/gnu_getopt.c: + + _getopt_internal <--- + + 1: Probably not required unless this program is run on multiple + threads. + + -------------------------------------------------------------------- + + Global variable: + + optind (unistd/getopt_vars.c) + + extra/locale/gen_ctype_from_glibc.c: + + main (1) + + ld.so-1/util/ldconfig.c: + + main (1) + + ld.so-1/util/ldd.c: + + main (1) + + unistd/getopt.c: + + Err <--- + getopt <--- + + unistd/gnu_getopt.c: + + exchange <--- + _getopt_initialize <--- + _getopt_internal <--- + main (1) + main (2nd one) (1) + + 1: Probably not required unless this program is run on multiple + threads. + + -------------------------------------------------------------------- + + Global variable: + + optopt (unistd/getopt_vars.c) + + unistd/getopt.c: + + Err <--- + getopt <--- + + unistd/gnu_getopt.c: + + _getopt_internal <--- + -- cgit v1.2.3