diff options
Diffstat (limited to 'db/clib/snprintf.c')
-rw-r--r-- | db/clib/snprintf.c | 129 |
1 files changed, 107 insertions, 22 deletions
diff --git a/db/clib/snprintf.c b/db/clib/snprintf.c index e41272dde..e1bc5d112 100644 --- a/db/clib/snprintf.c +++ b/db/clib/snprintf.c @@ -1,24 +1,30 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2003 + * Copyright (c) 1996-2004 * Sleepycat Software. All rights reserved. + * + * $Id: snprintf.c,v 11.18 2004/09/22 03:32:43 bostic Exp $ */ #include "db_config.h" -#ifndef lint -static const char revid[] = "$Id: snprintf.c,v 11.12 2003/05/02 16:10:41 bostic Exp $"; -#endif /* not lint */ - #ifndef NO_SYSTEM_INCLUDES #include <sys/types.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> /* Declare STDERR_FILENO. */ #endif #include "db_int.h" +#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) +static void sprintf_overflow __P((void)); +static int sprintf_retcharpnt __P((void)); +#endif + /* * snprintf -- * Bounded version of sprintf. @@ -41,9 +47,98 @@ snprintf(str, n, fmt, va_alist) { static int ret_charpnt = -1; va_list ap; - int len; + size_t len; + + if (ret_charpnt == -1) + ret_charpnt = sprintf_retcharpnt(); + +#ifdef STDC_HEADERS + va_start(ap, fmt); +#else + va_start(ap); +#endif + len = (size_t)vsprintf(str, fmt, ap); + if (ret_charpnt) + len = strlen(str); + + va_end(ap); + + if (len >= n) { + sprintf_overflow(); + /* NOTREACHED */ + } + return ((int)len); +} +#endif + +/* + * vsnprintf -- + * Bounded version of vsprintf. + * + * PUBLIC: #ifndef HAVE_VSNPRINTF + * PUBLIC: int vsnprintf __P((char *, size_t, const char *, va_list)); + * PUBLIC: #endif + */ +#ifndef HAVE_VSNPRINTF +int +vsnprintf(str, n, fmt, ap) + char *str; + size_t n; + const char *fmt; + va_list ap; +{ + static int ret_charpnt = -1; + size_t len; + + if (ret_charpnt == -1) + ret_charpnt = sprintf_retcharpnt(); + + len = (size_t)vsprintf(str, fmt, ap); + if (ret_charpnt) + len = strlen(str); + + if (len >= n) { + sprintf_overflow(); + /* NOTREACHED */ + } + return ((int)len); +} +#endif + +#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) +static void +sprintf_overflow() +{ + /* + * !!! + * We're potentially manipulating strings handed us by the application, + * and on systems without a real snprintf() the sprintf() calls could + * have overflowed the buffer. We can't do anything about it now, but + * we don't want to return control to the application, we might have + * overwritten the stack with a Trojan horse. We're not trying to do + * anything recoverable here because systems without snprintf support + * are pretty rare anymore. + */ +#define OVERFLOW_ERROR "internal buffer overflow, process ended\n" +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + (void)write(STDERR_FILENO, OVERFLOW_ERROR, sizeof(OVERFLOW_ERROR) - 1); + + /* Be polite. */ + exit(1); - COMPQUIET(n, 0); + /* But firm. */ + abort(); + + /* NOTREACHED */ +} + +static int +sprintf_retcharpnt() +{ + int ret_charpnt; + char buf[10]; /* * Some old versions of sprintf return a pointer to the first argument @@ -53,22 +148,12 @@ snprintf(str, n, fmt, va_alist) * We do this test at run-time because it's not a test we can do in a * cross-compilation environment. */ - if (ret_charpnt == -1) { - char buf[10]; - ret_charpnt = - sprintf(buf, "123") != 3 || - sprintf(buf, "123456789") != 9 || - sprintf(buf, "1234") != 4; - } + ret_charpnt = + (int)sprintf(buf, "123") != 3 || + (int)sprintf(buf, "123456789") != 9 || + (int)sprintf(buf, "1234") != 4; -#ifdef STDC_HEADERS - va_start(ap, fmt); -#else - va_start(ap); -#endif - len = vsprintf(str, fmt, ap); - va_end(ap); - return (ret_charpnt ? (int)strlen(str) : len); + return (ret_charpnt); } #endif |