diff options
author | David Mitchell <davem@iabyn.com> | 2016-11-02 16:05:54 +0000 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2016-11-02 16:26:24 +0000 |
commit | c73f612f8535d5db75d096a430a7938ce1c28a10 (patch) | |
tree | 633a960e10a0b6344c52216c52a0426b66fc58ee /pp_hot.c | |
parent | 9ce5bf4c39e28441410672f39b5ee1c4569967f8 (diff) | |
download | perl-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.c | 7 |
1 files changed, 7 insertions, 0 deletions
@@ -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(); |