This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
fix taint handling in list assignment
authorDavid Mitchell <davem@iabyn.com>
Wed, 2 Nov 2016 16:05:54 +0000 (16:05 +0000)
committerDavid Mitchell <davem@iabyn.com>
Wed, 2 Nov 2016 16:26:24 +0000 (16:26 +0000)
commitc73f612f8535d5db75d096a430a7938ce1c28a10
tree633a960e10a0b6344c52216c52a0426b66fc58ee
parent9ce5bf4c39e28441410672f39b5ee1c4569967f8
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.
pp_hot.c
t/op/taint.t