diff options
-rw-r--r-- | perl.h | 46 | ||||
-rw-r--r-- | perlio.c | 2 | ||||
-rw-r--r-- | pod/perlapi.pod | 14 | ||||
-rw-r--r-- | util.c | 96 |
4 files changed, 93 insertions, 65 deletions
@@ -348,11 +348,17 @@ register struct op *Perl_op asm(stringify(OP_IN_REGISTER)); #endif #if defined(PERL_GCC_PEDANTIC) -# if !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) +# ifndef PERL_GCC_BRACE_GROUPS_FORBIDDEN # define PERL_GCC_BRACE_GROUPS_FORBIDDEN # endif #endif +#if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) && !defined(__cplusplus) +# ifndef PERL_USE_GCC_BRACE_GROUPS +# define PERL_USE_GCC_BRACE_GROUPS +# endif +#endif + /* * STMT_START { statements; } STMT_END; * can be used as a single statement, as in @@ -361,7 +367,7 @@ register struct op *Perl_op asm(stringify(OP_IN_REGISTER)); * Trying to select a version that gives no warnings... */ #if !(defined(STMT_START) && defined(STMT_END)) -# if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) && !defined(__cplusplus) +# ifdef PERL_USE_GCC_BRACE_GROUPS # define STMT_START (void)( /* gcc supports "({ STATEMENTS; })" */ # define STMT_END ) # else @@ -1439,18 +1445,38 @@ int sockatmark(int); */ #ifdef SPRINTF_RETURNS_STRLEN # define my_sprintf sprintf -# ifdef HAS_SNPRINTF -# define USE_SNPRINTF -# endif -# ifdef HAS_VSNPRINTF -# define USE_VSNPRINTF -# endif #else # define my_sprintf Perl_my_sprintf #endif -#define my_snprintf Perl_my_snprintf -#define my_vsnprintf Perl_my_vsnprintf +/* + * If we have v?snprintf() and the C99 variadic macros, we can just + * use just the v?snprintf(). It is nice to try to trap the buffer + * overflow, however, so if we are DEBUGGING, and we cannot use the + * gcc brace groups, then use the function wrappers which try to trap + * the overflow. If we can use the gcc brace groups, we can try that + * even with the version that uses the C99 variadic macros. + */ + +#if defined(HAS_C99_VARIADIC_MACROS) && !(defined(DEBUGGING) && !defined(PERL_USE_GCC_BRACE_GROUPS)) +# ifdef PERL_USE_GCC_BRACE_GROUPS +# define my_snprintf(buffer, len, ...) ({ int __len__ = snprintf(buffer, len, __VA_ARGS__); if (__len__ >= len) Perl_croak(aTHX_ "panic: snprintf buffer overflow"); __len__; }) +# else +# define my_snprintf(buffer, len, ...) snprintf(buffer, len, __VA_ARGS__) +# endif +#else +# define my_snprintf Perl_my_snprintf +#endif + +#if defined(HAS_C99_VARIADIC_MACROS) +# ifdef PERL_USE_GCC_BRACE_GROUPS +# define my_vsnprintf(buffer, len, ...) ({ int __len__ = vsnprintf(buffer, len, __VA_ARGS__); if (__len__ >= len) Perl_croak(aTHX_ "panic: vsnprintf buffer overflow"); __len__; }) +# else +# define my_vsnprintf(buffer, len, ...) vsnprintf(buffer, len, __VA_ARGS__) +# endif +#else +# define my_vsnprintf Perl_my_vsnprintf +#endif /* Configure gets this right but the UTS compiler gets it wrong. -- Hal Morris <hom00@utsglobal.com> */ @@ -5142,7 +5142,7 @@ vfprintf(FILE *fd, char *pat, char *args) int PerlIO_vsprintf(char *s, int n, const char *fmt, va_list ap) { - dVAR; + dTHX; const int val = my_vsnprintf(s, n > 0 ? n : 0, fmt, ap); if (n >= 0) { if (strlen(s) >= (STRLEN) n) { diff --git a/pod/perlapi.pod b/pod/perlapi.pod index 400b329ca1..b9eb329b71 100644 --- a/pod/perlapi.pod +++ b/pod/perlapi.pod @@ -2249,9 +2249,11 @@ Found in file util.c X<my_snprintf> The C library C<snprintf> functionality, if available and -standards-compliant (uses C<vsnprintf>, actually). If the +standards-compliant (uses C<vsnprintf>, actually). However, if the C<vsnprintf> is not available, will unfortunately use the unsafe -C<vsprintf>. Consider using C<sv_vcatpvf> instead. +C<vsprintf> which can overrun the buffer (there is an overrun check, +but that may be too late). Consider using C<sv_vcatpvf> instead, or +getting C<vsnprintf>. int my_snprintf(char *buffer, const Size_t len, const char *format, ...) @@ -2273,9 +2275,11 @@ Found in file util.c =item my_vsnprintf X<my_vsnprintf> -The C library C<vsnprintf> if available and standards-compliant, -but if the C<vsnprintf> is not available, will unfortunately use -the unsafe C<vsprintf>. Consider using C<sv_vcatpvf> instead. +The C library C<vsnprintf> if available and standards-compliant. +However, if if the C<vsnprintf> is not available, will unfortunately +use the unsafe C<vsprintf> which can overrun the buffer (there is an +overrun check, but that may be too late). Consider using +C<sv_vcatpvf> instead, or getting C<vsnprintf>. int my_vsnprintf(char *buffer, const Size_t len, const char *format, va_list ap) @@ -5206,27 +5206,30 @@ Perl_mem_log_alloc(const UV n, const UV typesize, const char *typename, Malloc_t /* We can't use SVs or PerlIO for obvious reasons, * so we'll use stdio and low-level IO instead. */ char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE]; -# if defined(PERL_MEM_LOG_TIMESTAMP) && defined(HAS_GETTIMEOFDAY) +# ifdef PERL_MEM_LOG_TIMESTAMP struct timeval tv; +# ifdef HAS_GETTIMEOFDAY gettimeofday(&tv, 0); +# endif + /* If there are other OS specific ways of hires time than + * gettimeofday() (see ext/Time/HiRes), the easiest way is + * probably that they would be used to fill in the struct + * timeval. */ +# endif { const STRLEN len = my_snprintf(buf, PERL_MEM_LOG_SPRINTF_BUF_SIZE, - "%10d.%06d: alloc: %s:%d:%s: %"IVdf" %"UVuf - " %s = %"IVdf": %"UVxf"\n", - (int)tv.tv_sec, (int)tv.tv_usec, - filename, linenumber, funcname, n, typesize, - typename, n * typesize, PTR2UV(newalloc)); -# else - const STRLEN len = - my_snprintf(buf, - PERL_MEM_LOG_SPRINTF_BUF_SIZE, +# ifdef PERL_MEM_LOG_TIMESTAMP + "%10d.%06d: " +# endif "alloc: %s:%d:%s: %"IVdf" %"UVuf " %s = %"IVdf": %"UVxf"\n", +# ifdef PERL_MEM_LOG_TIMESTAMP + (int)tv.tv_sec, (int)tv.tv_usec, +# endif filename, linenumber, funcname, n, typesize, typename, n * typesize, PTR2UV(newalloc)); -# endif # ifdef PERL_MEM_LOG_ENV_FD s = PerlEnv_getenv("PERL_MEM_LOG_FD"); PerlLIO_write(s ? atoi(s) : PERL_MEM_LOG_FD, buf, len); @@ -5254,29 +5257,25 @@ Perl_mem_log_realloc(const UV n, const UV typesize, const char *typename, Malloc /* We can't use SVs or PerlIO for obvious reasons, * so we'll use stdio and low-level IO instead. */ char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE]; -# if defined(PERL_MEM_LOG_TIMESTAMP) && defined(HAS_GETTIMEOFDAY) +# ifdef PERL_MEM_LOG_TIMESTAMP struct timeval tv; gettimeofday(&tv, 0); +# endif { const STRLEN len = my_snprintf(buf, PERL_MEM_LOG_SPRINTF_BUF_SIZE, - "%10d.%06d: realloc: %s:%d:%s: %"IVdf" %"UVuf - " %s = %"IVdf": %"UVxf" -> %"UVxf"\n", - (int)tv.tv_sec, (int)tv.tv_usec, - filename, linenumber, funcname, n, typesize, - typename, n * typesize, PTR2UV(oldalloc), - PTR2UV(newalloc)); -# else - const STRLEN len = - my_snprintf(buf, - PERL_MEM_LOG_SPRINTF_BUF_SIZE, +# ifdef PERL_MEM_LOG_TIMESTAMP + "%10d.%06d: " +# endif "realloc: %s:%d:%s: %"IVdf" %"UVuf " %s = %"IVdf": %"UVxf" -> %"UVxf"\n", +# ifdef PERL_MEM_LOG_TIMESTAMP + (int)tv.tv_sec, (int)tv.tv_usec, +# endif filename, linenumber, funcname, n, typesize, typename, n * typesize, PTR2UV(oldalloc), PTR2UV(newalloc)); -# endif # ifdef PERL_MEM_LOG_ENV_FD s = PerlEnv_getenv("PERL_MEM_LOG_FD"); PerlLIO_write(s ? atoi(s) : PERL_MEM_LOG_FD, buf, len); @@ -5304,24 +5303,23 @@ Perl_mem_log_free(Malloc_t oldalloc, const char *filename, const int linenumber, /* We can't use SVs or PerlIO for obvious reasons, * so we'll use stdio and low-level IO instead. */ char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE]; -# if defined(PERL_MEM_LOG_TIMESTAMP) && defined(HAS_GETTIMEOFDAY) +# ifdef PERL_MEM_LOG_TIMESTAMP struct timeval tv; gettimeofday(&tv, 0); +# endif { const STRLEN len = my_snprintf(buf, PERL_MEM_LOG_SPRINTF_BUF_SIZE, - "%10d.%06d: free: %s:%d:%s: %"UVxf"\n", +# ifdef PERL_MEM_LOG_TIMESTAMP + "%10d.%06d: " +# endif + "free: %s:%d:%s: %"UVxf"\n", +# ifdef PERL_MEM_LOG_TIMESTAMP (int)tv.tv_sec, (int)tv.tv_usec, +# endif filename, linenumber, funcname, PTR2UV(oldalloc)); -# else - const STRLEN len = - my_sprintf(buf, - "free: %s:%d:%s: %"UVxf"\n", - filename, linenumber, funcname, - PTR2UV(oldalloc)); -# endif # ifdef PERL_MEM_LOG_ENV_FD s = PerlEnv_getenv("PERL_MEM_LOG_FD"); PerlLIO_write(s ? atoi(s) : PERL_MEM_LOG_FD, buf, len); @@ -5361,65 +5359,65 @@ Perl_my_sprintf(char *buffer, const char* pat, ...) =for apidoc my_snprintf The C library C<snprintf> functionality, if available and -standards-compliant (uses C<vsnprintf>, actually). If the +standards-compliant (uses C<vsnprintf>, actually). However, if the C<vsnprintf> is not available, will unfortunately use the unsafe -C<vsprintf>. Consider using C<sv_vcatpvf> instead. +C<vsprintf> which can overrun the buffer (there is an overrun check, +but that may be too late). Consider using C<sv_vcatpvf> instead, or +getting C<vsnprintf>. =cut */ int Perl_my_snprintf(char *buffer, const Size_t len, const char *format, ...) -/* Cannot do this using variadic macros because that is too unportable. */ { dTHX; int retval; va_list ap; -#ifndef USE_VSNPRINTF - PERL_UNUSED_ARG(len); -#endif va_start(ap, format); -#ifdef USE_VSNPRINTF +#ifdef HAS_VSNPRINTF retval = vsnprintf(buffer, len, format, ap); #else retval = vsprintf(buffer, format, ap); #endif va_end(ap); + if (retval >= len) + Perl_croak(aTHX_ "panic: my_snprintf buffer overflow"); return retval; } /* =for apidoc my_vsnprintf -The C library C<vsnprintf> if available and standards-compliant, -but if the C<vsnprintf> is not available, will unfortunately use -the unsafe C<vsprintf>. Consider using C<sv_vcatpvf> instead. +The C library C<vsnprintf> if available and standards-compliant. +However, if if the C<vsnprintf> is not available, will unfortunately +use the unsafe C<vsprintf> which can overrun the buffer (there is an +overrun check, but that may be too late). Consider using +C<sv_vcatpvf> instead, or getting C<vsnprintf>. =cut */ int Perl_my_vsnprintf(char *buffer, const Size_t len, const char *format, va_list ap) -/* Cannot do this using variadic macros because that is too unportable. */ { dTHX; int retval; -#ifndef USE_VSNPRINTF - PERL_UNUSED_ARG(len); -#endif #ifdef NEED_VA_COPY va_list apc; Perl_va_copy(apc); -# ifdef USE_VSNPRINTF +# ifdef HAS_VSNPRINTF retval = vsnprintf(buffer, len, format, apc); # else retval = vsprintf(buffer, format, apc); # endif #else -# ifdef USE_VSNPRINTF +# ifdef HAS_VSNPRINTF retval = vsnprintf(buffer, len, format, ap); # else retval = vsprintf(buffer, format, ap); # endif -#endif +#endif /* #ifdef NEED_VA_COPY */ + if (retval >= len) + Perl_croak(aTHX_ "panic: my_vsnprintf buffer overflow"); return retval; } |