about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog40
-rw-r--r--elf/dl-load.c22
-rw-r--r--elf/dl-minimal.c21
-rw-r--r--elf/dl-misc.c4
-rw-r--r--elf/dl-object.c7
-rw-r--r--elf/dl-open.c1
-rw-r--r--elf/dl-profile.c21
-rw-r--r--elf/dl-reloc.c6
-rw-r--r--elf/dl-version.c8
-rw-r--r--elf/rtld.c20
-rw-r--r--stdio-common/_itoa.c23
-rw-r--r--stdio-common/_itoa.h9
-rw-r--r--sysdeps/generic/dl-sysdep.c4
-rw-r--r--sysdeps/posix/readv.c2
-rw-r--r--sysdeps/posix/writev.c45
15 files changed, 164 insertions, 69 deletions
diff --git a/ChangeLog b/ChangeLog
index 994fe8f30c..95d7090879 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,12 +1,48 @@
+2002-02-03  Andreas Schwab  <schwab@suse.de>
+
+	* sysdeps/posix/readv.c: Use ssize_t for bytes_read.
+	* sysdeps/posix/writev.c: Use ssize_t for bytes_written.  Fix comment.
+
+2002-02-03  Thorsten Kukuk  <kukuk@suse.de>
+
+	* sysdeps/posix/writev.c: Check for ssize_t overflow, don't use
+	alloca if the memory reqirements are too high.
+
+2002-02-03  Ulrich Drepper  <drepper@redhat.com>
+
+	* elf/dl-load.c (decompose_rpath): Avoid using strstr.
+	* elf/dl-minimal.c (_strerror_r): Use _itoa instead of _itoa_word since
+	the former is available anyway and speed isn't important here.
+	* elf/dl-misc.c (_dl_debug_vdprintf): Likewise.
+	* elf/dl-version.c (match_symbol): Likewise.
+	(_dl_check_map_versions): Likewise.
+	* elf/rtld.c (process_envvars): Likewise.
+	(print_statistics): Likewise.
+	* sysdeps/generic/dl-sysdep.c (_dl_show_auxv): Likewise.
+	* elf/dl-minimal.c (_itoa): Always define it.  Make it work for all
+	bases.  Add assert to catch uses of unimplemented features.
+	(__strsep): Add assert to catch uses of unimplemented features.
+	* elf/dl-object.c (_dl_new_object): Don't use rawmemchr.  Use strchr
+	and avoid inline optimization.
+	* elf/rtld.c (process_envvars): Likewise.
+	* elf/dl-open.c: Don't include <stdio-common/_itoa.h>.
+	* elf/dl-profile.c (_dl_start_profile): Help compiler to avoid ffs.
+	* elf/rtld.c (dl_main): Avoid strsep inline optimization.
+
 2002-02-02  Ulrich Drepper  <drepper@redhat.com>
 
+	* stdio-common/_itoa.h: Minor simplifications of the code.
+	* stdio-common/_itoa.c: Likewise.
+
+	* elf/dl-reloc.c (_dl_relocate_object): Use _dl_debug_printf
+	instead of _dl_printf for debugging info output.
+
 	* manual/examples/mkfsock.c (make_named_socket): Make sure name is
 	always NUL-terminated.  Patch by Chris D. Sloan <cds@cs.hmc.edu>.
 
 2002-02-01  H.J. Lu  <hjl@gnu.org>
 
-	* sysdeps/mips/atomicity.h (exchange_and_add): Use branch
-	likely.
+	* sysdeps/mips/atomicity.h (exchange_and_add): Use branch likely.
 	(atomic_add): Likewise.
 	(compare_and_swap): Return 0 only when failed to compare. Use
 	branch likely.
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 574d4dad4e..cf64ebcc1e 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -496,12 +496,19 @@ decompose_rpath (struct r_search_path_struct *sps,
   if (__builtin_expect (GL(dl_inhibit_rpath) != NULL, 0)
       && !__libc_enable_secure)
     {
-      const char *found = strstr (GL(dl_inhibit_rpath), where);
-      if (found != NULL)
+      const char *inhp = GL(dl_inhibit_rpath);
+
+      do
 	{
-	  size_t len = strlen (where);
-	  if ((found == GL(dl_inhibit_rpath) || found[-1] == ':')
-	      && (found[len] == '\0' || found[len] == ':'))
+	  const char *wp = where;
+
+	  while (*inhp == *wp && *wp != '\0')
+	    {
+	      ++inhp;
+	      ++wp;
+	    }
+
+	  if (*wp == '\0' && (*inhp == '\0' || *inhp == ':'))
 	    {
 	      /* This object is on the list of objects for which the
 		 RUNPATH and RPATH must not be used.  */
@@ -522,7 +529,12 @@ decompose_rpath (struct r_search_path_struct *sps,
 
 	      return;
 	    }
+
+	  while (*inhp != '\0')
+	    if (*inhp++ == ':')
+	      break;
 	}
+      while (*inhp != '\0');
     }
 
   /* Make a writable copy.  At the same time expand possible dynamic
diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c
index efdc26dc62..cd899bfd74 100644
--- a/elf/dl-minimal.c
+++ b/elf/dl-minimal.c
@@ -171,7 +171,7 @@ __strerror_r (int errnum, char *buf, size_t buflen)
       /* No need to check buffer size, all calls in the dynamic linker
 	 provide enough space.  */
       buf[buflen - 1] = '\0';
-      msg = _itoa_word (errnum, buf + buflen - 1, 10, 0);
+      msg = _itoa (errnum, buf + buflen - 1, 10, 0);
       msg = memcpy (msg - (sizeof ("Error ") - 1), "Error ",
 		    sizeof ("Error ") - 1);
       break;
@@ -270,9 +270,9 @@ __strtoul_internal (const char *nptr, char **endptr, int base, int group)
 }
 
 
-#if HP_TIMING_AVAIL && ULONG_MAX <= 4294967295UL
-/* We need this function to print the cycle count.  On 64-bit machines the
-   _itoa_word function should be used.  */
+/* We always use _itoa instead of _itoa_word in ld.so since the former
+   also has to be present and it is never about speed when these
+   functions are used.  */
 char *
 _itoa (value, buflim, base, upper_case)
      unsigned long long int value;
@@ -280,17 +280,16 @@ _itoa (value, buflim, base, upper_case)
      unsigned int base;
      int upper_case;
 {
-  char *bp = buflim;
+  extern const char _itoa_lower_digits[];
 
-  assert (base == 10);
+  assert (! upper_case);
 
   do
-    *--bp = '0' + value % 10;
-  while ((value /= 10) != 0);
+    *--buflim = _itoa_lower_digits[value % base];
+  while ((value /= base) != 0);
 
-  return bp;
+  return buflim;
 }
-#endif
 
 
 /* The following is not a complete strsep implementation.  It cannot
@@ -303,6 +302,8 @@ __strsep (char **stringp, const char *delim)
 {
   char *begin;
 
+  assert (delim[0] != '\0');
+
   begin = *stringp;
   if (begin != NULL)
     {
diff --git a/elf/dl-misc.c b/elf/dl-misc.c
index 0a37b59ad7..ab883acb3c 100644
--- a/elf/dl-misc.c
+++ b/elf/dl-misc.c
@@ -105,7 +105,7 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
 	      char *p;
 	      pid = __getpid ();
 	      assert (pid >= 0 && pid < 100000);
-	      p = _itoa_word (pid, &pidbuf[5], 10, 0);
+	      p = _itoa (pid, &pidbuf[5], 10, 0);
 	      while (p > pidbuf)
 		*--p = '0';
 	      pidbuf[5] = ':';
@@ -185,7 +185,7 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
 		   having more than one integer formatting in a call.  */
 		char *buf = (char *) alloca (3 * sizeof (unsigned long int));
 		char *endp = &buf[3 * sizeof (unsigned long int)];
-		char *cp = _itoa_word (num, endp, *fmt == 'x' ? 16 : 10, 0);
+		char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0);
 
 		/* Pad to the width the user specified.  */
 		if (width != -1)
diff --git a/elf/dl-object.c b/elf/dl-object.c
index 398628aa1b..6196cd7329 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -142,9 +142,10 @@ _dl_new_object (char *realname, const char *libname, int type,
 	      goto out;
 	    }
 
-	  /* Find the end of the path and see whether we have to add
-	     a slash.  */
-	  cp = __rawmemchr (origin, '\0');
+	  /* Find the end of the path and see whether we have to add a
+	     slash.  We could use rawmemchr but this need not be
+	     fast.  */
+	  cp = (strchr) (origin, '\0');
 	  if (cp[-1] != '/')
 	    *cp++ = '/';
 	}
diff --git a/elf/dl-open.c b/elf/dl-open.c
index e5f7ac835b..253f7b93dc 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -31,7 +31,6 @@
 #include <bp-sym.h>
 
 #include <dl-dst.h>
-#include <stdio-common/_itoa.h>
 
 
 extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
diff --git a/elf/dl-profile.c b/elf/dl-profile.c
index 83e849561a..19d1865c25 100644
--- a/elf/dl-profile.c
+++ b/elf/dl-profile.c
@@ -19,6 +19,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -217,9 +218,23 @@ _dl_start_profile (struct link_map *map, const char *output_dir)
   kcountsize = textsize / HISTFRACTION;
   hashfraction = HASHFRACTION;
   if ((HASHFRACTION & (HASHFRACTION - 1)) == 0)
-    /* If HASHFRACTION is a power of two, mcount can use shifting
-       instead of integer division.  Precompute shift amount.  */
-    log_hashfraction = __ffs (hashfraction * sizeof (*froms)) - 1;
+    {
+      /* If HASHFRACTION is a power of two, mcount can use shifting
+	 instead of integer division.  Precompute shift amount.
+
+	 This is a constant but the compiler cannot compile the
+	 expression away since the __ffs implementation is not known
+	 to the compiler.  Help the compiler by precomputing the
+	 usual cases.  */
+      assert (hashfraction == 2);
+
+      if (sizeof (*froms) == 8)
+	log_hashfraction = 4;
+      else if (sizeof (*froms) == 16)
+	log_hashfraction = 5;
+      else
+	log_hashfraction = __ffs (hashfraction * sizeof (*froms)) - 1;
+    }
   else
     log_hashfraction = -1;
   tossize = textsize / HASHFRACTION;
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 67a47aa14a..1c0c18d089 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -59,9 +59,9 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
     lazy = 0;
 
   if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_RELOC, 0))
-    _dl_printf ("\nrelocation processing: %s%s\n",
-		l->l_name[0] ? l->l_name : _dl_argv[0],
-		lazy ? " (lazy)" : "");
+    INT(_dl_debug_printf) ("\nrelocation processing: %s%s\n",
+			   l->l_name[0] ? l->l_name : _dl_argv[0],
+			   lazy ? " (lazy)" : "");
 
   /* DT_TEXTREL is now in level 2 and might phase out at some time.
      But we rewrite the DT_FLAGS entry to a DT_TEXTREL entry to make
diff --git a/elf/dl-version.c b/elf/dl-version.c
index 9ba91b2efe..f9fd3ba55d 100644
--- a/elf/dl-version.c
+++ b/elf/dl-version.c
@@ -121,8 +121,8 @@ no version information available (required by ", name, ")");
 	  buf[sizeof (buf) - 1] = '\0';
 	  /* XXX We cannot translate the message.  */
 	  errstring = make_string ("unsupported version ",
-				   _itoa_word (def->vd_version,
-					       &buf[sizeof (buf) - 1], 10, 0),
+				   _itoa (def->vd_version,
+					  &buf[sizeof (buf) - 1], 10, 0),
 				   " of Verdef record");
 	  result = 1;
 	  goto call_cerror;
@@ -210,8 +210,8 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
 	  buf[sizeof (buf) - 1] = '\0';
 	  /* XXX We cannot translate the message.  */
 	  errstring = make_string ("unsupported version ",
-				   _itoa_word (ent->vn_version,
-					       &buf[sizeof (buf) - 1], 10, 0),
+				   _itoa (ent->vn_version,
+					  &buf[sizeof (buf) - 1], 10, 0),
 				   " of Verneed record\n");
 	call_error:
 	  INT(_dl_signal_error) (errval, (*map->l_name
diff --git a/elf/rtld.c b/elf/rtld.c
index 4dd288b072..b49d110267 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -697,7 +697,8 @@ of this helper program; chances are you did not intend to run this program.\n\
 
       HP_TIMING_NOW (start);
 
-      while ((p = strsep (&list, " :")) != NULL)
+      /* Prevent optimizing strsep.  Speed is not important here.  */
+      while ((p = (strsep) (&list, " :")) != NULL)
 	if (p[0] != '\0'
 	    && (__builtin_expect (! __libc_enable_secure, 1)
 		|| strchr (p, '/') == NULL))
@@ -1063,8 +1064,8 @@ of this helper program; chances are you did not intend to run this program.\n\
     {
       ElfW(Lib) *liblist, *liblistend;
       struct link_map **r_list, **r_listend, *l;
-      const char *strtab = (const void *)
-			   D_PTR (GL(dl_loaded), l_info[DT_STRTAB]);
+      const char *strtab = (const void *) D_PTR (GL(dl_loaded),
+						 l_info[DT_STRTAB]);
 
       assert (GL(dl_loaded)->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL);
       liblist = (ElfW(Lib) *)
@@ -1550,7 +1551,8 @@ process_envvars (enum mode *modep)
       do
 	{
 	  unsetenv (nextp);
-	  nextp = (char *) rawmemchr (nextp, '\0') + 1;
+	  /* We could use rawmemchr but this need not be fast.  */
+	  nextp = (char *) (strchr) (nextp, '\0') + 1;
 	}
       while (*nextp != '\0');
 
@@ -1572,7 +1574,7 @@ process_envvars (enum mode *modep)
       char *startp;
 
       buf[name_len + 11] = '\0';
-      startp = _itoa_word (__getpid (), &buf[name_len + 11], 10, 0);
+      startp = _itoa (__getpid (), &buf[name_len + 11], 10, 0);
       *--startp = '.';
       startp = memcpy (startp - name_len, debug_output, name_len);
 
@@ -1607,8 +1609,8 @@ print_statistics (void)
     {
       char pbuf[30];
       HP_TIMING_PRINT (buf, sizeof (buf), relocate_time);
-      cp = _itoa_word ((1000ULL * relocate_time) / rtld_total_time,
-		       pbuf + sizeof (pbuf), 10, 0);
+      cp = _itoa ((1000ULL * relocate_time) / rtld_total_time,
+		  pbuf + sizeof (pbuf), 10, 0);
       wp = pbuf;
       switch (pbuf + sizeof (pbuf) - cp)
 	{
@@ -1637,8 +1639,8 @@ print_statistics (void)
     {
       char pbuf[30];
       HP_TIMING_PRINT (buf, sizeof (buf), load_time);
-      cp = _itoa_word ((1000ULL * load_time) / rtld_total_time,
-		       pbuf + sizeof (pbuf), 10, 0);
+      cp = _itoa ((1000ULL * load_time) / rtld_total_time,
+		  pbuf + sizeof (pbuf), 10, 0);
       wp = pbuf;
       switch (pbuf + sizeof (pbuf) - cp)
 	{
diff --git a/stdio-common/_itoa.c b/stdio-common/_itoa.c
index 1c29df62de..e36cd520f7 100644
--- a/stdio-common/_itoa.c
+++ b/stdio-common/_itoa.c
@@ -1,5 +1,5 @@
 /* Internal function for converting integers to ASCII.
-   Copyright (C) 1994, 1995, 1996, 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1994,1995,1996,1999,2000,2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Torbjorn Granlund <tege@matematik.su.se>
    and Ulrich Drepper <drepper@gnu.org>.
@@ -170,7 +170,6 @@ _itoa (value, buflim, base, upper_case)
      int upper_case;
 {
   const char *digits = upper_case ? _itoa_upper_digits : _itoa_lower_digits;
-  char *bp = buflim;
   const struct base_table_t *brec = &_itoa_base_table[base - 2];
 
   switch (base)
@@ -191,7 +190,7 @@ _itoa (value, buflim, base, upper_case)
 		  work_lo = value & 0xfffffffful;			      \
 		  for (cnt = BITS_PER_MP_LIMB / BITS; cnt > 0; --cnt)	      \
 		    {							      \
-		      *--bp = digits[work_lo & ((1ul << BITS) - 1)];	      \
+		      *--buflim = digits[work_lo & ((1ul << BITS) - 1)];      \
 		      work_lo >>= BITS;					      \
 		    }							      \
 		  if (BITS_PER_MP_LIMB % BITS != 0)			      \
@@ -205,7 +204,7 @@ _itoa (value, buflim, base, upper_case)
 		      if (work_hi == 0)					      \
 			work_hi = work_lo;				      \
 		      else						      \
-			*--bp = digits[work_lo];			      \
+			*--buflim = digits[work_lo];			      \
 		    }							      \
 		}							      \
 	      else							      \
@@ -213,7 +212,7 @@ _itoa (value, buflim, base, upper_case)
 	    }								      \
 	  do								      \
 	    {								      \
-	      *--bp = digits[work_hi & ((1 << BITS) - 1)];		      \
+	      *--buflim = digits[work_hi & ((1 << BITS) - 1)];		      \
 	      work_hi >>= BITS;						      \
 	    }								      \
 	  while (work_hi != 0);						      \
@@ -239,7 +238,7 @@ _itoa (value, buflim, base, upper_case)
 	      umul_ppmm (x, dummy, value, base_multiplier);
 	      quo = (x + ((value - x) >> 1)) >> (brec->post_shift - 1);
 	      rem = value - quo * base;
-	      *--bp = digits[rem];
+	      *--buflim = digits[rem];
 	      value = quo;
 	    }
 	else
@@ -250,7 +249,7 @@ _itoa (value, buflim, base, upper_case)
 	      umul_ppmm (x, dummy, value, base_multiplier);
 	      quo = x >> brec->post_shift;
 	      rem = value - quo * base;
-	      *--bp = digits[rem];
+	      *--buflim = digits[rem];
 	      value = quo;
 	    }
 #endif
@@ -376,7 +375,7 @@ _itoa (value, buflim, base, upper_case)
 		  umul_ppmm (x, dummy, ti, base_multiplier);
 		  quo = (x + ((ti - x) >> 1)) >> (brec->post_shift - 1);
 		  rem = ti - quo * base;
-		  *--bp = digits[rem];
+		  *--buflim = digits[rem];
 		  ti = quo;
 		  ++ndig_for_this_limb;
 		}
@@ -388,7 +387,7 @@ _itoa (value, buflim, base, upper_case)
 		  umul_ppmm (x, dummy, ti, base_multiplier);
 		  quo = x >> brec->post_shift;
 		  rem = ti - quo * base;
-		  *--bp = digits[rem];
+		  *--buflim = digits[rem];
 		  ti = quo;
 		  ++ndig_for_this_limb;
 		}
@@ -399,7 +398,7 @@ _itoa (value, buflim, base, upper_case)
 
 		quo = ti / base;
 		rem = ti % base;
-		*--bp = digits[rem];
+		*--buflim = digits[rem];
 		ti = quo;
 		++ndig_for_this_limb;
 	      }
@@ -408,7 +407,7 @@ _itoa (value, buflim, base, upper_case)
 	    if (n != 0)
 	      while (ndig_for_this_limb < brec->big.ndigits)
 		{
-		  *--bp = '0';
+		  *--buflim = '0';
 		  ++ndig_for_this_limb;
 		}
 	  }
@@ -418,5 +417,5 @@ _itoa (value, buflim, base, upper_case)
       break;
     }
 
-  return bp;
+  return buflim;
 }
diff --git a/stdio-common/_itoa.h b/stdio-common/_itoa.h
index 6fbfdde7c2..18f98dcd71 100644
--- a/stdio-common/_itoa.h
+++ b/stdio-common/_itoa.h
@@ -1,5 +1,5 @@
 /* Internal function for converting integers to ASCII.
-   Copyright (C) 1994, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
+   Copyright (C) 1994, 95, 96, 97, 98, 99, 2002 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
@@ -35,14 +35,13 @@ _itoa_word (unsigned long value, char *buflim,
 {
   extern const char _itoa_upper_digits[], _itoa_lower_digits[];
   const char *digits = upper_case ? _itoa_upper_digits : _itoa_lower_digits;
-  char *bp = buflim;
 
   switch (base)
     {
 #define SPECIAL(Base)							      \
     case Base:								      \
       do								      \
-	*--bp = digits[value % Base];					      \
+	*--buflim = digits[value % Base];				      \
       while ((value /= Base) != 0);					      \
       break
 
@@ -51,10 +50,10 @@ _itoa_word (unsigned long value, char *buflim,
       SPECIAL (8);
     default:
       do
-	*--bp = digits[value % base];
+	*--buflim = digits[value % base];
       while ((value /= base) != 0);
     }
-  return bp;
+  return buflim;
 }
 
 static inline char * __attribute__ ((unused))
diff --git a/sysdeps/generic/dl-sysdep.c b/sysdeps/generic/dl-sysdep.c
index 0fb40cb744..79816eeb8c 100644
--- a/sysdeps/generic/dl-sysdep.c
+++ b/sysdeps/generic/dl-sysdep.c
@@ -258,9 +258,9 @@ _dl_show_auxv (void)
 	      const char *val = av->a_un.a_ptr;
 
 	      if (__builtin_expect (auxvars[idx].form, dec) == dec)
-		val = _itoa_word (av->a_un.a_val, buf + sizeof buf - 1, 10, 0);
+		val = _itoa (av->a_un.a_val, buf + sizeof buf - 1, 10, 0);
 	      else if (__builtin_expect (auxvars[idx].form, hex) == hex)
-		val = _itoa_word (av->a_un.a_val, buf + sizeof buf - 1, 16, 0);
+		val = _itoa (av->a_un.a_val, buf + sizeof buf - 1, 16, 0);
 
 	      _dl_printf ("%s%s\n", auxvars[idx].label, val);
 	    }
diff --git a/sysdeps/posix/readv.c b/sysdeps/posix/readv.c
index 89fe1af7d3..988ede5f51 100644
--- a/sysdeps/posix/readv.c
+++ b/sysdeps/posix/readv.c
@@ -38,7 +38,7 @@ __readv (fd, vector, count)
   char *buffer;
   char *buffer_start;
   size_t bytes;
-  int bytes_read;
+  ssize_t bytes_read;
   int i;
   bool use_malloc = false;
 
diff --git a/sysdeps/posix/writev.c b/sysdeps/posix/writev.c
index f92ff1c19d..dc2c806d66 100644
--- a/sysdeps/posix/writev.c
+++ b/sysdeps/posix/writev.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1996, 1997, 2002 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
@@ -19,6 +19,9 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <sys/param.h>
 #include <sys/uio.h>
 
 /* Write data pointed by the buffers described by VECTOR, which
@@ -35,23 +38,46 @@ __writev (fd, vector, count)
   char *buffer;
   register char *bp;
   size_t bytes, to_copy;
+  ssize_t bytes_written;
   int i;
+  bool use_malloc = false;
 
   /* Find the total number of bytes to be written.  */
   bytes = 0;
   for (i = 0; i < count; ++i)
-    bytes += vector[i].iov_len;
+    {
+      /* Check for ssize_t overflow.  */
+      if (SSIZE_MAX - bytes < vector[i].iov_len)
+	{
+	  errno = EINVAL;
+	  return -1;
+	}
+      bytes += vector[i].iov_len;
+    }
 
-  /* Allocate a temporary buffer to hold the data.  */
-  buffer = (char *) __alloca (bytes);
+  /* Allocate a temporary buffer to hold the data.  We should normally
+     use alloca since it's faster and does not require synchronization
+     with other threads.  But we cannot if the amount of memory
+     required is too large.  Use 512k as the limit.  */
+  if (bytes < 512 * 1024)
+    buffer = (char *) __alloca (bytes);
+  else
+    {
+      buffer = (char *) malloc (bytes);
+      if (buffer == NULL)
+	/* XXX I don't know whether it is acceptable to try writing
+	   the data in chunks.  Probably not so we just fail here.  */
+	return -1;
+
+      use_malloc = true;
+    }
 
   /* Copy the data into BUFFER.  */
   to_copy = bytes;
   bp = buffer;
   for (i = 0; i < count; ++i)
     {
-#define	min(a, b)	((a) > (b) ? (b) : (a))
-      size_t copy = min (vector[i].iov_len, to_copy);
+      size_t copy = MIN (vector[i].iov_len, to_copy);
 
       bp = __mempcpy ((void *) bp, (void *) vector[i].iov_base, copy);
 
@@ -60,7 +86,12 @@ __writev (fd, vector, count)
 	break;
     }
 
-  return __write (fd, buffer, bytes);
+  bytes_written = __write (fd, buffer, bytes);
+
+  if (use_malloc)
+    free (buffer);
+
+  return bytes_written;
 }
 #ifndef __writev
 weak_alias (__writev, writev)