summaryrefslogtreecommitdiff
path: root/pp_hot.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2016-11-02 16:05:54 +0000
committerDavid Mitchell <davem@iabyn.com>2016-11-02 16:26:24 +0000
commitc73f612f8535d5db75d096a430a7938ce1c28a10 (patch)
tree633a960e10a0b6344c52216c52a0426b66fc58ee /pp_hot.c
parent9ce5bf4c39e28441410672f39b5ee1c4569967f8 (diff)
downloadperl-c73f612f8535d5db75d096a430a7938ce1c28a10.tar.gz
fix taint handling in list assignment
My recent commit v5.25.6-79-gb09ed99 reworked list assignment, and accidentally broke taint handling at the same time. The basic idea is that each element is independent; in: ($a, $b, ...) = ($tainted, $untainted, ...); $a should end up tainted, $b should end up untainted, the statement containing the assign should remain untainted, and if the statement was already tainted it shouldn't affect the assign. Surprisingly this is completely untested, which is why I failed to spot it when I broke it. Now fixed. In fact in addition I spotted something that had always been broken, and fixed that too: it was tainting the rest of the statement; in: (($a) = ($TAINT. "x")), ($b = $b . "x"); The taint in the list assign to $a was lingering to mess up and taint $b. Prior to v5.25.6-79-gb09ed99 , pp_assign looked roughly like: for (...each lhs elem...) { TAINT_NOT; switch (lhs type) { case scalar: assign a value to lhs; break; case SVt_PVAV: av_clear(); for (...each rhs elem...) sv = newSV(0); sv_setsv(sv, rhs_elem); av_store(av, i, sv); TAINT_NOT; } break; } case SVt_PVHV: ...similarly... } Commit v5.25.6-79-gb09ed99 accidentally removed *all* the TAINT_NOT's. This commit re-adds the first TAINT_NOT, but doesn't re-add the per-array/hash TAINT_NOT's, on the grounds that the aggregates are first emptied, so any elements being assigned to will be fresh and can't have taint magic attached, so calling mg_set() on them won't set the taint value to 1 even if PL_tainted is set. But this commit does add an extra TAINT_NOT *after* the outer loop, which is what I think is fixing a longstanding bug.
Diffstat (limited to 'pp_hot.c')
-rw-r--r--pp_hot.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/pp_hot.c b/pp_hot.c
index 068b902e31..3db6f5d897 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1321,6 +1321,8 @@ PP(pp_aassign)
bool alias = FALSE;
SV *lsv = *lelem++;
+ TAINT_NOT; /* Each item stands on its own, taintwise. */
+
assert(relem <= lastrelem);
if (UNLIKELY(!lsv)) {
alias = TRUE;
@@ -1731,6 +1733,9 @@ PP(pp_aassign)
/* simplified lelem loop for when there are no relems left */
while (LIKELY(lelem <= lastlelem)) {
SV *lsv = *lelem++;
+
+ TAINT_NOT; /* Each item stands on its own, taintwise. */
+
if (UNLIKELY(!lsv)) {
lsv = *lelem++;
ASSUME(SvTYPE(lsv) == SVt_PVAV);
@@ -1760,6 +1765,8 @@ PP(pp_aassign)
} /* switch */
} /* while */
+ TAINT_NOT; /* result of list assign isn't tainted */
+
if (UNLIKELY(PL_delaymagic & ~DM_DELAY)) {
/* Will be used to set PL_tainting below */
Uid_t tmp_uid = PerlProc_getuid();