Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
80.00% |
64 / 80 |
|
83.33% |
15 / 18 |
CRAP | |
0.00% |
0 / 1 |
FunctionCausedByLines | |
80.00% |
64 / 80 |
|
83.33% |
15 / 18 |
73.63 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getGenericLines | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addGenericLines | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setGenericLines | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addParamSinkLines | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
addParamPreservedLines | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
setParamSinkLines | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setParamPreservedLines | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setVariadicParamSinkLines | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setVariadicParamPreservedLines | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
addVariadicParamSinkLines | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
addVariadicParamPreservedLines | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
getParamSinkLines | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
5 | |||
getParamPreservedLines | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
5 | |||
mergeWith | |
84.00% |
21 / 25 |
|
0.00% |
0 / 1 |
14.80 | |||
__clone | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
toString | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
30 | |||
__toString | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php declare( strict_types=1 ); |
2 | |
3 | namespace SecurityCheckPlugin; |
4 | |
5 | /** |
6 | * This class represents caused-by lines for a function-like: |
7 | * - Lines in genericLines are for taintedness that is added inside the function, regardless of parameters; these |
8 | * have a Taintedness object associated, while the associated links are always empty. |
9 | * - Lines in (variadic)paramSinkLines are those inside a function that EXEC the arguments. These also have a |
10 | * Taintedness object associated, and no links. |
11 | * - Lines in (variadic)paramPreservedLines are responsible for putting a parameter inside the return value. These have |
12 | * a safe Taintedness associated, and usually non-empty links. |
13 | */ |
14 | class FunctionCausedByLines { |
15 | /** @var CausedByLines */ |
16 | private $genericLines; |
17 | /** @var CausedByLines[] */ |
18 | private $paramSinkLines = []; |
19 | /** @var CausedByLines[] */ |
20 | private $paramPreservedLines = []; |
21 | /** @var int|null Index of a variadic parameter, if any */ |
22 | private $variadicParamIndex; |
23 | /** @var CausedByLines|null */ |
24 | private $variadicParamSinkLines; |
25 | /** @var CausedByLines|null */ |
26 | private $variadicParamPreservedLines; |
27 | |
28 | public function __construct() { |
29 | $this->genericLines = new CausedByLines(); |
30 | } |
31 | |
32 | /** |
33 | * @return CausedByLines |
34 | * @suppress PhanUnreferencedPublicMethod |
35 | */ |
36 | public function getGenericLines(): CausedByLines { |
37 | return $this->genericLines; |
38 | } |
39 | |
40 | /** |
41 | * @param string[] $lines |
42 | * @param Taintedness $taint |
43 | * @param MethodLinks|null $links |
44 | */ |
45 | public function addGenericLines( array $lines, Taintedness $taint, MethodLinks $links = null ): void { |
46 | $this->genericLines->addLines( $lines, $taint, $links ); |
47 | } |
48 | |
49 | /** |
50 | * @param CausedByLines $lines |
51 | */ |
52 | public function setGenericLines( CausedByLines $lines ): void { |
53 | $this->genericLines = $lines; |
54 | } |
55 | |
56 | /** |
57 | * @param int $param |
58 | * @param string[] $lines |
59 | * @param Taintedness $taint |
60 | */ |
61 | public function addParamSinkLines( int $param, array $lines, Taintedness $taint ): void { |
62 | assert( $param !== $this->variadicParamIndex ); |
63 | if ( !isset( $this->paramSinkLines[$param] ) ) { |
64 | $this->paramSinkLines[$param] = new CausedByLines(); |
65 | } |
66 | $this->paramSinkLines[$param]->addLines( $lines, $taint ); |
67 | } |
68 | |
69 | /** |
70 | * @param int $param |
71 | * @param string[] $lines |
72 | * @param Taintedness $taint |
73 | * @param MethodLinks|null $links |
74 | */ |
75 | public function addParamPreservedLines( |
76 | int $param, |
77 | array $lines, |
78 | Taintedness $taint, |
79 | MethodLinks $links = null |
80 | ): void { |
81 | assert( $param !== $this->variadicParamIndex ); |
82 | if ( !isset( $this->paramPreservedLines[$param] ) ) { |
83 | $this->paramPreservedLines[$param] = new CausedByLines(); |
84 | } |
85 | $this->paramPreservedLines[$param]->addLines( $lines, $taint, $links ); |
86 | } |
87 | |
88 | /** |
89 | * @param int $param |
90 | * @param CausedByLines $lines |
91 | */ |
92 | public function setParamSinkLines( int $param, CausedByLines $lines ): void { |
93 | $this->paramSinkLines[$param] = $lines; |
94 | } |
95 | |
96 | /** |
97 | * @param int $param |
98 | * @param CausedByLines $lines |
99 | */ |
100 | public function setParamPreservedLines( int $param, CausedByLines $lines ): void { |
101 | $this->paramPreservedLines[$param] = $lines; |
102 | } |
103 | |
104 | /** |
105 | * @param int $param |
106 | * @param CausedByLines $lines |
107 | */ |
108 | public function setVariadicParamSinkLines( int $param, CausedByLines $lines ): void { |
109 | $this->variadicParamIndex = $param; |
110 | $this->variadicParamSinkLines = $lines; |
111 | } |
112 | |
113 | /** |
114 | * @param int $param |
115 | * @param CausedByLines $lines |
116 | */ |
117 | public function setVariadicParamPreservedLines( int $param, CausedByLines $lines ): void { |
118 | $this->variadicParamIndex = $param; |
119 | $this->variadicParamPreservedLines = $lines; |
120 | } |
121 | |
122 | /** |
123 | * @param int $param |
124 | * @param string[] $lines |
125 | * @param Taintedness $taint |
126 | */ |
127 | public function addVariadicParamSinkLines( |
128 | int $param, |
129 | array $lines, |
130 | Taintedness $taint |
131 | ): void { |
132 | assert( !isset( $this->paramSinkLines[$param] ) && !isset( $this->paramPreservedLines[$param] ) ); |
133 | $this->variadicParamIndex = $param; |
134 | if ( !$this->variadicParamSinkLines ) { |
135 | $this->variadicParamSinkLines = new CausedByLines(); |
136 | } |
137 | $this->variadicParamSinkLines->addLines( $lines, $taint ); |
138 | } |
139 | |
140 | /** |
141 | * @param int $param |
142 | * @param string[] $lines |
143 | * @param Taintedness $taint |
144 | * @param MethodLinks|null $links |
145 | */ |
146 | public function addVariadicParamPreservedLines( |
147 | int $param, |
148 | array $lines, |
149 | Taintedness $taint, |
150 | MethodLinks $links = null |
151 | ): void { |
152 | assert( !isset( $this->paramSinkLines[$param] ) && !isset( $this->paramPreservedLines[$param] ) ); |
153 | $this->variadicParamIndex = $param; |
154 | if ( !$this->variadicParamPreservedLines ) { |
155 | $this->variadicParamPreservedLines = new CausedByLines(); |
156 | } |
157 | $this->variadicParamPreservedLines->addLines( $lines, $taint, $links ); |
158 | } |
159 | |
160 | /** |
161 | * @param int $param |
162 | * @return CausedByLines |
163 | */ |
164 | public function getParamSinkLines( int $param ): CausedByLines { |
165 | if ( isset( $this->paramSinkLines[$param] ) ) { |
166 | return $this->paramSinkLines[$param]; |
167 | } |
168 | if ( |
169 | $this->variadicParamIndex !== null && $param >= $this->variadicParamIndex && |
170 | $this->variadicParamSinkLines |
171 | ) { |
172 | return $this->variadicParamSinkLines; |
173 | } |
174 | return new CausedByLines(); |
175 | } |
176 | |
177 | /** |
178 | * @param int $param |
179 | * @return CausedByLines |
180 | */ |
181 | public function getParamPreservedLines( int $param ): CausedByLines { |
182 | if ( isset( $this->paramPreservedLines[$param] ) ) { |
183 | return $this->paramPreservedLines[$param]; |
184 | } |
185 | if ( |
186 | $this->variadicParamIndex !== null && $param >= $this->variadicParamIndex && |
187 | $this->variadicParamPreservedLines |
188 | ) { |
189 | return $this->variadicParamPreservedLines; |
190 | } |
191 | return new CausedByLines(); |
192 | } |
193 | |
194 | /** |
195 | * @param FunctionCausedByLines $other |
196 | * @param FunctionTaintedness $funcTaint To check NO_OVERRIDE |
197 | */ |
198 | public function mergeWith( self $other, FunctionTaintedness $funcTaint ): void { |
199 | if ( $funcTaint->canOverrideOverall() ) { |
200 | $this->genericLines->mergeWith( $other->genericLines ); |
201 | } |
202 | foreach ( $other->paramSinkLines as $param => $lines ) { |
203 | if ( $funcTaint->canOverrideNonVariadicParam( $param ) ) { |
204 | if ( isset( $this->paramSinkLines[$param] ) ) { |
205 | $this->paramSinkLines[$param]->mergeWith( $lines ); |
206 | } else { |
207 | $this->paramSinkLines[$param] = $lines; |
208 | } |
209 | } |
210 | } |
211 | foreach ( $other->paramPreservedLines as $param => $lines ) { |
212 | if ( $funcTaint->canOverrideNonVariadicParam( $param ) ) { |
213 | if ( isset( $this->paramPreservedLines[$param] ) ) { |
214 | $this->paramPreservedLines[$param]->mergeWith( $lines ); |
215 | } else { |
216 | $this->paramPreservedLines[$param] = $lines; |
217 | } |
218 | } |
219 | } |
220 | $variadicIndex = $other->variadicParamIndex; |
221 | if ( $variadicIndex !== null && $funcTaint->canOverrideVariadicParam() ) { |
222 | $this->variadicParamIndex = $variadicIndex; |
223 | $sinkVariadic = $other->variadicParamSinkLines; |
224 | if ( $sinkVariadic ) { |
225 | if ( $this->variadicParamSinkLines ) { |
226 | $this->variadicParamSinkLines->mergeWith( $sinkVariadic ); |
227 | } else { |
228 | $this->variadicParamSinkLines = $sinkVariadic; |
229 | } |
230 | } |
231 | $preserveVariadic = $other->variadicParamPreservedLines; |
232 | if ( $preserveVariadic ) { |
233 | if ( $this->variadicParamPreservedLines ) { |
234 | $this->variadicParamPreservedLines->mergeWith( $preserveVariadic ); |
235 | } else { |
236 | $this->variadicParamPreservedLines = $preserveVariadic; |
237 | } |
238 | } |
239 | } |
240 | } |
241 | |
242 | public function __clone() { |
243 | $this->genericLines = clone $this->genericLines; |
244 | foreach ( $this->paramSinkLines as $k => $pLines ) { |
245 | $this->paramSinkLines[$k] = clone $pLines; |
246 | } |
247 | if ( $this->variadicParamSinkLines ) { |
248 | $this->variadicParamSinkLines = clone $this->variadicParamSinkLines; |
249 | } |
250 | if ( $this->variadicParamPreservedLines ) { |
251 | $this->variadicParamPreservedLines = clone $this->variadicParamPreservedLines; |
252 | } |
253 | } |
254 | |
255 | /** |
256 | * @return string |
257 | */ |
258 | public function toString(): string { |
259 | $str = "{\nGeneric: " . $this->genericLines->toDebugString() . ",\n"; |
260 | foreach ( $this->paramSinkLines as $par => $lines ) { |
261 | $str .= "$par (sink): " . $lines->toDebugString() . ",\n"; |
262 | } |
263 | foreach ( $this->paramPreservedLines as $par => $lines ) { |
264 | $str .= "$par (preserved): " . $lines->toDebugString() . ",\n"; |
265 | } |
266 | if ( $this->variadicParamSinkLines ) { |
267 | $str .= "...{$this->variadicParamIndex} (sink): " . $this->variadicParamSinkLines->toDebugString() . "\n"; |
268 | } |
269 | if ( $this->variadicParamPreservedLines ) { |
270 | $str .= "...{$this->variadicParamIndex} (preserved): " . |
271 | $this->variadicParamPreservedLines->toDebugString() . "\n"; |
272 | } |
273 | return "$str}"; |
274 | } |
275 | |
276 | /** |
277 | * @return string |
278 | */ |
279 | public function __toString(): string { |
280 | return $this->toString(); |
281 | } |
282 | } |