Re: [PATCH] Re: Change 28183 has broken 64-bit builds?
Jarkko Hietaniemi [Thu, 18 May 2006 22:44:14 +0000 (01:44 +0300)]
Message-ID: <446CCE8E.8010407@gmail.com>

p4raw-id: //depot/perl@28234

perl.h
perlio.c
util.c

diff --git a/perl.h b/perl.h
index aa47dec..5b4dbdd 100644 (file)
--- a/perl.h
+++ b/perl.h
@@ -1458,24 +1458,34 @@ int sockatmark(int);
  * even with the version that uses the C99 variadic macros.
  */
 
-#if defined(HAS_C99_VARIADIC_MACROS) && !(defined(DEBUGGING) && !defined(PERL_USE_GCC_BRACE_GROUPS))
+/* Note that we do not check against snprintf()/vsnprintf() returning
+ * negative values because that is non-standard behaviour and we use
+ * snprintf/vsnprintf only iff HAS_VSNPRINTF has been defined, and
+ * that should be true only if the snprintf()/vsnprintf() are true
+ * to the standard. */
+
+#if defined(HAS_SNPRINTF) && 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__; })
+#      define my_snprintf(buffer, len, ...) ({ int __len__ = snprintf(buffer, len, __VA_ARGS__); if ((len) > 0 && __len__ >= (len)) Perl_croak(aTHX_ "panic: snprintf buffer overflow"); __len__; })
+#      define PERL_MY_SNPRINTF_GUARDED
 #  else
 #    define my_snprintf(buffer, len, ...) snprintf(buffer, len, __VA_ARGS__)
 #  endif
 #else
 #  define my_snprintf  Perl_my_snprintf
+#  define PERL_MY_SNPRINTF_GUARDED
 #endif
 
-#if defined(HAS_C99_VARIADIC_MACROS)
+#if defined(HAS_VSNPRINTF) && defined(HAS_C99_VARIADIC_MACROS) && !(defined(DEBUGGING) && !defined(PERL_USE_GCC_BRACE_GROUPS))
 #  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__; })
+#      define my_vsnprintf(buffer, len, ...) ({ int __len__ = vsnprintf(buffer, len, __VA_ARGS__); if ((len) > 0 && __len__ >= (len)) Perl_croak(aTHX_ "panic: vsnprintf buffer overflow"); __len__; })
+#      define PERL_MY_VSNPRINTF_GUARDED
 #  else
 #    define my_vsnprintf(buffer, len, ...) vsnprintf(buffer, len, __VA_ARGS__)
 #  endif
 #else
 #  define my_vsnprintf Perl_my_vsnprintf
+#  define PERL_MY_VSNPRINTF_GUARDED
 #endif
 
 /* Configure gets this right but the UTS compiler gets it wrong.
index 9e06ef1..a0cb4a4 100644 (file)
--- a/perlio.c
+++ b/perlio.c
@@ -478,9 +478,9 @@ PerlIO_debug(const char *fmt, ...)
        const char * const s = CopFILE(PL_curcop);
        /* Use fixed buffer as sv_catpvf etc. needs SVs */
        char buffer[1024];
-       const STRLEN len = my_sprintf(buffer, "%.40s:%" IVdf " ", s ? s : "(none)", (IV) CopLINE(PL_curcop));
-       const STRLEN len2 = my_vsnprintf(buffer+len, sizeof(buffer) - len, fmt, ap);
-       PerlLIO_write(PL_perlio_debug_fd, buffer, len + len2);
+       const STRLEN len1 = my_snprintf(buffer, sizeof(buffer), "%.40s:%" IVdf " ", s ? s : "(none)", (IV) CopLINE(PL_curcop));
+       const STRLEN len2 = my_vsnprintf(buffer + len1, sizeof(buffer) - len1, fmt, ap);
+       PerlLIO_write(PL_perlio_debug_fd, buffer, len1 + len2);
 #else
        const char *s = CopFILE(PL_curcop);
        STRLEN len;
@@ -5144,14 +5144,12 @@ PerlIO_vsprintf(char *s, int n, const char *fmt, va_list ap)
 {
     dTHX;
     const int val = my_vsnprintf(s, n > 0 ? n : 0, fmt, ap);
-    if (n >= 0) {
-       if (strlen(s) >= (STRLEN) n) {
-           dTHX;
-           (void) PerlIO_puts(Perl_error_log,
-                              "panic: sprintf overflow - memory corrupted!\n");
-           my_exit(1);
-       }
+#ifndef PERL_MY_VSNPRINTF_GUARDED
+    if (val < 0 || (n > 0 ? val >= n : 0)) {
+       dTHX;
+       Perl_croak("panic: my_vsnprintf overflow in PerlIO_vsprintf\n");
     }
+#endif
     return val;
 }
 #endif
diff --git a/util.c b/util.c
index 4e49d19..4abdf73 100644 (file)
--- a/util.c
+++ b/util.c
@@ -5380,7 +5380,8 @@ Perl_my_snprintf(char *buffer, const Size_t len, const char *format, ...)
     retval = vsprintf(buffer, format, ap);
 #endif
     va_end(ap);
-    if (retval >= len)
+    /* vsnprintf() shows failure with >= len, vsprintf() with < 0 */
+    if (retval < 0 || (len > 0 && retval >= len))
        Perl_croak(aTHX_ "panic: my_snprintf buffer overflow");
     return retval;
 }
@@ -5416,7 +5417,8 @@ Perl_my_vsnprintf(char *buffer, const Size_t len, const char *format, va_list ap
     retval = vsprintf(buffer, format, ap);
 # endif
 #endif /* #ifdef NEED_VA_COPY */
-    if (retval >= len)
+    /* vsnprintf() shows failure with >= len, vsprintf() with < 0 */
+    if (retval < 0 || (len > 0 && retval >= len))
        Perl_croak(aTHX_ "panic: my_vsnprintf buffer overflow");
     return retval;
 }