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
