diff options
author | Father Chrysostomos <sprout@cpan.org> | 2012-04-16 20:24:45 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2012-04-16 20:24:45 -0700 |
commit | 78e230aef16bcd45dba3b038bb0883d528a495bd (patch) | |
tree | 65ca2bc430be792fa554a2d7ecabc92de9d70337 /util.c | |
parent | 04bd644859054f7d9eeb94b6c7a3e2b76872a6ab (diff) | |
download | perl-78e230aef16bcd45dba3b038bb0883d528a495bd.tar.gz |
[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.
Diffstat (limited to 'util.c')
-rw-r--r-- | util.c | 18 |
1 files changed, 14 insertions, 4 deletions
@@ -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 */ |