Re: [PATCH] my_snprintf
Jarkko Hietaniemi [Fri, 12 May 2006 22:28:49 +0000 (01:28 +0300)]
Message-ID: <4464E1F1.9010706@gmail.com>

p4raw-id: //depot/perl@28183

12 files changed:
embed.fnc
global.sym
perl.h
perlio.c
pod/perlapi.pod
pp_ctl.c
proto.h
regcomp.c
sv.c
toke.c
universal.c
util.c

index 3fa7b93..98b980f 100644 (file)
--- a/embed.fnc
+++ b/embed.fnc
@@ -1687,6 +1687,9 @@ p |void   |offer_nice_chunk       |NN void *chunk|U32 chunk_size
 Apnod  |int    |my_sprintf     |NN char *buffer|NN const char *pat|...
 #endif
 
+Apnod  |int    |my_snprintf    |NN char *buffer|const Size_t len|NN const char *format|...
+Apnod  |int    |my_vsnprintf   |NN char *buffer|const Size_t len|NN const char *format|va_list ap
+
 px     |void   |my_clearenv
 
 #ifdef PERL_IMPLICIT_CONTEXT
index 49c90bf..dfe7eda 100644 (file)
@@ -713,5 +713,7 @@ Perl_ckwarn
 Perl_ckwarn_d
 Perl_new_warnings_bitfield
 Perl_my_sprintf
+Perl_my_snprintf
+Perl_my_vsnprintf
 Perl_my_cxt_init
 # ex: set ro:
diff --git a/perl.h b/perl.h
index f83cbf8..91e1b58 100644 (file)
--- a/perl.h
+++ b/perl.h
@@ -1449,6 +1449,9 @@ int sockatmark(int);
 #  define my_sprintf Perl_my_sprintf
 #endif
 
+#define my_snprintf  Perl_my_snprintf
+#define my_vsnprintf Perl_my_vsnprintf
+
 /* Configure gets this right but the UTS compiler gets it wrong.
    -- Hal Morris <hom00@utsglobal.com> */
 #ifdef UTS
index 288159c..ad2570e 100644 (file)
--- a/perlio.c
+++ b/perlio.c
@@ -479,11 +479,7 @@ PerlIO_debug(const char *fmt, ...)
        /* 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));
-# ifdef USE_VSNPRINTF
-       const STRLEN len2 = vsnprintf(buffer+len, sizeof(buffer) - len, fmt, ap);
-# else
-       const STRLEN len2 = vsprintf(buffer+len, fmt, ap);
-# endif /* USE_VSNPRINTF */
+       const STRLEN len2 = my_vsnprintf(buffer+len, sizeof(buffer) - len, fmt, ap);
        PerlLIO_write(PL_perlio_debug_fd, buffer, len + len2);
 #else
        const char *s = CopFILE(PL_curcop);
@@ -5147,11 +5143,7 @@ int
 PerlIO_vsprintf(char *s, int n, const char *fmt, va_list ap)
 {
     dVAR;
-#ifdef USE_VSNPRINTF
-    const int val = vsnprintf(s, n > 0 ? n : 0, fmt, ap);
-#else
-    const int val = vsprintf(s, fmt, ap);
-#endif /* #ifdef USE_VSNPRINTF */
+    const int val = my_vsnprintf(s, n > 0 ? n : 0, fmt, ap);
     if (n >= 0) {
        if (strlen(s) >= (STRLEN) n) {
            dTHX;
index d608eef..c3b6074 100644 (file)
@@ -2245,6 +2245,19 @@ Fill the sv with current working directory
 =for hackers
 Found in file util.c
 
+=item my_snprintf
+X<my_snprintf>
+
+The C library C<snprintf> functionality, if available and
+standards-compliant (uses C<vsnprintf>, actually).  If the
+C<vsnprintf> is not available, will unfortunately use the unsafe
+C<vsprintf>.  Consider using C<sv_vcatpvf> instead.
+
+       int     my_snprintf(char *buffer, const Size_t len, const char *format, ...)
+
+=for hackers
+Found in file util.c
+
 =item my_sprintf
 X<my_sprintf>
 
@@ -2257,6 +2270,18 @@ need the wrapper function - usually this is a direct call to C<sprintf>.
 =for hackers
 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.
+
+       int     my_vsnprintf(char *buffer, const Size_t len, const char *format, va_list ap)
+
+=for hackers
+Found in file util.c
+
 =item new_version
 X<new_version>
 
index d335281..55ffb19 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -831,11 +831,7 @@ PP(pp_formline)
            /* Formats aren't yet marked for locales, so assume "yes". */
            {
                STORE_NUMERIC_STANDARD_SET_LOCAL();
-#ifdef USE_SNPRINTF
-               snprintf(t, SvLEN(PL_formtarget) - (t - SvPVX(PL_formtarget)), fmt, (int) fieldsize, (int) arg & 255, value);
-#else
-               sprintf(t, fmt, (int) fieldsize, (int) arg & 255, value);
-#endif /* ifdef USE_SNPRINTF */
+               my_snprintf(t, SvLEN(PL_formtarget) - (t - SvPVX(PL_formtarget)), fmt, (int) fieldsize, (int) arg & 255, value);
                RESTORE_NUMERIC_STANDARD();
            }
            t += fieldsize;
@@ -2773,13 +2769,8 @@ Perl_sv_compile_2op(pTHX_ SV *sv, OP** startop, const char *code, PAD** padp)
        len = SvCUR(sv);
     }
     else
-#ifdef USE_SNPRINTF
-       len = snprintf(tmpbuf, sizeof(tbuf), "_<(%.10s_eval %lu)", code,
-                      (unsigned long)++PL_evalseq);
-#else
-       len = my_sprintf(tmpbuf, "_<(%.10s_eval %lu)", code,
-                        (unsigned long)++PL_evalseq);
-#endif /* ifdef USE_SNPRINTF */
+       len = my_snprintf(tmpbuf, sizeof(tbuf), "_<(%.10s_eval %lu)", code,
+                         (unsigned long)++PL_evalseq);
     SAVECOPFILE_FREE(&PL_compiling);
     CopFILE_set(&PL_compiling, tmpbuf+2);
     SAVECOPLINE(&PL_compiling);
@@ -3461,11 +3452,7 @@ PP(pp_entereval)
        len = SvCUR(temp_sv);
     }
     else
-#ifdef USE_SNPRINTF
-       len = snprintf(tmpbuf, sizeof(tbuf), "_<(eval %lu)", (unsigned long)++PL_evalseq);
-#else
-       len = my_sprintf(tmpbuf, "_<(eval %lu)", (unsigned long)++PL_evalseq);
-#endif /* ifdef USE_SNPRINTF */
+       len = my_snprintf(tmpbuf, sizeof(tbuf), "_<(eval %lu)", (unsigned long)++PL_evalseq);
     SAVECOPFILE_FREE(&PL_compiling);
     CopFILE_set(&PL_compiling, tmpbuf+2);
     SAVECOPLINE(&PL_compiling);
diff --git a/proto.h b/proto.h
index 43a749a..07ee72d 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -4335,6 +4335,15 @@ PERL_CALLCONV int        Perl_my_sprintf(char *buffer, const char *pat, ...)
 
 #endif
 
+PERL_CALLCONV int      Perl_my_snprintf(char *buffer, const Size_t len, const char *format, ...)
+                       __attribute__nonnull__(1)
+                       __attribute__nonnull__(3);
+
+PERL_CALLCONV int      Perl_my_vsnprintf(char *buffer, const Size_t len, const char *format, va_list ap)
+                       __attribute__nonnull__(1)
+                       __attribute__nonnull__(3);
+
+
 PERL_CALLCONV void     Perl_my_clearenv(pTHX);
 
 #ifdef PERL_IMPLICIT_CONTEXT
index 6ba85bb..e98fcf9 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -6184,11 +6184,7 @@ Perl_save_re_context(pTHX)
            U32 i;
            for (i = 1; i <= rx->nparens; i++) {
                char digits[TYPE_CHARS(long)];
-#ifdef USE_SNPRINTF
-               const STRLEN len = snprintf(digits, sizeof(digits), "%lu", (long)i);
-#else
-               const STRLEN len = my_sprintf(digits, "%lu", (long)i);
-#endif /* #ifdef USE_SNPRINTF */
+               const STRLEN len = my_snprintf(digits, sizeof(digits), "%lu", (long)i);
                GV *const *const gvp
                    = (GV**)hv_fetch(PL_defstash, digits, len, 0);
 
diff --git a/sv.c b/sv.c
index 6c7071d..37c84f4 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -2660,13 +2660,8 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
 
            if (SvIOKp(sv)) {
                len = SvIsUV(sv)
-#ifdef USE_SNPRINTF
-                   ? snprintf(tbuf, sizeof(tbuf), "%"UVuf, (UV)SvUVX(sv))
-                   : snprintf(tbuf, sizeof(tbuf), "%"IVdf, (IV)SvIVX(sv));
-#else
-                   ? my_sprintf(tbuf, "%"UVuf, (UV)SvUVX(sv))
-                   : my_sprintf(tbuf, "%"IVdf, (IV)SvIVX(sv));
-#endif /* #ifdef USE_SNPRINTF */
+                   ? my_snprintf(tbuf, sizeof(tbuf), "%"UVuf, (UV)SvUVX(sv))
+                   : my_snprintf(tbuf, sizeof(tbuf), "%"IVdf, (IV)SvIVX(sv));
            } else {
                Gconvert(SvNVX(sv), NV_DIG, 0, tbuf);
                len = strlen(tbuf);
@@ -9270,13 +9265,8 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                 * --jhi */
 #if defined(HAS_LONG_DOUBLE)
                elen = ((intsize == 'q')
-# ifdef USE_SNPRINTF
-                       ? snprintf(PL_efloatbuf, PL_efloatsize, ptr, nv)
-                       : snprintf(PL_efloatbuf, PL_efloatsize, ptr, (double)nv));
-# else
-                       ? my_sprintf(PL_efloatbuf, ptr, nv)
-                       : my_sprintf(PL_efloatbuf, ptr, (double)nv));
-# endif /* #ifdef USE_SNPRINTF */
+                       ? my_snprintf(PL_efloatbuf, PL_efloatsize, ptr, nv)
+                       : my_snprintf(PL_efloatbuf, PL_efloatsize, ptr, (double)nv));
 #else
                elen = my_sprintf(PL_efloatbuf, ptr, nv);
 #endif
diff --git a/toke.c b/toke.c
index 173474c..9e340ba 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -5976,11 +5976,7 @@ Perl_yylex(pTHX)
                if (!PL_in_my_stash) {
                    char tmpbuf[1024];
                    PL_bufptr = s;
-#ifdef USE_SNPRINTF
-                   snprintf(tmpbuf, sizeof(tmpbuf), "No such class %.1000s", PL_tokenbuf);
-#else
-                   sprintf(tmpbuf, "No such class %.1000s", PL_tokenbuf);
-#endif /* #ifdef USE_SNPRINTF */
+                   my_snprintf(tmpbuf, sizeof(tmpbuf), "No such class %.1000s", PL_tokenbuf);
                    yyerror(tmpbuf);
                }
 #ifdef PERL_MAD
index 21f2c54..266613e 100644 (file)
@@ -622,11 +622,7 @@ XS(XS_version_qv)
            if ( SvNOK(ver) ) /* may get too much accuracy */
            {
                char tbuf[64];
-#ifdef USE_SNPRINTF
-               const STRLEN len = snprintf(tbuf, sizeof(tbuf), "%.9"NVgf, SvNVX(ver));
-#else
-               const STRLEN len = my_sprintf(tbuf, "%.9"NVgf, SvNVX(ver));
-#endif /* #ifdef USE_SNPRINTF  */
+               const STRLEN len = my_snprintf(tbuf, sizeof(tbuf), "%.9"NVgf, SvNVX(ver));
                version = savepvn(tbuf, len);
            }
            else
diff --git a/util.c b/util.c
index fb461cc..82f7f82 100644 (file)
--- a/util.c
+++ b/util.c
@@ -4294,11 +4294,7 @@ Perl_upg_version(pTHX_ SV *ver)
     if ( SvNOK(ver) ) /* may get too much accuracy */ 
     {
        char tbuf[64];
-#ifdef USE_SNPRINTF
-       const STRLEN len = snprintf(tbuf, sizeof(tbuf), "%.9"NVgf, SvNVX(ver));
-#else
-       const STRLEN len = my_sprintf(tbuf, "%.9"NVgf, SvNVX(ver));
-#endif /* #ifdef USE_SNPRINTF */
+       const STRLEN len = my_snprintf(tbuf, sizeof(tbuf), "%.9"NVgf, SvNVX(ver));
        version = savepvn(tbuf, len);
     }
 #ifdef SvVOK
@@ -5215,38 +5211,21 @@ Perl_mem_log_alloc(const UV n, const UV typesize, const char *typename, Malloc_t
        gettimeofday(&tv, 0);
        {
            const STRLEN len =
-#  ifdef USE_SNPRINTF
-               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
-               my_sprintf(buf,
-                          "%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));
-#  endif
+               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 =
-#  ifdef USE_SNPRINTF
-               snprintf(buf,
-                        PERL_MEM_LOG_SPRINTF_BUF_SIZE,
-                        "alloc: %s:%d:%s: %"IVdf" %"UVuf
-                        " %s = %"IVdf": %"UVxf"\n",
-                        filename, linenumber, funcname, n, typesize,
-                        typename, n * typesize, PTR2UV(newalloc));
-#  else
-               my_sprintf(buf,
-                          "alloc: %s:%d:%s: %"IVdf" %"UVuf
-                          " %s = %"IVdf": %"UVxf"\n",
-                          filename, linenumber, funcname, n, typesize,
-                          typename, n * typesize, PTR2UV(newalloc));
-#  endif
+               my_snprintf(buf,
+                           PERL_MEM_LOG_SPRINTF_BUF_SIZE,
+                           "alloc: %s:%d:%s: %"IVdf" %"UVuf
+                           " %s = %"IVdf": %"UVxf"\n",
+                           filename, linenumber, funcname, n, typesize,
+                           typename, n * typesize, PTR2UV(newalloc));
 # endif
 # ifdef PERL_MEM_LOG_ENV_FD
            s = PerlEnv_getenv("PERL_MEM_LOG_FD");
@@ -5280,42 +5259,23 @@ Perl_mem_log_realloc(const UV n, const UV typesize, const char *typename, Malloc
        gettimeofday(&tv, 0);
        {
            const STRLEN len =
-#  ifdef USE_SNPRINTF
-               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
-               my_sprintf(buf,
-                          "%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));
-#  endif
+               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 =
-#  ifdef USE_SNPRINTF
-               snprintf(buf,
-                        PERL_MEM_LOG_SPRINTF_BUF_SIZE,
-                        "realloc: %s:%d:%s: %"IVdf" %"UVuf
-                        " %s = %"IVdf": %"UVxf" -> %"UVxf"\n",
-                        filename, linenumber, funcname, n, typesize,
-                        typename, n * typesize, PTR2UV(oldalloc),
-                        PTR2UV(newalloc));
-#  else
-               my_sprintf(buf,
-                          "realloc: %s:%d:%s: %"IVdf" %"UVuf
-                          " %s = %"IVdf": %"UVxf" -> %"UVxf"\n",
-                          filename, linenumber, funcname, n, typesize,
-                          typename, n * typesize, PTR2UV(oldalloc),
-                          PTR2UV(newalloc));
-#  endif
+               my_snprintf(buf,
+                           PERL_MEM_LOG_SPRINTF_BUF_SIZE,
+                           "realloc: %s:%d:%s: %"IVdf" %"UVuf
+                           " %s = %"IVdf": %"UVxf" -> %"UVxf"\n",
+                           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");
@@ -5349,20 +5309,12 @@ Perl_mem_log_free(Malloc_t oldalloc, const char *filename, const int linenumber,
        gettimeofday(&tv, 0);
        {
            const STRLEN len =
-#  ifdef USE_SNPRINTF
-               snprintf(buf,
-                        PERL_MEM_LOG_SPRINTF_BUF_SIZE,
-                        "%10d.%06d: free: %s:%d:%s: %"UVxf"\n",
-                        (int)tv.tv_sec, (int)tv.tv_usec,
-                        filename, linenumber, funcname,
-                        PTR2UV(oldalloc));
-#  else
-               my_sprintf(buf,
-                          "%10d.%06d: free: %s:%d:%s: %"UVxf"\n",
-                          (int)tv.tv_sec, (int)tv.tv_usec,
-                          filename, linenumber, funcname,
-                          PTR2UV(oldalloc));
-#  endif
+               my_snprintf(buf,
+                           PERL_MEM_LOG_SPRINTF_BUF_SIZE,
+                           "%10d.%06d: free: %s:%d:%s: %"UVxf"\n",
+                           (int)tv.tv_sec, (int)tv.tv_usec,
+                           filename, linenumber, funcname,
+                           PTR2UV(oldalloc));
 # else
            const STRLEN len =
                my_sprintf(buf,
@@ -5405,6 +5357,72 @@ Perl_my_sprintf(char *buffer, const char* pat, ...)
 }
 #endif
 
+/*
+=for apidoc my_snprintf
+
+The C library C<snprintf> functionality, if available and
+standards-compliant (uses C<vsnprintf>, actually).  If the
+C<vsnprintf> is not available, will unfortunately use the unsafe
+C<vsprintf>.  Consider using C<sv_vcatpvf> instead.
+
+=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
+    retval = vsnprintf(buffer, len, format, ap);
+#else
+    retval = vsprintf(buffer, format, ap);
+#endif
+    va_end(ap);
+    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.
+
+=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
+    retval = vsnprintf(buffer, len, format, apc);
+# else
+    retval = vsprintf(buffer, format, apc);
+# endif
+#else
+# ifdef USE_VSNPRINTF
+    retval = vsnprintf(buffer, len, format, ap);
+# else
+    retval = vsprintf(buffer, format, ap);
+# endif
+#endif
+    return retval;
+}
+
 void
 Perl_my_clearenv(pTHX)
 {