summaryrefslogtreecommitdiff
path: root/doop.c
diff options
context:
space:
mode:
authorHugo van der Sanden <hv@crypt.org>2015-02-08 13:53:00 +0000
committerHugo van der Sanden <hv@crypt.org>2015-02-09 12:03:03 +0000
commita53bfdae91fb2d719e69761f2d2f84c5d8a47753 (patch)
tree4e758edfc701e2cd2d1090c730c44dd49a756af1 /doop.c
parent7aa8cb0dec173dcfca4157e60634c74b97429a05 (diff)
downloadperl-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.c40
1 files changed, 14 insertions, 26 deletions
diff --git a/doop.c b/doop.c
index 2bd4e13f14..47fea2803a 100644
--- a/doop.c
+++ b/doop.c
@@ -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);
}
}