From: Bruno Haible Date: Tue, 24 May 2005 10:38:20 +0000 (+0000) Subject: glibc 2004-09-25 Ulrich Drepper X-Git-Tag: v0.15~512 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1adecea8a70a5df738182017eceac9f51753d1e6;p=thirdparty%2Fgettext.git glibc 2004-09-25 Ulrich Drepper --- diff --git a/gettext-runtime/intl/ChangeLog b/gettext-runtime/intl/ChangeLog index 26016fc12..0e4474a97 100644 --- a/gettext-runtime/intl/ChangeLog +++ b/gettext-runtime/intl/ChangeLog @@ -1,3 +1,26 @@ +2005-05-05 Bruno Haible + + * dcigettext.c (__libc_rwlock_wrlock): Define fallback. + * finddomain.c (__libc_rwlock_define_initialized, + __libc_rwlock_rdlock, __libc_rwlock_wrlock, __libc_rwlock_unlock): + Define fallbacks. + * loadmsgcat.c (__libc_lock_define_initialized_recursive, + __libc_lock_lock_recursive, __libc_lock_unlock_recursive): Define + fallbacks. + (_nl_load_domain): Fix portability problems in last patch. + +2004-09-25 Ulrich Drepper + + * dcigettext.c (DCIGETTEXT): Protect tfind/tsearch calls. + * dcigettext.c (_nl_find_msg): Call _nl_load_domain also if + decided < 0. + * finddomain.c (_nl_find_domain): Likewise. + * loadmsgcat.c (_nl_load_domain): Set decided to 1 only once we + are done. First set to -1 to signal initialization is ongoing. + Protect against concurrent callers with recursive lock. + * finddomain.c (_nl_find_domain): Protect calls to + _nl_make_l10nflist. [BZ #322] + 2004-08-06 Jakub Jelinek * finddomain.c (free_mem): Rename to... diff --git a/gettext-runtime/intl/dcigettext.c b/gettext-runtime/intl/dcigettext.c index 4d01774a1..738b12b5f 100644 --- a/gettext-runtime/intl/dcigettext.c +++ b/gettext-runtime/intl/dcigettext.c @@ -110,6 +110,7 @@ extern int errno; # define __libc_lock_unlock(NAME) # define __libc_rwlock_define_initialized(CLASS, NAME) # define __libc_rwlock_rdlock(NAME) +# define __libc_rwlock_wrlock(NAME) # define __libc_rwlock_unlock(NAME) #endif @@ -534,7 +535,15 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, search->localename = localename; # endif + /* Since tfind/tsearch manage a balanced tree, concurrent tfind and + tsearch calls can be fatal. */ + __libc_rwlock_define_initialized (static, tree_lock); + __libc_rwlock_rdlock (tree_lock); + foundp = (struct known_translation_t **) tfind (search, &root, transcmp); + + __libc_rwlock_unlock (tree_lock); + freea (search); if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr) { @@ -727,9 +736,14 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, newp->translation = retval; newp->translation_length = retlen; + __libc_rwlock_wrlock (tree_lock); + /* Insert the entry in the search tree. */ foundp = (struct known_translation_t **) tsearch (newp, &root, transcmp); + + __libc_rwlock_unlock (tree_lock); + if (foundp == NULL || __builtin_expect (*foundp != newp, 0)) /* The insert failed. */ @@ -794,7 +808,7 @@ _nl_find_msg (struct loaded_l10nfile *domain_file, char *result; size_t resultlen; - if (domain_file->decided == 0) + if (domain_file->decided <= 0) _nl_load_domain (domain_file, domainbinding); if (domain_file->data == NULL) diff --git a/gettext-runtime/intl/finddomain.c b/gettext-runtime/intl/finddomain.c index ebc507d69..8523ea8bf 100644 --- a/gettext-runtime/intl/finddomain.c +++ b/gettext-runtime/intl/finddomain.c @@ -1,5 +1,5 @@ /* Handle list of needed message catalogs - Copyright (C) 1995-1999, 2000-2001, 2003-2004 Free Software Foundation, Inc. + Copyright (C) 1995-1999, 2000-2001, 2003-2005 Free Software Foundation, Inc. Written by Ulrich Drepper , 1995. This program is free software; you can redistribute it and/or modify it @@ -37,6 +37,15 @@ # include "libgnuintl.h" #endif +#ifdef _LIBC +# include +#else +# define __libc_rwlock_define_initialized(CLASS, NAME) +# define __libc_rwlock_rdlock(NAME) +# define __libc_rwlock_wrlock(NAME) +# define __libc_rwlock_unlock(NAME) +#endif + /* @@ end of prolog @@ */ /* List of already loaded domains. */ static struct loaded_l10nfile *_nl_loaded_domains; @@ -83,17 +92,24 @@ _nl_find_domain (const char *dirname, char *locale, (7) audience/modifier */ + /* We need to protect modifying the _NL_LOADED_DOMAINS data. */ + __libc_rwlock_define_initialized (static, lock); + __libc_rwlock_rdlock (lock); + /* If we have already tested for this locale entry there has to be one data set in the list of loaded domains. */ retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname, strlen (dirname) + 1, 0, locale, NULL, NULL, NULL, NULL, NULL, NULL, NULL, domainname, 0); + + __libc_rwlock_unlock (lock); + if (retval != NULL) { /* We know something about this locale. */ int cnt; - if (retval->decided == 0) + if (retval->decided <= 0) _nl_load_domain (retval, domainbinding); if (retval->data != NULL) @@ -101,12 +117,13 @@ _nl_find_domain (const char *dirname, char *locale, for (cnt = 0; retval->successor[cnt] != NULL; ++cnt) { - if (retval->successor[cnt]->decided == 0) + if (retval->successor[cnt]->decided <= 0) _nl_load_domain (retval->successor[cnt], domainbinding); if (retval->successor[cnt]->data != NULL) break; } + return cnt >= 0 ? retval : NULL; /* NOTREACHED */ } @@ -138,24 +155,30 @@ _nl_find_domain (const char *dirname, char *locale, &codeset, &normalized_codeset, &special, &sponsor, &revision); + /* We need to protect modifying the _NL_LOADED_DOMAINS data. */ + __libc_rwlock_wrlock (lock); + /* Create all possible locale entries which might be interested in generalization. */ retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname, strlen (dirname) + 1, mask, language, territory, codeset, normalized_codeset, modifier, special, sponsor, revision, domainname, 1); + + __libc_rwlock_unlock (lock); + if (retval == NULL) /* This means we are out of core. */ return NULL; - if (retval->decided == 0) + if (retval->decided <= 0) _nl_load_domain (retval, domainbinding); if (retval->data == NULL) { int cnt; for (cnt = 0; retval->successor[cnt] != NULL; ++cnt) { - if (retval->successor[cnt]->decided == 0) + if (retval->successor[cnt]->decided <= 0) _nl_load_domain (retval->successor[cnt], domainbinding); if (retval->successor[cnt]->data != NULL) break; diff --git a/gettext-runtime/intl/loadmsgcat.c b/gettext-runtime/intl/loadmsgcat.c index a2d279928..26d0b87b1 100644 --- a/gettext-runtime/intl/loadmsgcat.c +++ b/gettext-runtime/intl/loadmsgcat.c @@ -92,6 +92,11 @@ char *alloca (); #ifdef _LIBC # include "../locale/localeinfo.h" # include +# include +#else +# define __libc_lock_define_initialized_recursive(CLASS, NAME) +# define __libc_lock_lock_recursive(NAME) +# define __libc_lock_unlock_recursive(NAME) #endif /* Provide fallback values for macros that ought to be defined in . @@ -773,7 +778,8 @@ internal_function _nl_load_domain (struct loaded_l10nfile *domain_file, struct binding *domainbinding) { - int fd; + __libc_lock_define_initialized_recursive (static, lock); + int fd = -1; size_t size; #ifdef _LIBC struct stat64 st; @@ -787,7 +793,22 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, const char *nullentry; size_t nullentrylen; - domain_file->decided = 1; + __libc_lock_lock_recursive (lock); + if (domain_file->decided != 0) + { + /* There are two possibilities: + + + this is the same thread calling again during this initialization + via _nl_find_msg. We have initialized everything this call needs. + + + this is another thread which tried to initialize this object. + Not necessary anymore since if the lock is available this + is finished. + */ + goto done; + } + + domain_file->decided = -1; domain_file->data = NULL; /* Note that it would be useless to store domainbinding in domain_file @@ -799,12 +820,12 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, specification the locale file name is different for XPG and CEN syntax. */ if (domain_file->filename == NULL) - return; + goto out; /* Try to open the addressed file. */ fd = open (domain_file->filename, O_RDONLY | O_BINARY); if (fd == -1) - return; + goto out; /* We must know about the size of the file. */ if ( @@ -815,11 +836,8 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, #endif || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0) || __builtin_expect (size < sizeof (struct mo_file_header), 0)) - { - /* Something went wrong. */ - close (fd); - return; - } + /* Something went wrong. */ + goto out; #ifdef HAVE_MMAP /* Now we are ready to load the file. If mmap() is available we try @@ -831,6 +849,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, { /* mmap() call was successful. */ close (fd); + fd = -1; use_mmap = 1; } #endif @@ -844,7 +863,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, data = (struct mo_file_header *) malloc (size); if (data == NULL) - return; + goto out; to_read = size; read_ptr = (char *) data; @@ -857,8 +876,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, if (nb == -1 && errno == EINTR) continue; #endif - close (fd); - return; + goto out; } read_ptr += nb; to_read -= nb; @@ -866,6 +884,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, while (to_read > 0); close (fd); + fd = -1; } /* Using the magic number we can test whether it really is a message @@ -880,12 +899,12 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, else #endif free (data); - return; + goto out; } domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain)); if (domain == NULL) - return; + goto out; domain_file->data = domain; domain->data = (char *) data; @@ -1247,7 +1266,7 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, free (data); free (domain); domain_file->data = NULL; - return; + goto out; } /* No caches of converted translations so far. */ @@ -1257,6 +1276,15 @@ _nl_load_domain (struct loaded_l10nfile *domain_file, /* Get the header entry and look for a plural specification. */ nullentry = _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen); EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals); + + out: + if (fd != -1) + close (fd); + + domain_file->decided = 1; + + done: + __libc_lock_unlock_recursive (lock); }