In perl.git, the branch blead has been updated

<http://perl5.git.perl.org/perl.git/commitdiff/78e230aef16bcd45dba3b038bb0883d528a495bd?hp=04bd644859054f7d9eeb94b6c7a3e2b76872a6ab>

- Log -----------------------------------------------------------------
commit 78e230aef16bcd45dba3b038bb0883d528a495bd
Author: Father Chrysostomos <[email protected]>
Date:   Mon Apr 16 20:24:45 2012 -0700

    [perl #112478] Avoid buffer overflow in upg_version
    
    On most systems, this is actually a panic, rather than an overflow,
    because the overflow is detected before it can happen.
    
    upg_version needs to use the equivalent of sprintf "%.9f" on a numeric
    input before parsing it.  For speed’s sake, I assume, it was done
    using my_snprintf, with a C auto for the buffer, declared with a fixed
    size of 64.
    
    There is no guarantee that the number passed in will not overflow that
    buffer, so upg_version should use an SV and sv_catpvf in those cases
    where it would overflow.
-----------------------------------------------------------------------

Summary of changes:
 lib/version/t/coretests.pm |   10 ++++++++++
 util.c                     |   18 ++++++++++++++----
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/lib/version/t/coretests.pm b/lib/version/t/coretests.pm
index 6d2b4c1..bd098b2 100644
--- a/lib/version/t/coretests.pm
+++ b/lib/version/t/coretests.pm
@@ -584,6 +584,16 @@ SKIP: {
        }
        pass('no crash with version->new($tied) where $tied returns "version"');
     }
+
+    { # [perl #112478]
+       $_112478::VERSION = 9e99;
+       ok eval { _112478->VERSION(9e99); 1 }, '->VERSION(9e99) succeeds'
+           or diag $@;
+       $_112478::VERSION = 1;
+       eval { _112478->VERSION(9e99) };
+       like $@, qr/this is only/,
+           '->VERSION(9e99) fails with the right error';
+    }
 }
 
 1;
diff --git a/util.c b/util.c
index e6b5fa5..c7ddd73 100644
--- a/util.c
+++ b/util.c
@@ -4959,18 +4959,28 @@ Perl_upg_version(pTHX_ SV *ver, bool qv)
 
        /* may get too much accuracy */ 
        char tbuf[64];
+       SV *sv = SvNVX(ver) > 10e50 ? newSV(64) : 0;
+       char *buf;
 #ifdef USE_LOCALE_NUMERIC
        char *loc = savepv(setlocale(LC_NUMERIC, NULL));
        setlocale(LC_NUMERIC, "C");
 #endif
-       len = my_snprintf(tbuf, sizeof(tbuf), "%.9"NVff, SvNVX(ver));
+       if (sv) {
+           Perl_sv_catpvf(aTHX_ sv, "%.9"NVff, SvNVX(ver));
+           buf = SvPV(sv, len);
+       }
+       else {
+           len = my_snprintf(tbuf, sizeof(tbuf), "%.9"NVff, SvNVX(ver));
+           buf = tbuf;
+       }
 #ifdef USE_LOCALE_NUMERIC
        setlocale(LC_NUMERIC, loc);
        Safefree(loc);
 #endif
-       while (tbuf[len-1] == '0' && len > 0) len--;
-       if ( tbuf[len-1] == '.' ) len--; /* eat the trailing decimal */
-       version = savepvn(tbuf, len);
+       while (buf[len-1] == '0' && len > 0) len--;
+       if ( buf[len-1] == '.' ) len--; /* eat the trailing decimal */
+       version = savepvn(buf, len);
+       SvREFCNT_dec(sv);
     }
 #ifdef SvVOK
     else if ( (mg = SvVSTRING_mg(ver)) ) { /* already a v-string */

--
Perl5 Master Repository

Reply via email to