diff options
author | Hugo van der Sanden <hv@crypt.org> | 2015-02-08 13:53:00 +0000 |
---|---|---|
committer | Hugo van der Sanden <hv@crypt.org> | 2015-02-09 12:03:03 +0000 |
commit | a53bfdae91fb2d719e69761f2d2f84c5d8a47753 (patch) | |
tree | 4e758edfc701e2cd2d1090c730c44dd49a756af1 /doop.c | |
parent | 7aa8cb0dec173dcfca4157e60634c74b97429a05 (diff) | |
download | perl-a53bfdae91fb2d719e69761f2d2f84c5d8a47753.tar.gz |
[perl #123759] always count on OPpTRANS_IDENTICAL
If we detect that an in-place transliteration will not result in any
changes to the string, we set OPpTRANS_IDENTICAL and skip the normal
checks for readonlyness; but if we do that, we must make sure to use
the same logic to decide which transliteration strategy to use, or
we may end up trying to write to the readonly string anyway.
This resulted in several ways to hit assert failures, found by AFL
(<http://lcamtuf.coredump.cx/afl>).
Diffstat (limited to 'doop.c')
-rw-r--r-- | doop.c | 40 |
1 files changed, 14 insertions, 26 deletions
@@ -619,18 +619,18 @@ I32 Perl_do_trans(pTHX_ SV *sv) { STRLEN len; - const I32 hasutf = (PL_op->op_private & - (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF)); + const I32 flags = PL_op->op_private; + const I32 hasutf = flags & (OPpTRANS_FROM_UTF | OPpTRANS_TO_UTF); PERL_ARGS_ASSERT_DO_TRANS; - if (SvREADONLY(sv) && !(PL_op->op_private & OPpTRANS_IDENTICAL)) { - Perl_croak_no_modify(); + if (SvREADONLY(sv) && !(flags & OPpTRANS_IDENTICAL)) { + Perl_croak_no_modify(); } (void)SvPV_const(sv, len); if (!len) return 0; - if (!(PL_op->op_private & OPpTRANS_IDENTICAL)) { + if (!(flags & OPpTRANS_IDENTICAL)) { if (!SvPOKp(sv) || SvTHINKFIRST(sv)) (void)SvPV_force_nomg(sv, len); (void)SvPOK_only_UTF8(sv); @@ -638,27 +638,15 @@ Perl_do_trans(pTHX_ SV *sv) DEBUG_t( Perl_deb(aTHX_ "2.TBL\n")); - switch (PL_op->op_private & ~hasutf & ( - OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF|OPpTRANS_IDENTICAL| - OPpTRANS_SQUASH|OPpTRANS_DELETE|OPpTRANS_COMPLEMENT)) { - case 0: - if (hasutf) - return do_trans_simple_utf8(sv); - else - return do_trans_simple(sv); - - case OPpTRANS_IDENTICAL: - case OPpTRANS_IDENTICAL|OPpTRANS_COMPLEMENT: - if (hasutf) - return do_trans_count_utf8(sv); - else - return do_trans_count(sv); - - default: - if (hasutf) - return do_trans_complex_utf8(sv); - else - return do_trans_complex(sv); + /* If we use only OPpTRANS_IDENTICAL to bypass the READONLY check, + * we must also rely on it to choose the readonly strategy. + */ + if (flags & OPpTRANS_IDENTICAL) { + return hasutf ? do_trans_count_utf8(sv) : do_trans_count(sv); + } else if (flags & (OPpTRANS_SQUASH|OPpTRANS_DELETE|OPpTRANS_COMPLEMENT)) { + return hasutf ? do_trans_complex_utf8(sv) : do_trans_complex(sv); + } else { + return hasutf ? do_trans_simple_utf8(sv) : do_trans_simple(sv); } } |