summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rw-r--r--intl/dcigettext.c17
-rw-r--r--intl/finddomain.c21
-rw-r--r--intl/l10nflist.c6
-rw-r--r--intl/loadinfo.h5
-rw-r--r--intl/loadmsgcat.c67
-rw-r--r--sysdeps/posix/getaddrinfo.c36
7 files changed, 121 insertions, 48 deletions
diff --git a/ChangeLog b/ChangeLog
index 779d045778..dcbab5ec5c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2004-09-25 Ulrich Drepper <drepper@redhat.com>
+
+ * intl/dcigettext.c (DCIGETTEXT): Protect tfind/tsearch calls.
+ * intl/dcigettext.c (_nl_find_msg): Call _nl_load_domain also if
+ decided < 0.
+ * intl/finddomain.c (_nl_find_domain): Likewise.
+ * intl/l10nflist.c (_nl_make_l10nflist): Initialize lock.
+ * intl/loadinfo.h (struct loaded_l10nfile): Add lock element.
+ * intl/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.
+ * intl/finddomain.c (_nl_find_domain): Protect calls to
+ _nl_make_l10nflist.
+ * sysdeps/posix/getaddrinfo.c (getaddrinfo): If determinination of
+ source address fails, initialized source_addr_len field so that
+ duplicate address recognition does not copy junk. [BZ #322]
+
2004-09-25 Jakub Jelinek <jakub@redhat.com>
* sysdeps/unix/sysv/linux/i386/setuid.c (__setuid): Remove second
diff --git a/intl/dcigettext.c b/intl/dcigettext.c
index fa53b7c574..d7111729b9 100644
--- a/intl/dcigettext.c
+++ b/intl/dcigettext.c
@@ -1,5 +1,5 @@
/* Implementation of the internal dcigettext function.
- Copyright (C) 1995-2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1995-2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -439,7 +439,15 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
search->domainname = (char *) domainname;
search->category = category;
+ /* 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)
{
@@ -633,9 +641,14 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
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. */
@@ -680,7 +693,7 @@ _nl_find_msg (domain_file, domainbinding, msgid, lengthp)
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/intl/finddomain.c b/intl/finddomain.c
index 6988d9efc0..39e54755d2 100644
--- a/intl/finddomain.c
+++ b/intl/finddomain.c
@@ -35,6 +35,7 @@
#include "gettextP.h"
#ifdef _LIBC
# include <libintl.h>
+# include <bits/libc-lock.h>
#else
# include "libgnuintl.h"
#endif
@@ -78,17 +79,23 @@ _nl_find_domain (dirname, locale, domainname, domainbinding)
(4) 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, 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)
@@ -96,12 +103,13 @@ _nl_find_domain (dirname, locale, domainname, domainbinding)
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 */
}
@@ -132,24 +140,29 @@ _nl_find_domain (dirname, locale, domainname, domainbinding)
mask = _nl_explode_name (locale, &language, &modifier, &territory,
&codeset, &normalized_codeset);
+ /* 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,
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/intl/l10nflist.c b/intl/l10nflist.c
index 31760bdaaa..5a366e59fb 100644
--- a/intl/l10nflist.c
+++ b/intl/l10nflist.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 1995-2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
@@ -273,10 +273,14 @@ _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
return NULL;
retval->filename = abs_filename;
+ /* If more than one directory is in the list this is a pseudo-entry
+ which just references others. We do not try to load data for it,
+ ever. */
retval->decided = (__argz_count (dirlist, dirlist_len) != 1
|| ((mask & XPG_CODESET) != 0
&& (mask & XPG_NORM_CODESET) != 0));
retval->data = NULL;
+ __libc_lock_init_recursive (retval->lock);
if (last == NULL)
{
diff --git a/intl/loadinfo.h b/intl/loadinfo.h
index c2b6971b36..913022eb7b 100644
--- a/intl/loadinfo.h
+++ b/intl/loadinfo.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2000, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2000, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
@@ -20,6 +20,8 @@
#ifndef _LOADINFO_H
#define _LOADINFO_H 1
+#include <bits/libc-lock.h>
+
/* Declarations of locale dependent catalog lookup functions.
Implemented in
@@ -61,6 +63,7 @@ struct loaded_l10nfile
{
const char *filename;
int decided;
+ __libc_lock_define_recursive (, lock);
const void *data;
diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c
index 569ace2105..ec886d9bd7 100644
--- a/intl/loadmsgcat.c
+++ b/intl/loadmsgcat.c
@@ -899,7 +899,7 @@ _nl_load_domain (domain_file, domainbinding)
struct loaded_l10nfile *domain_file;
struct binding *domainbinding;
{
- int fd;
+ int fd = -1;
size_t size;
#ifdef _LIBC
struct stat64 st;
@@ -912,7 +912,24 @@ _nl_load_domain (domain_file, domainbinding)
int revision;
const char *nullentry;
- domain_file->decided = 1;
+ __libc_lock_lock_recursive (domain_file->lock);
+ if (domain_file->decided != 0)
+ {
+ /* There are two possibilities:
+
+ + is is the same thread calling again during this
+ initialization via _nl_init_domain_conv and _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.
+ */
+ __libc_lock_unlock_recursive (domain_file->lock);
+ return;
+ }
+
+ domain_file->decided = -1;
domain_file->data = NULL;
/* Note that it would be useless to store domainbinding in domain_file
@@ -924,12 +941,12 @@ _nl_load_domain (domain_file, domainbinding)
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);
if (fd == -1)
- return;
+ goto out;
/* We must know about the size of the file. */
if (
@@ -940,11 +957,8 @@ _nl_load_domain (domain_file, domainbinding)
#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
@@ -952,45 +966,42 @@ _nl_load_domain (domain_file, domainbinding)
data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
MAP_PRIVATE, fd, 0);
- if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
+ if (__builtin_expect (data != MAP_FAILED, 1))
{
/* mmap() call was successful. */
close (fd);
+ fd = -1;
use_mmap = 1;
}
#endif
/* If the data is not yet available (i.e. mmap'ed) we try to load
it manually. */
- if (data == (struct mo_file_header *) -1)
+ if (data == MAP_FAILED)
{
size_t to_read;
char *read_ptr;
data = (struct mo_file_header *) malloc (size);
if (data == NULL)
- return;
+ goto out;
to_read = size;
read_ptr = (char *) data;
do
{
- long int nb = (long int) read (fd, read_ptr, to_read);
+ long int nb = (long int) TEMP_FAILURE_RETRY (read (fd, read_ptr,
+ to_read));
if (nb <= 0)
- {
-#ifdef EINTR
- if (nb == -1 && errno == EINTR)
- continue;
-#endif
- close (fd);
- return;
- }
+ goto out;
+
read_ptr += nb;
to_read -= nb;
}
while (to_read > 0);
close (fd);
+ fd = -1;
}
/* Using the magic number we can test whether it really is a message
@@ -1005,12 +1016,12 @@ _nl_load_domain (domain_file, domainbinding)
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;
@@ -1372,7 +1383,7 @@ _nl_load_domain (domain_file, domainbinding)
free (data);
free (domain);
domain_file->data = NULL;
- return;
+ goto out;
}
/* Now initialize the character set converter from the character set
@@ -1382,6 +1393,14 @@ _nl_load_domain (domain_file, domainbinding)
/* Also look for a plural specification. */
EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
+
+ out:
+ if (fd != -1)
+ close (fd);
+
+ domain_file->decided = 1;
+
+ __libc_lock_unlock_recursive (domain_file->lock);
}
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index b3f9f4f9b0..225c1a1088 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -1561,10 +1561,7 @@ getaddrinfo (const char *name, const char *service,
results[i].dest_addr = q;
results[i].got_source_addr = false;
- /* We overwrite the type with SOCK_DGRAM since we do not
- want connect() to connect to the other side. If we
- cannot determine the source address remember this
- fact. If we just looked up the address for a different
+ /* If we just looked up the address for a different
protocol, reuse the result. */
if (last != NULL && last->ai_addrlen == q->ai_addrlen
&& memcmp (last->ai_addr, q->ai_addr, q->ai_addrlen) == 0)
@@ -1576,21 +1573,28 @@ getaddrinfo (const char *name, const char *service,
}
else
{
+ /* We overwrite the type with SOCK_DGRAM since we do not
+ want connect() to connect to the other side. If we
+ cannot determine the source address remember this
+ fact. */
int fd = __socket (q->ai_family, SOCK_DGRAM, IPPROTO_IP);
- if (fd != -1)
+ socklen_t sl = sizeof (results[i].source_addr);
+ if (fd != -1
+ && __connect (fd, q->ai_addr, q->ai_addrlen) == 0
+ && __getsockname (fd,
+ (struct sockaddr *) &results[i].source_addr,
+ &sl) == 0)
{
- socklen_t sl = sizeof (results[i].source_addr);
- if (__connect (fd, q->ai_addr, q->ai_addrlen) == 0
- && __getsockname (fd,
- (struct sockaddr *) &results[i].source_addr,
- &sl) == 0)
- {
- results[i].source_addr_len = sl;
- results[i].got_source_addr = true;
- }
-
- close_not_cancel_no_status (fd);
+ results[i].source_addr_len = sl;
+ results[i].got_source_addr = true;
}
+ else
+ /* Just make sure that if we have to process the same
+ address again we do not copy any memory. */
+ results[i].source_addr_len = 0;
+
+ if (fd != -1)
+ close_not_cancel_no_status (fd);
}
/* Remember the canonical name. */