Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
32 / 32
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
TaintednessLoopVisitor
100.00% covered (success)
100.00%
32 / 32
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
1 / 1
 visitForeach
100.00% covered (success)
100.00%
32 / 32
100.00% covered (success)
100.00%
1 / 1
3
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     * @param Node $node
19     */
20    public function visitForeach( Node $node ): void {
21        $expr = $node->children['expr'];
22        $lhsTaintednessWithError = $this->getTaintedness( $expr );
23        $lhsTaintedness = $lhsTaintednessWithError->getTaintedness();
24        $lhsLinks = $lhsTaintednessWithError->getMethodLinks();
25
26        $value = $node->children['value'];
27        if ( $value->kind === \ast\AST_REF ) {
28            // TODO, this doesn't propagate the taint to the outer scope
29            // (FWIW, phan doesn't do much better with types, https://github.com/phan/phan/issues/4017)
30            $value = $value->children['var'];
31        }
32
33        // TODO Actually compute this
34        $rhsIsArray = false;
35        // NOTE: As mentioned in test 'foreach', we won't be able to retroactively attribute
36        // the right taint to the value if we discover what the key is for the current iteration
37        $valueVisitor = new TaintednessAssignVisitor(
38            $this->code_base,
39            $this->context,
40            $lhsTaintedness->asValueFirstLevel(),
41            $lhsTaintednessWithError->getError(),
42            $lhsLinks->asValueFirstLevel(),
43            $lhsTaintedness->asValueFirstLevel(),
44            $lhsLinks,
45            $rhsIsArray
46        );
47        $valueVisitor( $value );
48
49        $key = $node->children['key'] ?? null;
50        if ( $key instanceof Node ) {
51            $keyVisitor = new TaintednessAssignVisitor(
52                $this->code_base,
53                $this->context,
54                $lhsTaintedness->asKeyForForeach(),
55                $lhsTaintednessWithError->getError(),
56                $lhsLinks->asKeyForForeach(),
57                $lhsTaintedness->asKeyForForeach(),
58                $lhsLinks,
59                $rhsIsArray
60            );
61            $keyVisitor( $key );
62        }
63    }
64}