In perl.git, the branch blead has been updated <http://perl5.git.perl.org/perl.git/commitdiff/b3b27d017bd3d61f6cbc3eaf8465b8d98d86a024?hp=b9a07097bdb32335cd4963591c6f2d29bc6302a8>
- Log ----------------------------------------------------------------- commit b3b27d017bd3d61f6cbc3eaf8465b8d98d86a024 Author: David Mitchell <[email protected]> Date: Wed Mar 11 12:25:58 2015 +0000 repeat op: avoid integer overflows For the list variant of the x operator, the overflow detection code doesn't always work, resulting in the stack not being extended enough. There are two places where an overflow could occur: calculating how many stack items to extend by (items * count), and passing to repeatcpy() how many bytes to copy 'items' SV pointers (items * sizeof(const SV *)). The overflow detection was generally a mess; checking for overflow using a value (max) that may have already overflown; checking whether 'max' had overflown incorrectly, and not checking (items * sizeof(const SV *) at all (perhaps hoping that the other checks would be a superset of this). Also, some of the vars were still I32s; promote to 64-bit capable types. Finally, the signature of Perl_repeatcpy() still has an I32 len; that really should be changed to IV at some point; but for now I've just ensured that the callers (list 'x' and scalar 'x') don't wrap. I haven't put in a check for the only other core caller of repeatcpy(), S_study_chunk(), since that would only become an issue compiling a pattern with a fixed or floating substr within it of length > 2**31. ----------------------------------------------------------------------- Summary of changes: pp.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/pp.c b/pp.c index f795725..ec0f9d3 100644 --- a/pp.c +++ b/pp.c @@ -1717,17 +1717,19 @@ PP(pp_repeat) if (GIMME_V == G_ARRAY && PL_op->op_private & OPpREPEAT_DOLIST) { dMARK; - static const char* const oom_list_extend = "Out of memory during list extend"; - const I32 items = SP - MARK; - const I32 max = items * count; + const Size_t items = SP - MARK; const U8 mod = PL_op->op_flags & OPf_MOD; - MEM_WRAP_CHECK_1(max, SV*, oom_list_extend); - /* Did the max computation overflow? */ - if (items > 0 && max > 0 && (max < items || max < count)) - Perl_croak(aTHX_ "%s", oom_list_extend); - MEXTEND(MARK, max); if (count > 1) { + Size_t max; + + if ( items > MEM_SIZE_MAX / (UV)count /* max would overflow */ + || items > (U32)I32_MAX / sizeof(SV *) /* repeatcpy would overflow */ + ) + Perl_croak(aTHX_ "%s","Out of memory during list extend"); + max = items * count; + MEXTEND(MARK, max); + while (SP > MARK) { if (*SP) { if (mod && SvPADTMP(*SP)) { @@ -1749,8 +1751,6 @@ PP(pp_repeat) SV * const tmpstr = POPs; STRLEN len; bool isutf; - static const char* const oom_string_extend = - "Out of memory during string extend"; if (TARG != tmpstr) sv_setsv_nomg(TARG, tmpstr); @@ -1760,11 +1760,16 @@ PP(pp_repeat) if (count < 1) SvCUR_set(TARG, 0); else { - const STRLEN max = (UV)count * len; - if (len > MEM_SIZE_MAX / count) - Perl_croak(aTHX_ "%s", oom_string_extend); - MEM_WRAP_CHECK_1(max, char, oom_string_extend); - SvGROW(TARG, max + 1); + STRLEN max; + + if ( len > (MEM_SIZE_MAX-1) / (UV)count /* max would overflow */ + || len > (U32)I32_MAX /* repeatcpy would overflow */ + ) + Perl_croak(aTHX_ "%s", + "Out of memory during string extend"); + max = (UV)count * len + 1; + SvGROW(TARG, max); + repeatcpy(SvPVX(TARG) + len, SvPVX(TARG), len, count - 1); SvCUR_set(TARG, SvCUR(TARG) * count); } -- Perl5 Master Repository
