Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
41 / 41 |
|
100.00% |
23 / 23 |
CRAP | |
100.00% |
1 / 1 |
TaintednessAccessorsTrait | |
100.00% |
41 / 41 |
|
100.00% |
23 / 23 |
35 | |
100.00% |
1 / 1 |
getTaintednessRaw | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getTaintednessRawClone | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
setTaintednessRaw | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
getCausedByRaw | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCausedByRawCloneOrEmpty | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
getFuncCausedByRawCloneOrEmpty | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
setCausedByRaw | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
setFuncCausedByRaw | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getMethodLinks | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getMethodLinksCloneOrEmpty | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
setMethodLinks | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
getMethodLinksRef | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getVarLinks | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
ensureVarLinksForArgExist | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getTaintednessRef | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
setTaintednessRef | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
clearRefData | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
clearTaintError | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getFuncTaint | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
doSetFuncTaint | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getRetObjs | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
addRetObjs | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
initRetObjs | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 |
1 | <?php declare( strict_types=1 ); |
2 | |
3 | namespace SecurityCheckPlugin; |
4 | |
5 | use Phan\Language\Element\FunctionInterface; |
6 | use Phan\Language\Element\PassByReferenceVariable; |
7 | use Phan\Language\Element\TypedElementInterface; |
8 | |
9 | /** |
10 | * Accessors to read and write taintedness props stored inside phan objects. This trait exists to avoid duplicating |
11 | * dynamic property names, to have better type inference, to enable phan checks for undeclared props on the other |
12 | * files, to keep track of props usage etc. |
13 | * @phan-file-suppress PhanUndeclaredProperty |
14 | */ |
15 | trait TaintednessAccessorsTrait { |
16 | /** |
17 | * @param TypedElementInterface $element |
18 | * @return Taintedness|null |
19 | */ |
20 | protected static function getTaintednessRaw( TypedElementInterface $element ): ?Taintedness { |
21 | return $element->taintedness ?? null; |
22 | } |
23 | |
24 | /** |
25 | * @param TypedElementInterface $element |
26 | * @return Taintedness|null |
27 | * @suppress PhanUnreferencedProtectedMethod False positive |
28 | */ |
29 | protected static function getTaintednessRawClone( TypedElementInterface $element ): ?Taintedness { |
30 | // Performance: use isset(), not property_exists() |
31 | return isset( $element->taintedness ) ? clone $element->taintedness : null; |
32 | } |
33 | |
34 | /** |
35 | * @param TypedElementInterface $element |
36 | * @param Taintedness $taintedness |
37 | */ |
38 | protected static function setTaintednessRaw( TypedElementInterface $element, Taintedness $taintedness ): void { |
39 | $element->taintedness = $taintedness; |
40 | if ( $element instanceof PassByReferenceVariable ) { |
41 | self::setTaintednessRef( $element->getElement(), $taintedness ); |
42 | } |
43 | } |
44 | |
45 | /** |
46 | * @param TypedElementInterface $element |
47 | * @return CausedByLines|null |
48 | */ |
49 | protected static function getCausedByRaw( TypedElementInterface $element ): ?CausedByLines { |
50 | return $element->taintedOriginalError ?? null; |
51 | } |
52 | |
53 | /** |
54 | * @param TypedElementInterface $element |
55 | * @return CausedByLines |
56 | */ |
57 | protected static function getCausedByRawCloneOrEmpty( TypedElementInterface $element ): CausedByLines { |
58 | return isset( $element->taintedOriginalError ) ? clone $element->taintedOriginalError : new CausedByLines(); |
59 | } |
60 | |
61 | /** |
62 | * @param FunctionInterface $func |
63 | * @return FunctionCausedByLines |
64 | */ |
65 | protected static function getFuncCausedByRawCloneOrEmpty( FunctionInterface $func ): FunctionCausedByLines { |
66 | return isset( $func->funcTaintedOriginalError ) |
67 | ? clone $func->funcTaintedOriginalError |
68 | : new FunctionCausedByLines(); |
69 | } |
70 | |
71 | /** |
72 | * @param TypedElementInterface $element |
73 | * @param CausedByLines $lines |
74 | */ |
75 | protected static function setCausedByRaw( TypedElementInterface $element, CausedByLines $lines ): void { |
76 | $element->taintedOriginalError = $lines; |
77 | if ( $element instanceof PassByReferenceVariable ) { |
78 | $curCausedBy = self::getCausedByRaw( $element->getElement() ); |
79 | $newCausedBy = $curCausedBy ? $curCausedBy->asMergedWith( $lines ) : $lines; |
80 | self::setCausedByRaw( $element->getElement(), $newCausedBy ); |
81 | } |
82 | } |
83 | |
84 | /** |
85 | * @param FunctionInterface $func |
86 | * @param FunctionCausedByLines $lines |
87 | */ |
88 | protected static function setFuncCausedByRaw( FunctionInterface $func, FunctionCausedByLines $lines ): void { |
89 | $func->funcTaintedOriginalError = $lines; |
90 | } |
91 | |
92 | /** |
93 | * @note This doesn't return a clone |
94 | * |
95 | * @param TypedElementInterface $element |
96 | * @return MethodLinks|null |
97 | */ |
98 | protected static function getMethodLinks( TypedElementInterface $element ): ?MethodLinks { |
99 | return $element->taintedMethodLinks ?? null; |
100 | } |
101 | |
102 | /** |
103 | * @param TypedElementInterface $element |
104 | * @return MethodLinks |
105 | */ |
106 | protected static function getMethodLinksCloneOrEmpty( TypedElementInterface $element ): MethodLinks { |
107 | // Performance: use isset(), not property_exists() |
108 | return isset( $element->taintedMethodLinks ) ? clone $element->taintedMethodLinks : new MethodLinks(); |
109 | } |
110 | |
111 | /** |
112 | * @param TypedElementInterface $element |
113 | * @param MethodLinks $links |
114 | */ |
115 | protected static function setMethodLinks( TypedElementInterface $element, MethodLinks $links ): void { |
116 | $element->taintedMethodLinks = $links; |
117 | if ( $element instanceof PassByReferenceVariable ) { |
118 | $element->getElement()->taintedMethodLinksRef = $links; |
119 | } |
120 | } |
121 | |
122 | /** |
123 | * @param TypedElementInterface $element |
124 | * @return MethodLinks|null |
125 | */ |
126 | protected static function getMethodLinksRef( TypedElementInterface $element ): ?MethodLinks { |
127 | return $element->taintedMethodLinksRef ?? null; |
128 | } |
129 | |
130 | /** |
131 | * @param FunctionInterface $func |
132 | * @param int $index |
133 | * @return VarLinksSet|null |
134 | */ |
135 | protected static function getVarLinks( FunctionInterface $func, int $index ): ?VarLinksSet { |
136 | return $func->taintedVarLinks[$index] ?? null; |
137 | } |
138 | |
139 | /** |
140 | * @param TypedElementInterface $element |
141 | * @param int $arg |
142 | */ |
143 | protected static function ensureVarLinksForArgExist( TypedElementInterface $element, int $arg ): void { |
144 | $element->taintedVarLinks ??= []; |
145 | $element->taintedVarLinks[$arg] ??= new VarLinksSet; |
146 | } |
147 | |
148 | /** |
149 | * @param TypedElementInterface $element |
150 | * @return Taintedness|null |
151 | */ |
152 | protected static function getTaintednessRef( TypedElementInterface $element ): ?Taintedness { |
153 | // Performance: use isset(), not property_exists() |
154 | return isset( $element->taintednessRef ) ? clone $element->taintednessRef : null; |
155 | } |
156 | |
157 | /** |
158 | * @param TypedElementInterface $element |
159 | * @param Taintedness $taintedness |
160 | */ |
161 | protected static function setTaintednessRef( TypedElementInterface $element, Taintedness $taintedness ): void { |
162 | $element->taintednessRef = $taintedness; |
163 | } |
164 | |
165 | /** |
166 | * @param TypedElementInterface $element |
167 | */ |
168 | protected static function clearRefData( TypedElementInterface $element ): void { |
169 | unset( $element->taintednessRef, $element->taintedMethodLinksRef ); |
170 | } |
171 | |
172 | /** |
173 | * Clears any previous error on the given element. |
174 | * |
175 | * @param TypedElementInterface $elem |
176 | */ |
177 | protected static function clearTaintError( TypedElementInterface $elem ): void { |
178 | unset( $elem->taintedOriginalError ); |
179 | } |
180 | |
181 | /** |
182 | * Get $func's taint, or null if not set. NOTE: This doesn't create a clone. |
183 | * |
184 | * @param FunctionInterface $func |
185 | * @return FunctionTaintedness|null |
186 | */ |
187 | protected static function getFuncTaint( FunctionInterface $func ): ?FunctionTaintedness { |
188 | return $func->funcTaint ?? null; |
189 | } |
190 | |
191 | /** |
192 | * @param FunctionInterface $func |
193 | * @param FunctionTaintedness $funcTaint |
194 | */ |
195 | protected static function doSetFuncTaint( FunctionInterface $func, FunctionTaintedness $funcTaint ): void { |
196 | $func->funcTaint = $funcTaint; |
197 | } |
198 | |
199 | /** |
200 | * @param FunctionInterface $func |
201 | * @return TypedElementInterface[]|null |
202 | */ |
203 | protected static function getRetObjs( FunctionInterface $func ): ?array { |
204 | $funcNode = $func->getNode(); |
205 | if ( !$funcNode ) { |
206 | // If it has no node, it won't have any returned object, so don't return null, to avoid |
207 | // potential recursive analysis attempts. |
208 | return []; |
209 | } |
210 | return $funcNode->retObjs ?? null; |
211 | } |
212 | |
213 | /** |
214 | * @note These are saved in the function node so that they can be shared by all implementations, without |
215 | * having to check the defining FQSEN of a method and canonicalize $func for lookup. |
216 | * @param FunctionInterface $func |
217 | * @param TypedElementInterface[] $retObjs |
218 | * @suppress PhanUnreferencedProtectedMethod Used in TaintednessVisitor |
219 | */ |
220 | protected static function addRetObjs( FunctionInterface $func, array $retObjs ): void { |
221 | $funcNode = $func->getNode(); |
222 | if ( $funcNode ) { |
223 | $funcNode->retObjs = array_merge( $funcNode->retObjs ?? [], $retObjs ); |
224 | } |
225 | } |
226 | |
227 | /** |
228 | * @param FunctionInterface $func |
229 | */ |
230 | protected static function initRetObjs( FunctionInterface $func ): void { |
231 | $funcNode = $func->getNode(); |
232 | if ( $funcNode ) { |
233 | $funcNode->retObjs ??= []; |
234 | } |
235 | } |
236 | |
237 | } |