changeset 839:34cb1d196d2b HEAD

String function cleanups. Allocating 0 bytes of memory is treated as error now, it could be an integer overflow. Moved printf_string_upper_bound() to it's own file, so strfuncs.c can be with MIT license.
author Timo Sirainen <tss@iki.fi>
date Sun, 22 Dec 2002 09:06:16 +0200
parents a6cd073c5283
children 481a678ba019
files COPYING src/lib/Makefile.am src/lib/data-stack.c src/lib/failures.c src/lib/imem.c src/lib/imem.h src/lib/mempool-alloconly.c src/lib/mempool-datastack.c src/lib/mempool-system.c src/lib/printf-upper-bound.c src/lib/printf-upper-bound.h src/lib/str.c src/lib/strfuncs.c src/lib/strfuncs.h src/master/settings.c
diffstat 15 files changed, 445 insertions(+), 485 deletions(-) [+]
line wrap: on
line diff
--- a/COPYING	Sun Dec 22 08:28:44 2002 +0200
+++ b/COPYING	Sun Dec 22 09:06:16 2002 +0200
@@ -6,4 +6,4 @@
 src/lib/
   - md5.c : Public Domain
   - base64.c, mkgmtime.c : BSD-like (read it)
-  - hash.c, primes.c, strfuncs.c, tree.c : LGPL v2
+  - hash.c, primes.c, printf-upper-bound.c, tree.c : LGPL v2
--- a/src/lib/Makefile.am	Sun Dec 22 08:28:44 2002 +0200
+++ b/src/lib/Makefile.am	Sun Dec 22 09:06:16 2002 +0200
@@ -36,6 +36,7 @@
 	ostream.c \
 	ostream-file.c \
 	primes.c \
+	printf-upper-bound.c \
 	process-title.c \
 	randgen.c \
 	restrict-access.c \
@@ -82,6 +83,7 @@
 	ostream.h \
 	ostream-internal.h \
 	primes.h \
+	printf-upper-bound.h \
 	process-title.h \
 	randgen.h \
 	restrict-access.h \
--- a/src/lib/data-stack.c	Sun Dec 22 08:28:44 2002 +0200
+++ b/src/lib/data-stack.c	Sun Dec 22 09:06:16 2002 +0200
@@ -202,11 +202,8 @@
 	int warn = FALSE;
 #endif
 
-	if (size == 0)
-		return NULL;
-
-	if (size > MAX_ALLOC_SIZE)
-		i_panic("Trying to allocate too much memory");
+	if (size == 0 || size > SSIZE_T_MAX)
+		i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
 
 	/* reset t_buffer_get() mark - not really needed but makes it easier
 	   to notice if t_malloc() is called between t_buffer_get() and
@@ -278,6 +275,9 @@
 {
 	size_t last_alloc_size;
 
+	if (size == 0 || size > SSIZE_T_MAX)
+		i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
+
 	last_alloc_size = current_frame_block->last_alloc_size[frame_pos];
 
 	/* see if we're trying to grow the memory we allocated last */
--- a/src/lib/failures.c	Sun Dec 22 08:28:44 2002 +0200
+++ b/src/lib/failures.c	Sun Dec 22 09:06:16 2002 +0200
@@ -27,6 +27,7 @@
 #include "lib.h"
 #include "ioloop.h"
 #include "fd-close-on-exec.h"
+#include "printf-upper-bound.h"
 
 #include <stdio.h>
 #include <stdlib.h>
--- a/src/lib/imem.c	Sun Dec 22 08:28:44 2002 +0200
+++ b/src/lib/imem.c	Sun Dec 22 09:06:16 2002 +0200
@@ -78,12 +78,6 @@
         return p_strdup_vprintf(default_pool, format, args);
 }
 
-void i_strdup_replace(char **dest, const char *str)
-{
-	p_free(default_pool, *dest);
-        *dest = p_strdup(default_pool, str);
-}
-
 char *i_strconcat(const char *str1, ...)
 {
 	va_list args;
@@ -93,9 +87,13 @@
 
 	va_start(args, str1);
 
-	temp = temp_strconcat(str1, args, &len);
-        ret = p_malloc(default_pool, len);
-        memcpy(ret, temp, len);
+	temp = _vstrconcat(str1, args, &len);
+	if (temp == NULL)
+		ret = NULL;
+	else {
+		ret = p_malloc(default_pool, len);
+		memcpy(ret, temp, len);
+	}
 
 	va_end(args);
         return ret;
--- a/src/lib/imem.h	Sun Dec 22 08:28:44 2002 +0200
+++ b/src/lib/imem.h	Sun Dec 22 09:06:16 2002 +0200
@@ -17,7 +17,6 @@
 char *i_strndup(const char *str, size_t max_chars);
 char *i_strdup_printf(const char *format, ...) __attr_format__(1, 2);
 char *i_strdup_vprintf(const char *format, va_list args);
-void i_strdup_replace(char **dest, const char *str);
 
 char *i_strconcat(const char *str1, ...); /* NULL terminated */
 
--- a/src/lib/mempool-alloconly.c	Sun Dec 22 08:28:44 2002 +0200
+++ b/src/lib/mempool-alloconly.c	Sun Dec 22 09:06:16 2002 +0200
@@ -168,6 +168,9 @@
 	AlloconlyPool *apool = (AlloconlyPool *) pool;
 	PoolAlloc *alloc;
 
+	if (size == 0 || size > SSIZE_T_MAX)
+		i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
+
 	size = MEM_ALIGN(size);
 
 	if (apool->block->left < size + SIZEOF_POOLALLOC) {
@@ -222,6 +225,9 @@
 	unsigned char *new_mem;
 	size_t old_size;
 
+	if (size == 0 || size > SSIZE_T_MAX)
+		i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
+
 	if (mem == NULL) {
 		alloc = NULL;
 		old_size = 0;
--- a/src/lib/mempool-datastack.c	Sun Dec 22 08:28:44 2002 +0200
+++ b/src/lib/mempool-datastack.c	Sun Dec 22 09:06:16 2002 +0200
@@ -28,8 +28,6 @@
 
 #include <stdlib.h>
 
-#define MAX_ALLOC_SIZE SSIZE_T_MAX
-
 typedef struct {
 	union {
 		size_t size;
@@ -73,8 +71,8 @@
 {
 	PoolAlloc *alloc;
 
-	if (size > MAX_ALLOC_SIZE)
-		i_panic("Trying to allocate too much memory");
+	if (size == 0 || size > SSIZE_T_MAX)
+		i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
 
 	alloc = t_malloc0(sizeof(PoolAlloc) + size);
 	alloc->size.size = size;
@@ -100,6 +98,9 @@
         size_t old_size;
 	unsigned char *rmem;
 
+	if (size == 0 || size > SSIZE_T_MAX)
+		i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
+
 	if (mem == NULL)
 		return pool_data_stack_malloc(pool, size);
 
--- a/src/lib/mempool-system.c	Sun Dec 22 08:28:44 2002 +0200
+++ b/src/lib/mempool-system.c	Sun Dec 22 09:06:16 2002 +0200
@@ -30,8 +30,6 @@
 
 #include <stdlib.h>
 
-#define MAX_ALLOC_SIZE SSIZE_T_MAX
-
 typedef struct {
 	union {
 		size_t size;
@@ -75,8 +73,8 @@
 {
 	PoolAlloc *alloc;
 
-	if (size > MAX_ALLOC_SIZE)
-		i_panic("Trying to allocate too much memory");
+	if (size == 0 || size > SSIZE_T_MAX)
+		i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
 
 	alloc = calloc(sizeof(PoolAlloc) + size, 1);
 	if (alloc == NULL)
@@ -99,6 +97,9 @@
 	size_t old_size;
 	char *rmem;
 
+	if (size == 0 || size > SSIZE_T_MAX)
+		i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
+
 	if (mem == NULL) {
 		alloc = NULL;
 		old_size = 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/printf-upper-bound.c	Sun Dec 22 09:06:16 2002 +0200
@@ -0,0 +1,310 @@
+/*
+    Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+    Modified by the GLib Team and others 1997-1999.
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+  
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+    Library General Public License for more details.
+  
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the
+    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.
+*/
+
+#include "lib.h"
+#include "printf-upper-bound.h"
+
+typedef union  _GDoubleIEEE754  GDoubleIEEE754;
+#define G_IEEE754_DOUBLE_BIAS   (1023)
+/* multiply with base2 exponent to get base10 exponent (nomal numbers) */
+#define G_LOG_2_BASE_10         (0.30102999566398119521)
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+union _GDoubleIEEE754
+{
+  double v_double;
+  struct {
+    unsigned int mantissa_low : 32;
+    unsigned int mantissa_high : 20;
+    unsigned int biased_exponent : 11;
+    unsigned int sign : 1;
+  } mpn;
+};
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+union _GDoubleIEEE754
+{
+  double v_double;
+  struct {
+    unsigned int sign : 1;
+    unsigned int biased_exponent : 11;
+    unsigned int mantissa_high : 20;
+    unsigned int mantissa_low : 32;
+  } mpn;
+};
+#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+#error unknown ENDIAN type
+#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+
+typedef struct
+{
+  unsigned int min_width;
+  unsigned int precision;
+  int alternate_format, zero_padding, adjust_left, locale_grouping;
+  int add_space, add_sign, possible_sign, seen_precision;
+  int mod_long, mod_extra_long;
+} PrintfArgSpec;
+
+#if (SIZEOF_LONG > 4) || (SIZEOF_VOID_P > 4)
+#  define HONOUR_LONGS 1
+#else
+#  define HONOUR_LONGS 0
+#endif
+
+size_t printf_string_upper_bound(const char *format, va_list args)
+{
+  size_t len = 1;
+
+  if (!format)
+    return len;
+
+  while (*format)
+    {
+      register char c = *format++;
+
+      if (c != '%')
+        len += 1;
+      else /* (c == '%') */
+        {
+          PrintfArgSpec spec;
+          int seen_l = FALSE, conv_done = FALSE;
+          unsigned int conv_len = 0;
+
+          memset(&spec, 0, sizeof(spec));
+          do
+            {
+              c = *format++;
+              switch (c)
+                {
+                  GDoubleIEEE754 u_double;
+                  unsigned int v_uint;
+                  int v_int;
+                  const char *v_string;
+
+                  /* beware of positional parameters
+                   */
+                case '$':
+                  i_panic("unable to handle positional parameters (%%n$)");
+                  break;
+
+                  /* parse flags
+                   */
+                case '#':
+                  spec.alternate_format = TRUE;
+                  break;
+                case '0':
+                  spec.zero_padding = TRUE;
+                  break;
+                case '-':
+                  spec.adjust_left = TRUE;
+                  break;
+                case ' ':
+                  spec.add_space = TRUE;
+                  break;
+                case '+':
+                  spec.add_sign = TRUE;
+                  break;
+                case '\'':
+                  spec.locale_grouping = TRUE;
+                  break;
+
+                  /* parse output size specifications
+                   */
+                case '.':
+                  spec.seen_precision = TRUE;
+                  break;
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                  v_uint = c - '0';
+                  c = *format;
+                  while (c >= '0' && c <= '9')
+                    {
+                      format++;
+                      v_uint = v_uint * 10 + (c - '0');
+                      c = *format;
+                    }
+                  if (spec.seen_precision)
+                    spec.precision = I_MAX (spec.precision, v_uint);
+                  else
+                    spec.min_width = I_MAX (spec.min_width, v_uint);
+                  break;
+                case '*':
+                  v_int = va_arg (args, int);
+                  if (spec.seen_precision)
+                    {
+                      /* forget about negative precision */
+                      if (v_int >= 0)
+                        spec.precision = I_MAX ((int)spec.precision, v_int);
+                    }
+                  else
+                    {
+                      if (v_int < 0)
+                        {
+                          v_int = - v_int;
+                          spec.adjust_left = TRUE;
+                        }
+                      spec.min_width = I_MAX ((int)spec.min_width, v_int);
+                    }
+                  break;
+
+                  /* parse type modifiers
+                   */
+                case 'h':
+		  /* ignore */
+                  break;
+                case 'l':
+                  if (!seen_l)
+                    {
+                      spec.mod_long = TRUE;
+                      seen_l = TRUE;
+                      break;
+                    }
+                  /* else, fall through */
+                case 'L':
+                  spec.mod_long = TRUE;
+                  spec.mod_extra_long = TRUE;
+                  break;
+
+                  /* parse output conversions
+                   */
+                case '%':
+                  conv_len += 1;
+                  break;
+                case 'o':
+                  conv_len += 2;
+                  /* fall through */
+                case 'd':
+                case 'i':
+                  conv_len += 1; /* sign */
+                  /* fall through */
+                case 'u':
+                  conv_len += 4;
+                  /* fall through */
+                case 'x':
+                case 'X':
+                  spec.possible_sign = TRUE;
+                  conv_len += 10;
+                  if (spec.mod_long && HONOUR_LONGS)
+                    conv_len *= 2;
+                  if (spec.mod_extra_long)
+                    conv_len *= 2;
+                  if (spec.mod_extra_long)
+                    {
+#if SIZEOF_LONG_LONG > 0
+                      (void) va_arg (args, long long);
+#else
+		      i_panic("mod_extra_long not supported");
+#endif
+                    }
+                  else if (spec.mod_long)
+                    (void) va_arg (args, long);
+                  else
+                    (void) va_arg (args, int);
+                  break;
+                case 'A':
+                case 'a':
+                  /*          0x */
+                  conv_len += 2;
+                  /* fall through */
+                case 'g':
+                case 'G':
+                case 'e':
+                case 'E':
+                case 'f':
+                  spec.possible_sign = TRUE;
+                  /*          n   .   dddddddddddddddddddddddd   E   +-  eeee */
+                  conv_len += 1 + 1 + I_MAX (24, spec.precision) + 1 + 1 + 4;
+                  if (spec.mod_extra_long)
+                    i_panic("unable to handle long double");
+#ifdef HAVE_LONG_DOUBLE
+#error need to implement special handling for long double
+#endif
+                  u_double.v_double = va_arg (args, double);
+                  /* %f can expand up to all significant digits before '.' (308) */
+                  if (c == 'f' &&
+                      u_double.mpn.biased_exponent > 0 && u_double.mpn.biased_exponent < 2047)
+                    {
+                      int exp = u_double.mpn.biased_exponent;
+
+                      exp -= G_IEEE754_DOUBLE_BIAS;
+                      exp = exp * G_LOG_2_BASE_10 + 1;
+                      conv_len += exp;
+                    }
+                  /* some printf() implementations require extra padding for rounding */
+                  conv_len += 2;
+                  /* we can't really handle locale specific grouping here */
+                  if (spec.locale_grouping)
+                    conv_len *= 2;
+                  break;
+                case 'c':
+                  conv_len += spec.mod_long ? MB_LEN_MAX : 1;
+                  (void) va_arg (args, int);
+                  break;
+                case 's':
+                  v_string = va_arg (args, char*);
+                  if (!v_string)
+                    conv_len += 8; /* hold "(null)" */
+                  else if (spec.seen_precision)
+                    conv_len += spec.precision;
+                  else
+                    conv_len += strlen (v_string);
+                  conv_done = TRUE;
+                  if (spec.mod_long)
+                    i_panic("unable to handle wide char strings");
+                  break;
+                case 'p':
+                  spec.alternate_format = TRUE;
+                  conv_len += 10;
+                  if (HONOUR_LONGS)
+                    conv_len *= 2;
+		  conv_done = TRUE;
+		  (void) va_arg (args, void*);
+                  break;
+
+                  /* handle invalid cases
+                   */
+                case '\000':
+                  /* no conversion specification, bad bad */
+		  i_panic("Missing conversion specifier");
+                  break;
+                default:
+                  i_panic("unable to handle `%c' while parsing format", c);
+                  break;
+                }
+              conv_done |= conv_len > 0;
+            }
+          while (!conv_done);
+          /* handle width specifications */
+          conv_len = I_MAX (conv_len, I_MAX (spec.precision, spec.min_width));
+          /* handle flags */
+          conv_len += spec.alternate_format ? 2 : 0;
+          conv_len += (spec.add_space || spec.add_sign || spec.possible_sign);
+          /* finally done */
+          len += conv_len;
+        } /* else (c == '%') */
+    } /* while (*format) */
+
+  return len;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/printf-upper-bound.h	Sun Dec 22 09:06:16 2002 +0200
@@ -0,0 +1,8 @@
+#ifndef __PRINTF_UPPER_BOUND_H
+#define __PRINTF_UPPER_BOUND_H
+
+/* Returns the maximum length of given format string when expanded.
+   If the format is invalid, i_fatal() is called. */
+size_t printf_string_upper_bound(const char *format, va_list args);
+
+#endif
--- a/src/lib/str.c	Sun Dec 22 08:28:44 2002 +0200
+++ b/src/lib/str.c	Sun Dec 22 09:06:16 2002 +0200
@@ -23,6 +23,7 @@
 
 #include "lib.h"
 #include "buffer.h"
+#include "printf-upper-bound.h"
 #include "str.h"
 
 #include <stdio.h>
--- a/src/lib/strfuncs.c	Sun Dec 22 08:28:44 2002 +0200
+++ b/src/lib/strfuncs.c	Sun Dec 22 09:06:16 2002 +0200
@@ -1,32 +1,32 @@
 /*
- strfuncs.c : String manipulation functions (note: LGPL, because the )
-
-    Copyright (C) 2001-2002 Timo Sirainen
+ strfuncs.c : String manipulation functions
 
-    printf_string_upper_bound() code is taken from GLIB:
-    Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
-    Modified by the GLib Team and others 1997-1999.
-
+    Copyright (c) 2002 Timo Sirainen
 
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 of the License, or (at your option) any later version.
-  
-    This library is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
-    Library General Public License for more details.
-  
-    You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the
-    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-    Boston, MA 02111-1307, USA.
+    Permission is hereby granted, free of charge, to any person obtaining
+    a copy of this software and associated documentation files (the
+    "Software"), to deal in the Software without restriction, including
+    without limitation the rights to use, copy, modify, merge, publish,
+    distribute, sublicense, and/or sell copies of the Software, and to
+    permit persons to whom the Software is furnished to do so, subject to
+    the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
 /* @UNSAFE: whole file */
 
 #include "lib.h"
+#include "printf-upper-bound.h"
 #include "strfuncs.h"
 
 #include <stdio.h>
@@ -35,301 +35,6 @@
 
 #define STRCONCAT_BUFSIZE 512
 
-typedef void *(*ALLOC_FUNC)(Pool, size_t);
-
-static void *tp_malloc(Pool pool __attr_unused__, size_t size)
-{
-        return t_malloc(size);
-}
-
-typedef union  _GDoubleIEEE754  GDoubleIEEE754;
-#define G_IEEE754_DOUBLE_BIAS   (1023)
-/* multiply with base2 exponent to get base10 exponent (nomal numbers) */
-#define G_LOG_2_BASE_10         (0.30102999566398119521)
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-union _GDoubleIEEE754
-{
-  double v_double;
-  struct {
-    unsigned int mantissa_low : 32;
-    unsigned int mantissa_high : 20;
-    unsigned int biased_exponent : 11;
-    unsigned int sign : 1;
-  } mpn;
-};
-#elif G_BYTE_ORDER == G_BIG_ENDIAN
-union _GDoubleIEEE754
-{
-  double v_double;
-  struct {
-    unsigned int sign : 1;
-    unsigned int biased_exponent : 11;
-    unsigned int mantissa_high : 20;
-    unsigned int mantissa_low : 32;
-  } mpn;
-};
-#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
-#error unknown ENDIAN type
-#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
-
-typedef struct
-{
-  unsigned int min_width;
-  unsigned int precision;
-  int alternate_format, zero_padding, adjust_left, locale_grouping;
-  int add_space, add_sign, possible_sign, seen_precision;
-  int mod_long, mod_extra_long;
-} PrintfArgSpec;
-
-#if (SIZEOF_LONG > 4) || (SIZEOF_VOID_P > 4)
-#  define HONOUR_LONGS 1
-#else
-#  define HONOUR_LONGS 0
-#endif
-
-size_t printf_string_upper_bound(const char *format, va_list args)
-{
-  size_t len = 1;
-
-  if (!format)
-    return len;
-
-  while (*format)
-    {
-      register char c = *format++;
-
-      if (c != '%')
-        len += 1;
-      else /* (c == '%') */
-        {
-          PrintfArgSpec spec;
-          int seen_l = FALSE, conv_done = FALSE;
-          unsigned int conv_len = 0;
-
-          memset(&spec, 0, sizeof(spec));
-          do
-            {
-              c = *format++;
-              switch (c)
-                {
-                  GDoubleIEEE754 u_double;
-                  unsigned int v_uint;
-                  int v_int;
-                  const char *v_string;
-
-                  /* beware of positional parameters
-                   */
-                case '$':
-                  i_panic("unable to handle positional parameters (%%n$)");
-                  break;
-
-                  /* parse flags
-                   */
-                case '#':
-                  spec.alternate_format = TRUE;
-                  break;
-                case '0':
-                  spec.zero_padding = TRUE;
-                  break;
-                case '-':
-                  spec.adjust_left = TRUE;
-                  break;
-                case ' ':
-                  spec.add_space = TRUE;
-                  break;
-                case '+':
-                  spec.add_sign = TRUE;
-                  break;
-                case '\'':
-                  spec.locale_grouping = TRUE;
-                  break;
-
-                  /* parse output size specifications
-                   */
-                case '.':
-                  spec.seen_precision = TRUE;
-                  break;
-                case '1':
-                case '2':
-                case '3':
-                case '4':
-                case '5':
-                case '6':
-                case '7':
-                case '8':
-                case '9':
-                  v_uint = c - '0';
-                  c = *format;
-                  while (c >= '0' && c <= '9')
-                    {
-                      format++;
-                      v_uint = v_uint * 10 + (c - '0');
-                      c = *format;
-                    }
-                  if (spec.seen_precision)
-                    spec.precision = I_MAX (spec.precision, v_uint);
-                  else
-                    spec.min_width = I_MAX (spec.min_width, v_uint);
-                  break;
-                case '*':
-                  v_int = va_arg (args, int);
-                  if (spec.seen_precision)
-                    {
-                      /* forget about negative precision */
-                      if (v_int >= 0)
-                        spec.precision = I_MAX ((int)spec.precision, v_int);
-                    }
-                  else
-                    {
-                      if (v_int < 0)
-                        {
-                          v_int = - v_int;
-                          spec.adjust_left = TRUE;
-                        }
-                      spec.min_width = I_MAX ((int)spec.min_width, v_int);
-                    }
-                  break;
-
-                  /* parse type modifiers
-                   */
-                case 'h':
-		  /* ignore */
-                  break;
-                case 'l':
-                  if (!seen_l)
-                    {
-                      spec.mod_long = TRUE;
-                      seen_l = TRUE;
-                      break;
-                    }
-                  /* else, fall through */
-                case 'L':
-                  spec.mod_long = TRUE;
-                  spec.mod_extra_long = TRUE;
-                  break;
-
-                  /* parse output conversions
-                   */
-                case '%':
-                  conv_len += 1;
-                  break;
-                case 'o':
-                  conv_len += 2;
-                  /* fall through */
-                case 'd':
-                case 'i':
-                  conv_len += 1; /* sign */
-                  /* fall through */
-                case 'u':
-                  conv_len += 4;
-                  /* fall through */
-                case 'x':
-                case 'X':
-                  spec.possible_sign = TRUE;
-                  conv_len += 10;
-                  if (spec.mod_long && HONOUR_LONGS)
-                    conv_len *= 2;
-                  if (spec.mod_extra_long)
-                    conv_len *= 2;
-                  if (spec.mod_extra_long)
-                    {
-#if SIZEOF_LONG_LONG > 0
-                      (void) va_arg (args, long long);
-#else
-		      i_panic("mod_extra_long not supported");
-#endif
-                    }
-                  else if (spec.mod_long)
-                    (void) va_arg (args, long);
-                  else
-                    (void) va_arg (args, int);
-                  break;
-                case 'A':
-                case 'a':
-                  /*          0x */
-                  conv_len += 2;
-                  /* fall through */
-                case 'g':
-                case 'G':
-                case 'e':
-                case 'E':
-                case 'f':
-                  spec.possible_sign = TRUE;
-                  /*          n   .   dddddddddddddddddddddddd   E   +-  eeee */
-                  conv_len += 1 + 1 + I_MAX (24, spec.precision) + 1 + 1 + 4;
-                  if (spec.mod_extra_long)
-                    i_panic("unable to handle long double");
-#ifdef HAVE_LONG_DOUBLE
-#error need to implement special handling for long double
-#endif
-                  u_double.v_double = va_arg (args, double);
-                  /* %f can expand up to all significant digits before '.' (308) */
-                  if (c == 'f' &&
-                      u_double.mpn.biased_exponent > 0 && u_double.mpn.biased_exponent < 2047)
-                    {
-                      int exp = u_double.mpn.biased_exponent;
-
-                      exp -= G_IEEE754_DOUBLE_BIAS;
-                      exp = exp * G_LOG_2_BASE_10 + 1;
-                      conv_len += exp;
-                    }
-                  /* some printf() implementations require extra padding for rounding */
-                  conv_len += 2;
-                  /* we can't really handle locale specific grouping here */
-                  if (spec.locale_grouping)
-                    conv_len *= 2;
-                  break;
-                case 'c':
-                  conv_len += spec.mod_long ? MB_LEN_MAX : 1;
-                  (void) va_arg (args, int);
-                  break;
-                case 's':
-                  v_string = va_arg (args, char*);
-                  if (!v_string)
-                    conv_len += 8; /* hold "(null)" */
-                  else if (spec.seen_precision)
-                    conv_len += spec.precision;
-                  else
-                    conv_len += strlen (v_string);
-                  conv_done = TRUE;
-                  if (spec.mod_long)
-                    i_panic("unable to handle wide char strings");
-                  break;
-                case 'p':
-                  spec.alternate_format = TRUE;
-                  conv_len += 10;
-                  if (HONOUR_LONGS)
-                    conv_len *= 2;
-		  conv_done = TRUE;
-		  (void) va_arg (args, void*);
-                  break;
-
-                  /* handle invalid cases
-                   */
-                case '\000':
-                  /* no conversion specification, bad bad */
-		  i_panic("Missing conversion specifier");
-                  break;
-                default:
-                  i_panic("unable to handle `%c' while parsing format", c);
-                  break;
-                }
-              conv_done |= conv_len > 0;
-            }
-          while (!conv_done);
-          /* handle width specifications */
-          conv_len = I_MAX (conv_len, I_MAX (spec.precision, spec.min_width));
-          /* handle flags */
-          conv_len += spec.alternate_format ? 2 : 0;
-          conv_len += (spec.add_space || spec.add_sign || spec.possible_sign);
-          /* finally done */
-          len += conv_len;
-        } /* else (c == '%') */
-    } /* while (*format) */
-
-  return len;
-}
-
 static const char *fix_format_real(const char *fmt, const char *p)
 {
 	const char *errstr;
@@ -434,74 +139,29 @@
 	return ret;
 }
 
-#define STRDUP_CORE(alloc_func, str) STMT_START { \
-	void *mem;				\
-	size_t len;				\
-						\
-	for (len = 0; (str)[len] != '\0'; )	\
-		len++;				\
-	len++;					\
-	mem = alloc_func;			\
-	memcpy(mem, str, sizeof(str[0])*len);	\
-	return mem;				\
-	} STMT_END
-
 char *p_strdup(Pool pool, const char *str)
 {
-	if (str == NULL)
-                return NULL;
-
-        STRDUP_CORE(p_malloc(pool, len), str);
-}
+	void *mem;
+	size_t len;
 
-const char *t_strdup(const char *str)
-{
-	if (str == NULL)
-                return NULL;
-
-        STRDUP_CORE(t_malloc(len), str);
-}
-
-char *t_strdup_noconst(const char *str)
-{
 	if (str == NULL)
                 return NULL;
 
-        STRDUP_CORE(t_malloc(len), str);
-}
-
-int *p_intarrdup(Pool pool, const int *arr)
-{
-	if (arr == NULL)
-                return NULL;
-
-        STRDUP_CORE(p_malloc(pool, sizeof(int) * len), arr);
-}
+	for (len = 0; (str)[len] != '\0'; )
+		len++;
+	len++;
 
-const int *t_intarrdup(const int *arr)
-{
-	if (arr == NULL)
-                return NULL;
-
-        STRDUP_CORE(t_malloc(sizeof(int) * len), arr);
+	mem = p_malloc(pool, len);
+	memcpy(mem, str, len);
+	return mem;
 }
 
-#define STRDUP_EMPTY_CORE(alloc_func, str) STMT_START { \
-	if ((str) == NULL || (str)[0] == '\0')	\
-                return NULL;			\
-						\
-	STRDUP_CORE(alloc_func, str);		\
-	} STMT_END
-
-
 char *p_strdup_empty(Pool pool, const char *str)
 {
-        STRDUP_EMPTY_CORE(p_malloc(pool, len), str);
-}
+	if (str == NULL || *str == '\0')
+                return NULL;
 
-const char *t_strdup_empty(const char *str)
-{
-        STRDUP_EMPTY_CORE(t_malloc(len), str);
+	return p_strdup(pool, str);
 }
 
 char *p_strdup_until(Pool pool, const char *start, const char *end)
@@ -512,36 +172,18 @@
 	i_assert(start <= end);
 
 	size = (size_t) (end-start);
-	i_assert(size < SSIZE_T_MAX);
 
 	mem = p_malloc(pool, size + 1);
 	memcpy(mem, start, size);
 	return mem;
 }
 
-const char *t_strdup_until(const char *start, const char *end)
-{
-	size_t size;
-	char *mem;
-
-	i_assert(start <= end);
-
-	size = (size_t) (end-start);
-	i_assert(size < SSIZE_T_MAX);
-
-	mem = t_malloc(size + 1);
-	memcpy(mem, start, size);
-	mem[size] = '\0';
-	return mem;
-}
-
-static inline char *strndup_core(const char *str, size_t max_chars,
-				 ALLOC_FUNC alloc, Pool pool)
+char *p_strndup(Pool pool, const char *str, size_t max_chars)
 {
 	char *mem;
 	size_t len;
 
-	i_assert(max_chars < SSIZE_T_MAX);
+	i_assert(max_chars != (size_t)-1);
 
 	if (str == NULL)
 		return NULL;
@@ -550,22 +192,12 @@
 	while (str[len] != '\0' && len < max_chars)
 		len++;
 
-	mem = alloc(pool, len+1);
+	mem = pool->malloc(pool, len+1);
 	memcpy(mem, str, len);
 	mem[len] = '\0';
 	return mem;
 }
 
-char *p_strndup(Pool pool, const char *str, size_t max_chars)
-{
-        return strndup_core(str, max_chars, pool->malloc, pool);
-}
-
-const char *t_strndup(const char *str, size_t max_chars)
-{
-        return strndup_core(str, max_chars, tp_malloc, NULL);
-}
-
 char *p_strdup_printf(Pool pool, const char *format, ...)
 {
 	va_list args;
@@ -578,70 +210,32 @@
 	return ret;
 }
 
-const char *t_strdup_printf(const char *format, ...)
+char *p_strdup_vprintf(Pool pool, const char *format, va_list args)
 {
-	va_list args;
-        const char *ret;
-
-	va_start(args, format);
-        ret = t_strdup_vprintf(format, args);
-	va_end(args);
-
-	return ret;
-}
-
-static inline char *
-strdup_vprintf_core(const char *format, va_list args,
-		    ALLOC_FUNC alloc_func, Pool pool)
-{
-        va_list temp_args;
 	char *ret;
 	size_t len;
 
-	if (format == NULL)
-		return NULL;
+	i_assert(format != NULL);
+
+	if (pool != data_stack_pool)
+		t_push();
 
 	format = printf_string_fix_format(format);
 
-	VA_COPY(temp_args, args);
-
 	len = printf_string_upper_bound(format, args);
-        ret = alloc_func(pool, len);
+        ret = p_malloc(pool, len);
 
 #ifdef HAVE_VSNPRINTF
 	vsnprintf(ret, len, format, args);
 #else
 	vsprintf(ret, format, args);
 #endif
-
-	va_end(temp_args);
-
-        return ret;
-}
-
-char *p_strdup_vprintf(Pool pool, const char *format, va_list args)
-{
-	char *ret;
-
-	t_push();
-	ret = strdup_vprintf_core(format, args, pool->malloc, pool);
-	t_pop();
+	if (pool != data_stack_pool)
+		t_pop();
 	return ret;
 }
 
-const char *t_strdup_vprintf(const char *format, va_list args)
-{
-        return strdup_vprintf_core(format, args, tp_malloc, NULL);
-}
-
-void p_strdup_replace(Pool pool, char **dest, const char *str)
-{
-	p_free(pool, *dest);
-        *dest = p_strdup(pool, str);
-}
-
-const char *temp_strconcat(const char *str1, va_list args,
-			   size_t *ret_len)
+const char *_vstrconcat(const char *str1, va_list args, size_t *ret_len)
 {
 	const char *str;
         char *temp;
@@ -688,7 +282,7 @@
 
 	va_start(args, str1);
 
-	temp = temp_strconcat(str1, args, &len);
+	temp = _vstrconcat(str1, args, &len);
 	if (temp == NULL)
 		ret = NULL;
 	else {
@@ -700,6 +294,48 @@
         return ret;
 }
 
+const char *t_strdup(const char *str)
+{
+	return p_strdup(data_stack_pool, str);
+}
+
+char *t_strdup_noconst(const char *str)
+{
+	return p_strdup(data_stack_pool, str);
+}
+
+const char *t_strdup_empty(const char *str)
+{
+	return p_strdup_empty(data_stack_pool, str);
+}
+
+const char *t_strdup_until(const char *start, const char *end)
+{
+	return p_strdup_until(data_stack_pool, start, end);
+}
+
+const char *t_strndup(const char *str, size_t max_chars)
+{
+	return p_strndup(data_stack_pool, str, max_chars);
+}
+
+const char *t_strdup_printf(const char *format, ...)
+{
+	va_list args;
+	const char *ret;
+
+	va_start(args, format);
+	ret = p_strdup_vprintf(data_stack_pool, format, args);
+	va_end(args);
+
+	return ret;
+}
+
+const char *t_strdup_vprintf(const char *format, va_list args)
+{
+	return p_strdup_vprintf(data_stack_pool, format, args);
+}
+
 const char *t_strconcat(const char *str1, ...)
 {
 	va_list args;
@@ -708,7 +344,7 @@
 
 	va_start(args, str1);
 
-	ret = temp_strconcat(str1, args, &len);
+	ret = _vstrconcat(str1, args, &len);
 	if (ret != NULL)
 		t_buffer_alloc(len);
 
--- a/src/lib/strfuncs.h	Sun Dec 22 08:28:44 2002 +0200
+++ b/src/lib/strfuncs.h	Sun Dec 22 09:06:16 2002 +0200
@@ -6,7 +6,6 @@
 
 #define MAX_INT_STRLEN ((sizeof(uintmax_t) * CHAR_BIT + 2) / 3 + 1)
 
-size_t printf_string_upper_bound(const char *format, va_list args);
 const char *printf_string_fix_format(const char *fmt) __attr_format_arg__(1);
 
 /* Returns -1 if dest wasn't large enough, 0 if not. */
@@ -19,9 +18,6 @@
 char *p_strndup(Pool pool, const char *str, size_t max_chars);
 char *p_strdup_printf(Pool pool, const char *format, ...) __attr_format__(2, 3);
 char *p_strdup_vprintf(Pool pool, const char *format, va_list args);
-void p_strdup_replace(Pool pool, char **dest, const char *str);
-int *p_intarrdup(Pool pool, const int *arr);
-
 char *p_strconcat(Pool pool, const char *str1, ...); /* NULL terminated */
 
 /* same with temporary memory allocations: */
@@ -32,16 +28,16 @@
 const char *t_strndup(const char *str, size_t max_chars);
 const char *t_strdup_printf(const char *format, ...) __attr_format__(1, 2);
 const char *t_strdup_vprintf(const char *format, va_list args);
-const int *t_intarrdup(const int *arr);
+const char *t_strconcat(const char *str1, ...); /* NULL terminated */
 
-const char *t_strconcat(const char *str1, ...); /* NULL terminated */
+/* Like t_strdup(), but stop at cutchar. */
 const char *t_strcut(const char *str, char cutchar);
 
 /* Return TRUE if all characters in string are numbers.
    Stop when `end_char' is found from string. */
 int is_numeric(const char *str, char end_char);
 
-/* like strlcpy(), but return -1 if buffer was overflown, 0 if not. */
+/* Like strlcpy(), but return -1 if buffer was overflown, 0 if not. */
 int strocpy(char *dest, const char *src, size_t dstsize);
 
 /* Print given directory and file to dest buffer, separated with '/'.
@@ -66,6 +62,6 @@
 const char *dec2str(uintmax_t number);
 
 /* INTERNAL */
-const char *temp_strconcat(const char *str1, va_list args, size_t *ret_len);
+const char *_vstrconcat(const char *str1, va_list args, size_t *ret_len);
 
 #endif
--- a/src/master/settings.c	Sun Dec 22 08:28:44 2002 +0200
+++ b/src/master/settings.c	Sun Dec 22 09:06:16 2002 +0200
@@ -361,7 +361,8 @@
 		ptr = NULL;
 
 	if (ptr != NULL) {
-		i_strdup_replace(ptr, value);
+		i_free(*ptr);
+		*ptr = i_strdup(value);
 		return NULL;
 	}