Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
TaintednessLoopVisitor
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 1
 visitForeach
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace SecurityCheckPlugin;
4
5use ast\Node;
6use Phan\PluginV3\BeforeLoopBodyAnalysisVisitor;
7
8class TaintednessLoopVisitor extends BeforeLoopBodyAnalysisVisitor {
9    use TaintednessBaseVisitor;
10
11    /**
12     * Visit a foreach loop
13     *
14     * We do that in this visitor so that we can handle the loop condition prior to
15     * determine the taint of the loop variable, prior to evaluating the loop body.
16     * See https://github.com/phan/phan/issues/3936
17     */
18    public function visitForeach( Node $node ): void {
19        $expr = $node->children['expr'];
20        $lhsTaintednessWithError = $this->getTaintedness( $expr );
21        $lhsTaintedness = $lhsTaintednessWithError->getTaintedness();
22        $lhsLinks = $lhsTaintednessWithError->getMethodLinks();
23
24        $value = $node->children['value'];
25        if ( $value->kind === \ast\AST_REF ) {
26            // TODO, this doesn't propagate the taint to the outer scope
27            // (FWIW, phan doesn't do much better with types, https://github.com/phan/phan/issues/4017)
28            $value = $value->children['var'];
29        }
30
31        $valueTaint = $lhsTaintedness->asValueFirstLevel();
32        $valueError = $lhsTaintednessWithError->getError()->asAllValueFirstLevel();
33        $valueLinks = $lhsLinks->asValueFirstLevel();
34        // TODO Actually compute this
35        $rhsIsArray = false;
36        // NOTE: As mentioned in test 'foreach', we won't be able to retroactively attribute
37        // the right taint to the value if we discover what the key is for the current iteration
38        $valueVisitor = new TaintednessAssignVisitor(
39            $this->code_base,
40            $this->context,
41            $valueTaint,
42            $valueError,
43            $valueLinks,
44            $valueTaint,
45            $valueLinks,
46            $rhsIsArray
47        );
48        $valueVisitor( $value );
49
50        $key = $node->children['key'] ?? null;
51        if ( $key instanceof Node ) {
52            $keyTaint = $lhsTaintedness->asKeyForForeach();
53            $keyError = $lhsTaintednessWithError->getError()->asAllKeyForForeach();
54            $keyLinks = $lhsLinks->asKeyForForeach();
55            $keyVisitor = new TaintednessAssignVisitor(
56                $this->code_base,
57                $this->context,
58                $keyTaint,
59                $keyError,
60                $keyLinks,
61                $keyTaint,
62                $keyLinks,
63                $rhsIsArray
64            );
65            $keyVisitor( $key );
66        }
67    }
68}