Spaces:
Runtime error
Runtime error
Anuj-Panthri
commited on
Commit
•
d29be41
1
Parent(s):
32c8469
added tests for the TODOListController
Browse files- app/Http/Controllers/TODOListController.php +1 -0
- database/factories/ListItemFactory.php +25 -0
- pcov-1.0.11/package.xml +262 -0
- pcov-1.0.11/pcov-1.0.11/LICENSE +68 -0
- pcov-1.0.11/pcov-1.0.11/README.md +150 -0
- pcov-1.0.11/pcov-1.0.11/cfg/701/zend_cfg.c +595 -0
- pcov-1.0.11/pcov-1.0.11/cfg/701/zend_cfg.h +133 -0
- pcov-1.0.11/pcov-1.0.11/cfg/701/zend_worklist.h +137 -0
- pcov-1.0.11/pcov-1.0.11/cfg/702/zend_cfg.c +642 -0
- pcov-1.0.11/pcov-1.0.11/cfg/702/zend_cfg.h +139 -0
- pcov-1.0.11/pcov-1.0.11/cfg/702/zend_worklist.h +131 -0
- pcov-1.0.11/pcov-1.0.11/cfg/703/zend_cfg.c +643 -0
- pcov-1.0.11/pcov-1.0.11/cfg/703/zend_cfg.h +135 -0
- pcov-1.0.11/pcov-1.0.11/cfg/703/zend_worklist.h +129 -0
- pcov-1.0.11/pcov-1.0.11/cfg/704/zend_cfg.c +612 -0
- pcov-1.0.11/pcov-1.0.11/cfg/704/zend_cfg.h +128 -0
- pcov-1.0.11/pcov-1.0.11/cfg/704/zend_worklist.h +121 -0
- pcov-1.0.11/pcov-1.0.11/config.m4 +35 -0
- pcov-1.0.11/pcov-1.0.11/config.w32 +32 -0
- pcov-1.0.11/pcov-1.0.11/pcov.c +909 -0
- pcov-1.0.11/pcov-1.0.11/php_pcov.h +84 -0
- pcov-1.0.11/pcov-1.0.11/tests/001.phpt +38 -0
- pcov-1.0.11/pcov-1.0.11/tests/002.phpt +49 -0
- pcov-1.0.11/pcov-1.0.11/tests/003.phpt +16 -0
- pcov-1.0.11/pcov-1.0.11/tests/004.phpt +17 -0
- pcov-1.0.11/pcov-1.0.11/tests/005.phpt +29 -0
- pcov-1.0.11/pcov-1.0.11/tests/006.phpt +19 -0
- pcov-1.0.11/pcov-1.0.11/tests/007.phpt +39 -0
- tests/Feature/DatabaseTest.php +32 -0
- tests/Feature/TODOListControllerTest.php +75 -0
app/Http/Controllers/TODOListController.php
CHANGED
@@ -33,6 +33,7 @@ public function changeStatus($id,Request $request){
|
|
33 |
|
34 |
return redirect("/");
|
35 |
}
|
|
|
36 |
public function deleteItem(Request $request){
|
37 |
// \Log::info(json_encode($request->all()));
|
38 |
$listitem = ListItem::where("id",$request->id)->first();
|
|
|
33 |
|
34 |
return redirect("/");
|
35 |
}
|
36 |
+
|
37 |
public function deleteItem(Request $request){
|
38 |
// \Log::info(json_encode($request->all()));
|
39 |
$listitem = ListItem::where("id",$request->id)->first();
|
database/factories/ListItemFactory.php
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Database\Factories;
|
4 |
+
|
5 |
+
use Illuminate\Database\Eloquent\Factories\Factory;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Model>
|
9 |
+
*/
|
10 |
+
class ListItemFactory extends Factory
|
11 |
+
{
|
12 |
+
/**
|
13 |
+
* Define the model's default state.
|
14 |
+
*
|
15 |
+
* @return array<string, mixed>
|
16 |
+
*/
|
17 |
+
public function definition(): array
|
18 |
+
{
|
19 |
+
return [
|
20 |
+
//
|
21 |
+
'name' => $this->faker->name(),
|
22 |
+
'is_complete' => $this->faker->numberBetween($min = 0, $max = 1),
|
23 |
+
];
|
24 |
+
}
|
25 |
+
}
|
pcov-1.0.11/package.xml
ADDED
@@ -0,0 +1,262 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<package packagerversion="1.10.13" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
|
3 |
+
<name>pcov</name>
|
4 |
+
<channel>pecl.php.net</channel>
|
5 |
+
<summary>Code coverage driver</summary>
|
6 |
+
<description>A self contained php-code-coverage compatible driver for PHP.</description>
|
7 |
+
<lead>
|
8 |
+
<name>Joe Watkins</name>
|
9 |
+
<user>krakjoe</user>
|
10 |
+
<email>[email protected]</email>
|
11 |
+
<active>yes</active>
|
12 |
+
</lead>
|
13 |
+
<lead>
|
14 |
+
<name>Remi Collet</name>
|
15 |
+
<user>remi</user>
|
16 |
+
<email>[email protected]</email>
|
17 |
+
<active>yes</active>
|
18 |
+
</lead>
|
19 |
+
<date>2021-12-20</date>
|
20 |
+
<time>16:52:09</time>
|
21 |
+
<version>
|
22 |
+
<release>1.0.11</release>
|
23 |
+
<api>1.0.0</api>
|
24 |
+
</version>
|
25 |
+
<stability>
|
26 |
+
<release>stable</release>
|
27 |
+
<api>stable</api>
|
28 |
+
</stability>
|
29 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
30 |
+
<notes>
|
31 |
+
- Fix anonymous function coverage
|
32 |
+
</notes>
|
33 |
+
<contents>
|
34 |
+
<dir name="/">
|
35 |
+
<file md5sum="93f5486205626d6eba2d209b17bd193e" name="tests/001.phpt" role="test" />
|
36 |
+
<file md5sum="6b95706fb3f8dc5aa3d3bddf32a59f77" name="tests/002.phpt" role="test" />
|
37 |
+
<file md5sum="b3f1c66c5acdbf38f0e71bd4b68a113b" name="tests/003.phpt" role="test" />
|
38 |
+
<file md5sum="4a71f06f3c696ebba237f7cf384a6add" name="tests/004.phpt" role="test" />
|
39 |
+
<file md5sum="d01afd57c13e8d6c14eaba8f13580cfd" name="tests/005.phpt" role="test" />
|
40 |
+
<file md5sum="19ef5f87be894ea2e21741e11ff070e3" name="tests/006.phpt" role="test" />
|
41 |
+
<file md5sum="8a30bcf04d22dd4cedb596523fecd51d" name="tests/007.phpt" role="test" />
|
42 |
+
<file md5sum="dd62ffbecb188d3ba1dc2f1d75500471" name="cfg/701/zend_cfg.h" role="src" />
|
43 |
+
<file md5sum="87b970404e3031a02359d8a304a178cd" name="cfg/701/zend_cfg.c" role="src" />
|
44 |
+
<file md5sum="71191356d54ce9d0b092e32a1af93a89" name="cfg/701/zend_worklist.h" role="src" />
|
45 |
+
<file md5sum="3cfc353db84cbbe5a4cc6ee24e0d373f" name="cfg/702/zend_cfg.h" role="src" />
|
46 |
+
<file md5sum="0d0c5fd1d3e013b683ba96ddf095f8da" name="cfg/702/zend_cfg.c" role="src" />
|
47 |
+
<file md5sum="5e7ced31fffd27eb43086a9c2c4a0a79" name="cfg/702/zend_worklist.h" role="src" />
|
48 |
+
<file md5sum="558cb212089bf4be25ac65f315a2d336" name="cfg/703/zend_cfg.h" role="src" />
|
49 |
+
<file md5sum="1a0f67c3956478a2fc2b9085b67a2b33" name="cfg/703/zend_cfg.c" role="src" />
|
50 |
+
<file md5sum="e8d04cc62e08921dc37bceb54e21caf3" name="cfg/703/zend_worklist.h" role="src" />
|
51 |
+
<file md5sum="b33132efb5ea6c6ad6cb8c84b12be7ed" name="cfg/704/zend_cfg.h" role="src" />
|
52 |
+
<file md5sum="ddb9d10c26bfa5f6f386746257ec57db" name="cfg/704/zend_cfg.c" role="src" />
|
53 |
+
<file md5sum="f86293a5a150c9b208cb88edac66025f" name="cfg/704/zend_worklist.h" role="src" />
|
54 |
+
<file md5sum="fb07bfc51f6d5e0c30b65d9701233b2e" name="LICENSE" role="doc" />
|
55 |
+
<file md5sum="e5bd4101b1949bc39e45840bafcb22b7" name="README.md" role="doc" />
|
56 |
+
<file md5sum="a2c30f07ba7cf6353da075ca57609ceb" name="config.m4" role="src" />
|
57 |
+
<file md5sum="bdb0adc09350e458d4ecc60ea747f828" name="config.w32" role="src" />
|
58 |
+
<file md5sum="509fc4e7754da03938e61171ecce1573" name="php_pcov.h" role="src" />
|
59 |
+
<file md5sum="adb8dceda66e3f1c55d997963d6efae0" name="pcov.c" role="src" />
|
60 |
+
</dir>
|
61 |
+
</contents>
|
62 |
+
<dependencies>
|
63 |
+
<required>
|
64 |
+
<php>
|
65 |
+
<min>7.1.0</min>
|
66 |
+
</php>
|
67 |
+
<pearinstaller>
|
68 |
+
<min>1.10</min>
|
69 |
+
</pearinstaller>
|
70 |
+
</required>
|
71 |
+
</dependencies>
|
72 |
+
<providesextension>pcov</providesextension>
|
73 |
+
<extsrcrelease />
|
74 |
+
<changelog>
|
75 |
+
<release>
|
76 |
+
<date>2021-11-24</date>
|
77 |
+
<version>
|
78 |
+
<release>1.0.10</release>
|
79 |
+
<api>1.0.0</api>
|
80 |
+
</version>
|
81 |
+
<stability>
|
82 |
+
<release>stable</release>
|
83 |
+
<api>stable</api>
|
84 |
+
</stability>
|
85 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
86 |
+
<notes>
|
87 |
+
- Use zend_new_interned_string instead of hand-rolling
|
88 |
+
- Use ZEND_MOD_END to fix build warning
|
89 |
+
</notes>
|
90 |
+
</release>
|
91 |
+
<release>
|
92 |
+
<date>2021-06-07</date>
|
93 |
+
<version>
|
94 |
+
<release>1.0.9</release>
|
95 |
+
<api>1.0.0</api>
|
96 |
+
</version>
|
97 |
+
<stability>
|
98 |
+
<release>stable</release>
|
99 |
+
<api>stable</api>
|
100 |
+
</stability>
|
101 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
102 |
+
<notes>
|
103 |
+
- Fix #67 huge memory consumption to generate coverage
|
104 |
+
</notes>
|
105 |
+
</release>
|
106 |
+
<release>
|
107 |
+
<date>2021-03-22</date>
|
108 |
+
<version>
|
109 |
+
<release>1.0.8</release>
|
110 |
+
<api>1.0.0</api>
|
111 |
+
</version>
|
112 |
+
<stability>
|
113 |
+
<release>stable</release>
|
114 |
+
<api>stable</api>
|
115 |
+
</stability>
|
116 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
117 |
+
<notes>
|
118 |
+
- Fix Windows build
|
119 |
+
</notes>
|
120 |
+
</release>
|
121 |
+
<release>
|
122 |
+
<date>2021-03-19</date>
|
123 |
+
<version>
|
124 |
+
<release>1.0.7</release>
|
125 |
+
<api>1.0.0</api>
|
126 |
+
</version>
|
127 |
+
<stability>
|
128 |
+
<release>stable</release>
|
129 |
+
<api>stable</api>
|
130 |
+
</stability>
|
131 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
132 |
+
<notes>
|
133 |
+
- Fix #46 Segmentation fault on 7.4 on macOS with anonymous class
|
134 |
+
- Fix #59 "malloc_consolidate(): invalid chunk size" with PHP 8.1
|
135 |
+
</notes>
|
136 |
+
</release>
|
137 |
+
<release>
|
138 |
+
<date>2019-06-13</date>
|
139 |
+
<version>
|
140 |
+
<release>1.0.6</release>
|
141 |
+
<api>1.0.0</api>
|
142 |
+
</version>
|
143 |
+
<stability>
|
144 |
+
<release>stable</release>
|
145 |
+
<api>stable</api>
|
146 |
+
</stability>
|
147 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
148 |
+
<notes>
|
149 |
+
- Fix for 7.4.0alpha1
|
150 |
+
</notes>
|
151 |
+
</release>
|
152 |
+
<release>
|
153 |
+
<date>2019-06-11</date>
|
154 |
+
<version>
|
155 |
+
<release>1.0.5</release>
|
156 |
+
<api>1.0.0</api>
|
157 |
+
</version>
|
158 |
+
<stability>
|
159 |
+
<release>stable</release>
|
160 |
+
<api>stable</api>
|
161 |
+
</stability>
|
162 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
163 |
+
<notes>
|
164 |
+
- Fix #19 fault in 7.2 caused by modification of filename pointer
|
165 |
+
</notes>
|
166 |
+
</release>
|
167 |
+
<release>
|
168 |
+
<date>2019-06-03</date>
|
169 |
+
<version>
|
170 |
+
<release>1.0.4</release>
|
171 |
+
<api>1.0.0</api>
|
172 |
+
</version>
|
173 |
+
<stability>
|
174 |
+
<release>stable</release>
|
175 |
+
<api>stable</api>
|
176 |
+
</stability>
|
177 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
178 |
+
<notes>
|
179 |
+
- Fix #17 Lines not covered when more tests are run
|
180 |
+
- Improve perf of clear routine
|
181 |
+
- Merge upstream cfg updates (switch block change)
|
182 |
+
- Omit ignored opcodes from internal coverage data completely (doesn't effect users, except less memory used)
|
183 |
+
</notes>
|
184 |
+
</release>
|
185 |
+
<release>
|
186 |
+
<date>2019-05-06</date>
|
187 |
+
<version>
|
188 |
+
<release>1.0.3</release>
|
189 |
+
<api>1.0.0</api>
|
190 |
+
</version>
|
191 |
+
<stability>
|
192 |
+
<release>stable</release>
|
193 |
+
<api>stable</api>
|
194 |
+
</stability>
|
195 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
196 |
+
<notes>
|
197 |
+
- Fix #12 issue with faulty line coverage
|
198 |
+
</notes>
|
199 |
+
</release>
|
200 |
+
<release>
|
201 |
+
<date>2019-03-31</date>
|
202 |
+
<version>
|
203 |
+
<release>1.0.2</release>
|
204 |
+
<api>1.0.0</api>
|
205 |
+
</version>
|
206 |
+
<stability>
|
207 |
+
<release>stable</release>
|
208 |
+
<api>stable</api>
|
209 |
+
</stability>
|
210 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
211 |
+
<notes>
|
212 |
+
- Fix #10 second non-cli SAPI request behaves strangely
|
213 |
+
</notes>
|
214 |
+
</release>
|
215 |
+
<release>
|
216 |
+
<date>2019-03-25</date>
|
217 |
+
<version>
|
218 |
+
<release>1.0.1</release>
|
219 |
+
<api>1.0.0</api>
|
220 |
+
</version>
|
221 |
+
<stability>
|
222 |
+
<release>stable</release>
|
223 |
+
<api>stable</api>
|
224 |
+
</stability>
|
225 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
226 |
+
<notes>
|
227 |
+
- Release memory from building CFG as early as possible
|
228 |
+
- Compat with 7.4/8.0 changes
|
229 |
+
</notes>
|
230 |
+
</release>
|
231 |
+
<release>
|
232 |
+
<date>2019-01-30</date>
|
233 |
+
<version>
|
234 |
+
<release>1.0.0</release>
|
235 |
+
<api>1.0.0</api>
|
236 |
+
</version>
|
237 |
+
<stability>
|
238 |
+
<release>stable</release>
|
239 |
+
<api>stable</api>
|
240 |
+
</stability>
|
241 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
242 |
+
<notes>
|
243 |
+
- initial pecl stable release
|
244 |
+
</notes>
|
245 |
+
</release>
|
246 |
+
<release>
|
247 |
+
<date>2019-01-22</date>
|
248 |
+
<version>
|
249 |
+
<release>0.9.0</release>
|
250 |
+
<api>0.9.0</api>
|
251 |
+
</version>
|
252 |
+
<stability>
|
253 |
+
<release>beta</release>
|
254 |
+
<api>beta</api>
|
255 |
+
</stability>
|
256 |
+
<license uri="http://www.php.net/license">PHP License</license>
|
257 |
+
<notes>
|
258 |
+
- initial pecl release
|
259 |
+
</notes>
|
260 |
+
</release>
|
261 |
+
</changelog>
|
262 |
+
</package>
|
pcov-1.0.11/pcov-1.0.11/LICENSE
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--------------------------------------------------------------------
|
2 |
+
The PHP License, version 3.01
|
3 |
+
Copyright (c) 1999 - 2018 The PHP Group. All rights reserved.
|
4 |
+
--------------------------------------------------------------------
|
5 |
+
|
6 |
+
Redistribution and use in source and binary forms, with or without
|
7 |
+
modification, is permitted provided that the following conditions
|
8 |
+
are met:
|
9 |
+
|
10 |
+
1. Redistributions of source code must retain the above copyright
|
11 |
+
notice, this list of conditions and the following disclaimer.
|
12 |
+
|
13 |
+
2. Redistributions in binary form must reproduce the above copyright
|
14 |
+
notice, this list of conditions and the following disclaimer in
|
15 |
+
the documentation and/or other materials provided with the
|
16 |
+
distribution.
|
17 |
+
|
18 |
+
3. The name "PHP" must not be used to endorse or promote products
|
19 |
+
derived from this software without prior written permission. For
|
20 |
+
written permission, please contact [email protected].
|
21 |
+
|
22 |
+
4. Products derived from this software may not be called "PHP", nor
|
23 |
+
may "PHP" appear in their name, without prior written permission
|
24 |
+
from [email protected]. You may indicate that your software works in
|
25 |
+
conjunction with PHP by saying "Foo for PHP" instead of calling
|
26 |
+
it "PHP Foo" or "phpfoo"
|
27 |
+
|
28 |
+
5. The PHP Group may publish revised and/or new versions of the
|
29 |
+
license from time to time. Each version will be given a
|
30 |
+
distinguishing version number.
|
31 |
+
Once covered code has been published under a particular version
|
32 |
+
of the license, you may always continue to use it under the terms
|
33 |
+
of that version. You may also choose to use such covered code
|
34 |
+
under the terms of any subsequent version of the license
|
35 |
+
published by the PHP Group. No one other than the PHP Group has
|
36 |
+
the right to modify the terms applicable to covered code created
|
37 |
+
under this License.
|
38 |
+
|
39 |
+
6. Redistributions of any form whatsoever must retain the following
|
40 |
+
acknowledgment:
|
41 |
+
"This product includes PHP software, freely available from
|
42 |
+
<http://www.php.net/software/>".
|
43 |
+
|
44 |
+
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
|
45 |
+
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
46 |
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
47 |
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
|
48 |
+
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
49 |
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
50 |
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
51 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
52 |
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
53 |
+
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
54 |
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
55 |
+
OF THE POSSIBILITY OF SUCH DAMAGE.
|
56 |
+
|
57 |
+
--------------------------------------------------------------------
|
58 |
+
|
59 |
+
This software consists of voluntary contributions made by many
|
60 |
+
individuals on behalf of the PHP Group.
|
61 |
+
|
62 |
+
The PHP Group can be contacted via Email at [email protected].
|
63 |
+
|
64 |
+
For more information on the PHP Group and the PHP project,
|
65 |
+
please see <http://www.php.net>.
|
66 |
+
|
67 |
+
PHP includes the Zend Engine, freely available at
|
68 |
+
<http://www.zend.com>.
|
pcov-1.0.11/pcov-1.0.11/README.md
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
PCOV
|
2 |
+
====
|
3 |
+
|
4 |
+
[![Build Status](https://travis-ci.org/krakjoe/pcov.svg?branch=develop)](https://travis-ci.org/krakjoe/pcov)
|
5 |
+
[![Build status](https://ci.appveyor.com/api/projects/status/w265n0w7yk6o3y6m?svg=true)](https://ci.appveyor.com/project/krakjoe/pcov)
|
6 |
+
|
7 |
+
A self contained [CodeCoverage](https://github.com/sebastianbergmann/php-code-coverage) compatible driver for PHP
|
8 |
+
|
9 |
+
Requirements and Installation
|
10 |
+
=============================
|
11 |
+
|
12 |
+
See [INSTALL.md](INSTALL.md)
|
13 |
+
|
14 |
+
|
15 |
+
API
|
16 |
+
===
|
17 |
+
|
18 |
+
```php
|
19 |
+
/**
|
20 |
+
* Shall start recording coverage information
|
21 |
+
*/
|
22 |
+
function \pcov\start() : void;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Shall stop recording coverage information
|
26 |
+
*/
|
27 |
+
function \pcov\stop() : void;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Shall collect coverage information
|
31 |
+
*
|
32 |
+
* @param integer $type define witch type of information should be collected
|
33 |
+
* \pcov\all shall collect coverage information for all files
|
34 |
+
* \pcov\inclusive shall collect coverage information for the specified files
|
35 |
+
* \pcov\exclusive shall collect coverage information for all but the specified files
|
36 |
+
* @param array $filter path of files (realpath) that should be filtered
|
37 |
+
*
|
38 |
+
* @return array
|
39 |
+
*/
|
40 |
+
function \pcov\collect(int $type = \pcov\all, array $filter = []) : array;
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Shall clear stored information
|
44 |
+
*
|
45 |
+
* @param bool $files set true to clear file tables
|
46 |
+
*
|
47 |
+
* Note: clearing the file tables may have surprising consequences
|
48 |
+
*/
|
49 |
+
function \pcov\clear(bool $files = false) : void;
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Shall return list of files waiting to be collected
|
53 |
+
*/
|
54 |
+
function \pcov\waiting() : array;
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Shall return the current size of the trace and cfg arena
|
58 |
+
*/
|
59 |
+
function \pcov\memory() : int;
|
60 |
+
```
|
61 |
+
|
62 |
+
Configuration
|
63 |
+
=============
|
64 |
+
|
65 |
+
PCOV is configured using PHP.ini:
|
66 |
+
|
67 |
+
| Option | Default | Changeable | Description |
|
68 |
+
|:-----------------------|:-------------------|:--------------:|:------------------------------------------------------|
|
69 |
+
| `pcov.enabled` | 1 | SYSTEM | enable or disable zend hooks for pcov |
|
70 |
+
| `pcov.directory` | auto | SYSTEM,PERDIR | restrict collection to files under this path |
|
71 |
+
| `pcov.exclude` | unused | SYSTEM,PERDIR | exclude files under pcov.directory matching this PCRE |
|
72 |
+
| `pcov.initial.memory` | 65536 | SYSTEM,PERDIR | shall set initial size of arena |
|
73 |
+
| `pcov.initial.files` | 64 | SYSTEM,PERDIR | shall set initial size of tables |
|
74 |
+
|
75 |
+
Notes
|
76 |
+
-----
|
77 |
+
|
78 |
+
The recommended defaults for production should be:
|
79 |
+
|
80 |
+
* `pcov.enabled = 0`
|
81 |
+
|
82 |
+
The recommended defaults for development should be:
|
83 |
+
|
84 |
+
* `pcov.enabled = 1`
|
85 |
+
* `pcov.directory = /path/to/your/source/directory`
|
86 |
+
|
87 |
+
When `pcov.directory` is left unset, PCOV will attempt to find `src`, `lib` or, `app` in the current
|
88 |
+
working directory, in that order; If none are found the current directory will be used, which may waste resources storing
|
89 |
+
coverage information for the test suite.
|
90 |
+
|
91 |
+
If `pcov.directory` contains test code, it's recommended to set `pcov.exclude` to avoid wasting resources.
|
92 |
+
|
93 |
+
To avoid unnecessary allocation of additional arenas for traces and control flow graphs, `pcov.initial.memory` should be set according to the memory required by the test suite, which may be discovered with `\pcov\memory()`.
|
94 |
+
|
95 |
+
To avoid reallocation of tables, `pcov.initial.files` should be set to a number higher than the number of files that will be loaded during testing, inclusive of test files.
|
96 |
+
|
97 |
+
*Note that arenas are allocated in chunks: If the chunk size is set to 65536 and pcov require 65537 bytes, the system will allocate two chunks, each 65536 bytes. When setting arena space therefore, be generous in your estimates.*
|
98 |
+
|
99 |
+
Interoperability
|
100 |
+
================
|
101 |
+
|
102 |
+
When PCOV is enabled by configuration `pcov.enabled=1`:
|
103 |
+
|
104 |
+
* interoperability with Xdebug is not possible
|
105 |
+
* interoperability with phpdbg is not possible
|
106 |
+
* interoperability with Blackfire profiler is not possible
|
107 |
+
|
108 |
+
At an internals level, the executor function is overriden by pcov, so any extension or SAPI which does the same will be broken.
|
109 |
+
|
110 |
+
When PCOV is disabled by configuration `pcov.enabled=0`:
|
111 |
+
|
112 |
+
* PCOV is zero cost - code runs at full speed
|
113 |
+
* Xdebug may be loaded
|
114 |
+
* phpdbg may be executed
|
115 |
+
* Blackfire probe may be loaded
|
116 |
+
|
117 |
+
At an internals level, the executor function is untouched, and pcov allocates no memory.
|
118 |
+
|
119 |
+
Differences in Reporting
|
120 |
+
========================
|
121 |
+
|
122 |
+
There are subtle differences between Xdebug and PCOV in reporting: Both Xdebug and PCOV perform branch analysis in order to detect executable code. Xdebug has custom written (very mature, proven) analysis, while PCOV uses the very well proven control flow graph from Optimizer. They generate comparably accurate reports, while phpdbg uses less robust detection of executable code and generates reports with known defects. One such defect in phpdbg is this:
|
123 |
+
|
124 |
+
```php
|
125 |
+
/* 2 */ function foo($bar) {
|
126 |
+
/* 3 */ if ($bar) {
|
127 |
+
/* 4 */ return true;
|
128 |
+
/* 5 */ }
|
129 |
+
/* 6 */ }
|
130 |
+
```
|
131 |
+
|
132 |
+
phpdbg will detect that this function is 100% covered when the first control path is taken, `if ($bar)`, because it cannot correctly detect which implicit return paths inserted by Zend at compile time are executable, and so chooses to ignore them all. While this may seem like a trivial difference to some, it means that the reports generated by phpdbg are not completely trustworthy.
|
133 |
+
|
134 |
+
While the accuracy of Xdebug and PCOV are comparable, the reports they generate are not precisely the same, one such example is the `switch` construct:
|
135 |
+
|
136 |
+
```php
|
137 |
+
/* 2 */ switch ($condition) {
|
138 |
+
/* 3 */ case 1:
|
139 |
+
/* 4 */ return "PHP rox!";
|
140 |
+
/* 5 */ }
|
141 |
+
```
|
142 |
+
|
143 |
+
From PHP 7.2.15 and PCOV 1.0, PCOV will detect the executability of the cases inside the switch body correctly, but will not detect line 2 (with the `switch` statement) as executable because Zend didn't output an executable opcode on that line. Xdebug's custom analysis doesn't use the same method and so will show an extra executable line on 2. Pre 7.2.15 and PCOV 1.0, the coverage of some switches is questionable as a result of the way Zend constructs the opcodes in the body of the switch - it may not execute them depending on a jump table optimization.
|
144 |
+
|
145 |
+
While Xdebug and PCOV both do the same kind of analysis of code, Xdebug is currently able to do more with that information than just generate accurate line coverage reports, it has path coverage and PCOV does not, although path coverage is not yet implemented (and probably won't be) by CodeCoverage.
|
146 |
+
|
147 |
+
Differences in Performance
|
148 |
+
==========================
|
149 |
+
|
150 |
+
The differences in performance of Xdebug and PCOV are not slight. Xdebug is first and foremost a debugging extension, and when you load it, you incur the overhead of a debugger even when it's disabled. PCOV is less than 1000 lines of code (not including CFG) and doesn't have anything like the overhead of a debugger.
|
pcov-1.0.11/pcov-1.0.11/cfg/701/zend_cfg.c
ADDED
@@ -0,0 +1,595 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Zend Engine, CFG - Control Flow Graph |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| Copyright (c) 1998-2018 The PHP Group |
|
6 |
+
+----------------------------------------------------------------------+
|
7 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
8 |
+
| that is bundled with this package in the file LICENSE, and is |
|
9 |
+
| available through the world-wide-web at the following url: |
|
10 |
+
| http://www.php.net/license/3_01.txt |
|
11 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
12 |
+
| obtain it through the world-wide-web, please send a note to |
|
13 |
+
| [email protected] so we can mail you a copy immediately. |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
| Authors: Dmitry Stogov <[email protected]> |
|
16 |
+
+----------------------------------------------------------------------+
|
17 |
+
|
18 |
+
This source file has been adapted for pcov so that the CFG from O+ is standalone
|
19 |
+
*/
|
20 |
+
|
21 |
+
#include "php.h"
|
22 |
+
#include "zend_compile.h"
|
23 |
+
#include "zend_cfg.h"
|
24 |
+
#include "zend_worklist.h"
|
25 |
+
|
26 |
+
/* func flags */
|
27 |
+
#define ZEND_FUNC_INDIRECT_VAR_ACCESS (1<<0) /* accesses variables by name */
|
28 |
+
#define ZEND_FUNC_HAS_CALLS (1<<1)
|
29 |
+
#define ZEND_FUNC_VARARG (1<<2) /* uses func_get_args() */
|
30 |
+
#define ZEND_FUNC_NO_LOOPS (1<<3)
|
31 |
+
#define ZEND_FUNC_IRREDUCIBLE (1<<4)
|
32 |
+
#define ZEND_FUNC_RECURSIVE (1<<7)
|
33 |
+
#define ZEND_FUNC_RECURSIVE_DIRECTLY (1<<8)
|
34 |
+
#define ZEND_FUNC_RECURSIVE_INDIRECTLY (1<<9)
|
35 |
+
#define ZEND_FUNC_HAS_EXTENDED_INFO (1<<10)
|
36 |
+
|
37 |
+
/* The following flags are valid only for return values of internal functions
|
38 |
+
* returned by zend_get_func_info()
|
39 |
+
*/
|
40 |
+
#define FUNC_MAY_WARN (1<<30)
|
41 |
+
|
42 |
+
typedef struct _zend_func_info zend_func_info;
|
43 |
+
typedef struct _zend_call_info zend_call_info;
|
44 |
+
|
45 |
+
#define ZEND_FUNC_INFO(op_array) \
|
46 |
+
((zend_func_info*)((op_array)->reserved[zend_func_info_rid]))
|
47 |
+
|
48 |
+
#define ZEND_SET_FUNC_INFO(op_array, info) do { \
|
49 |
+
zend_func_info** pinfo = (zend_func_info**)&(op_array)->reserved[zend_func_info_rid]; \
|
50 |
+
*pinfo = info; \
|
51 |
+
} while (0)
|
52 |
+
|
53 |
+
static uint32_t zend_cfg_classify_function(zend_string *name, uint32_t num_args) {
|
54 |
+
if (zend_string_equals_literal(name, "extract")) {
|
55 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
56 |
+
} else if (zend_string_equals_literal(name, "compact")) {
|
57 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
58 |
+
} else if (zend_string_equals_literal(name, "parse_str") && num_args <= 1) {
|
59 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
60 |
+
} else if (zend_string_equals_literal(name, "mb_parse_str") && num_args <= 1) {
|
61 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
62 |
+
} else if (zend_string_equals_literal(name, "get_defined_vars")) {
|
63 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
64 |
+
} else if (zend_string_equals_literal(name, "assert")) {
|
65 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
66 |
+
} else if (zend_string_equals_literal(name, "func_num_args")) {
|
67 |
+
return ZEND_FUNC_VARARG;
|
68 |
+
} else if (zend_string_equals_literal(name, "func_get_arg")) {
|
69 |
+
return ZEND_FUNC_VARARG;
|
70 |
+
} else if (zend_string_equals_literal(name, "func_get_args")) {
|
71 |
+
return ZEND_FUNC_VARARG;
|
72 |
+
} else {
|
73 |
+
return 0;
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_block *b) /* {{{ */
|
78 |
+
{
|
79 |
+
zend_uchar opcode;
|
80 |
+
zend_basic_block *b0;
|
81 |
+
int successor_0, successor_1;
|
82 |
+
zend_basic_block *blocks = cfg->blocks;
|
83 |
+
|
84 |
+
while (1) {
|
85 |
+
b->flags |= ZEND_BB_REACHABLE;
|
86 |
+
successor_0 = b->successors[0];
|
87 |
+
if (successor_0 >= 0) {
|
88 |
+
successor_1 = b->successors[1];
|
89 |
+
if (successor_1 >= 0) {
|
90 |
+
b0 = blocks + successor_0;
|
91 |
+
b0->flags |= ZEND_BB_TARGET;
|
92 |
+
if (!(b0->flags & ZEND_BB_REACHABLE)) {
|
93 |
+
zend_mark_reachable(opcodes, cfg, b0);
|
94 |
+
}
|
95 |
+
|
96 |
+
ZEND_ASSERT(b->len != 0);
|
97 |
+
opcode = opcodes[b->start + b->len - 1].opcode;
|
98 |
+
b = blocks + successor_1;
|
99 |
+
if (opcode == ZEND_JMPZNZ) {
|
100 |
+
b->flags |= ZEND_BB_TARGET;
|
101 |
+
} else {
|
102 |
+
b->flags |= ZEND_BB_FOLLOW;
|
103 |
+
}
|
104 |
+
} else if (b->len != 0) {
|
105 |
+
opcode = opcodes[b->start + b->len - 1].opcode;
|
106 |
+
b = blocks + successor_0;
|
107 |
+
if (opcode == ZEND_JMP) {
|
108 |
+
b->flags |= ZEND_BB_TARGET;
|
109 |
+
} else {
|
110 |
+
b->flags |= ZEND_BB_FOLLOW;
|
111 |
+
|
112 |
+
if (cfg->split_at_calls) {
|
113 |
+
if (opcode == ZEND_INCLUDE_OR_EVAL ||
|
114 |
+
opcode == ZEND_GENERATOR_CREATE ||
|
115 |
+
opcode == ZEND_YIELD ||
|
116 |
+
opcode == ZEND_YIELD_FROM ||
|
117 |
+
opcode == ZEND_DO_FCALL ||
|
118 |
+
opcode == ZEND_DO_UCALL ||
|
119 |
+
opcode == ZEND_DO_FCALL_BY_NAME) {
|
120 |
+
b->flags |= ZEND_BB_ENTRY;
|
121 |
+
}
|
122 |
+
}
|
123 |
+
if (cfg->split_at_recv) {
|
124 |
+
if (opcode == ZEND_RECV ||
|
125 |
+
opcode == ZEND_RECV_INIT) {
|
126 |
+
b->flags |= ZEND_BB_RECV_ENTRY;
|
127 |
+
}
|
128 |
+
}
|
129 |
+
}
|
130 |
+
} else {
|
131 |
+
b = blocks + successor_0;
|
132 |
+
b->flags |= ZEND_BB_FOLLOW;
|
133 |
+
}
|
134 |
+
if (b->flags & ZEND_BB_REACHABLE) return;
|
135 |
+
} else {
|
136 |
+
b->flags |= ZEND_BB_EXIT;
|
137 |
+
return;
|
138 |
+
}
|
139 |
+
}
|
140 |
+
}
|
141 |
+
/* }}} */
|
142 |
+
|
143 |
+
static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg *cfg, int start) /* {{{ */
|
144 |
+
{
|
145 |
+
zend_basic_block *blocks = cfg->blocks;
|
146 |
+
|
147 |
+
blocks[start].flags = ZEND_BB_START;
|
148 |
+
zend_mark_reachable(op_array->opcodes, cfg, blocks + start);
|
149 |
+
|
150 |
+
if (op_array->last_live_range || op_array->last_try_catch) {
|
151 |
+
zend_basic_block *b;
|
152 |
+
int j, changed;
|
153 |
+
uint32_t *block_map = cfg->map;
|
154 |
+
|
155 |
+
do {
|
156 |
+
changed = 0;
|
157 |
+
|
158 |
+
/* Add live range paths */
|
159 |
+
for (j = 0; j < op_array->last_live_range; j++) {
|
160 |
+
zend_live_range *live_range = &op_array->live_range[j];
|
161 |
+
if (live_range->var == (uint32_t)-1) {
|
162 |
+
/* this live range already removed */
|
163 |
+
continue;
|
164 |
+
}
|
165 |
+
b = blocks + block_map[live_range->start];
|
166 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
167 |
+
while (b->len > 0 && op_array->opcodes[b->start].opcode == ZEND_NOP) {
|
168 |
+
/* check if NOP breaks incorrect smart branch */
|
169 |
+
if (b->len == 2
|
170 |
+
&& (op_array->opcodes[b->start + 1].opcode == ZEND_JMPZ
|
171 |
+
|| op_array->opcodes[b->start + 1].opcode == ZEND_JMPNZ)
|
172 |
+
&& (op_array->opcodes[b->start + 1].op1_type & (IS_CV|IS_CONST))
|
173 |
+
&& b->start > 0
|
174 |
+
&& zend_is_smart_branch(op_array->opcodes + b->start - 1)) {
|
175 |
+
break;
|
176 |
+
}
|
177 |
+
b->start++;
|
178 |
+
b->len--;
|
179 |
+
}
|
180 |
+
if (b->len == 0 && (uint32_t)b->successors[0] == block_map[live_range->end]) {
|
181 |
+
/* mark as removed (empty live range) */
|
182 |
+
live_range->var = (uint32_t)-1;
|
183 |
+
continue;
|
184 |
+
}
|
185 |
+
b->flags |= ZEND_BB_GEN_VAR;
|
186 |
+
b = blocks + block_map[live_range->end];
|
187 |
+
b->flags |= ZEND_BB_KILL_VAR;
|
188 |
+
if (!(b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE))) {
|
189 |
+
if (cfg->split_at_live_ranges) {
|
190 |
+
changed = 1;
|
191 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
192 |
+
} else {
|
193 |
+
ZEND_ASSERT(b->start == live_range->end);
|
194 |
+
b->flags |= ZEND_BB_UNREACHABLE_FREE;
|
195 |
+
}
|
196 |
+
}
|
197 |
+
} else {
|
198 |
+
ZEND_ASSERT(!(blocks[block_map[live_range->end]].flags & ZEND_BB_REACHABLE));
|
199 |
+
}
|
200 |
+
}
|
201 |
+
|
202 |
+
/* Add exception paths */
|
203 |
+
for (j = 0; j < op_array->last_try_catch; j++) {
|
204 |
+
|
205 |
+
/* check for jumps into the middle of try block */
|
206 |
+
b = blocks + block_map[op_array->try_catch_array[j].try_op];
|
207 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
208 |
+
zend_basic_block *end;
|
209 |
+
|
210 |
+
if (op_array->try_catch_array[j].catch_op) {
|
211 |
+
end = blocks + block_map[op_array->try_catch_array[j].catch_op];
|
212 |
+
while (b != end) {
|
213 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
214 |
+
op_array->try_catch_array[j].try_op = b->start;
|
215 |
+
break;
|
216 |
+
}
|
217 |
+
b++;
|
218 |
+
}
|
219 |
+
}
|
220 |
+
b = blocks + block_map[op_array->try_catch_array[j].try_op];
|
221 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
222 |
+
if (op_array->try_catch_array[j].finally_op) {
|
223 |
+
end = blocks + block_map[op_array->try_catch_array[j].finally_op];
|
224 |
+
while (b != end) {
|
225 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
226 |
+
op_array->try_catch_array[j].try_op = op_array->try_catch_array[j].catch_op;
|
227 |
+
changed = 1;
|
228 |
+
zend_mark_reachable(op_array->opcodes, cfg, blocks + block_map[op_array->try_catch_array[j].try_op]);
|
229 |
+
break;
|
230 |
+
}
|
231 |
+
b++;
|
232 |
+
}
|
233 |
+
}
|
234 |
+
}
|
235 |
+
}
|
236 |
+
|
237 |
+
b = blocks + block_map[op_array->try_catch_array[j].try_op];
|
238 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
239 |
+
b->flags |= ZEND_BB_TRY;
|
240 |
+
if (op_array->try_catch_array[j].catch_op) {
|
241 |
+
b = blocks + block_map[op_array->try_catch_array[j].catch_op];
|
242 |
+
b->flags |= ZEND_BB_CATCH;
|
243 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
244 |
+
changed = 1;
|
245 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
246 |
+
}
|
247 |
+
}
|
248 |
+
if (op_array->try_catch_array[j].finally_op) {
|
249 |
+
b = blocks + block_map[op_array->try_catch_array[j].finally_op];
|
250 |
+
b->flags |= ZEND_BB_FINALLY;
|
251 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
252 |
+
changed = 1;
|
253 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
254 |
+
}
|
255 |
+
}
|
256 |
+
if (op_array->try_catch_array[j].finally_end) {
|
257 |
+
b = blocks + block_map[op_array->try_catch_array[j].finally_end];
|
258 |
+
b->flags |= ZEND_BB_FINALLY_END;
|
259 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
260 |
+
changed = 1;
|
261 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
262 |
+
}
|
263 |
+
}
|
264 |
+
} else {
|
265 |
+
if (op_array->try_catch_array[j].catch_op) {
|
266 |
+
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].catch_op]].flags & ZEND_BB_REACHABLE));
|
267 |
+
}
|
268 |
+
if (op_array->try_catch_array[j].finally_op) {
|
269 |
+
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_op]].flags & ZEND_BB_REACHABLE));
|
270 |
+
}
|
271 |
+
if (op_array->try_catch_array[j].finally_end) {
|
272 |
+
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_end]].flags & ZEND_BB_REACHABLE));
|
273 |
+
}
|
274 |
+
}
|
275 |
+
}
|
276 |
+
} while (changed);
|
277 |
+
}
|
278 |
+
}
|
279 |
+
/* }}} */
|
280 |
+
|
281 |
+
static void record_successor(zend_basic_block *blocks, int pred, int n, int succ)
|
282 |
+
{
|
283 |
+
blocks[pred].successors[n] = succ;
|
284 |
+
}
|
285 |
+
|
286 |
+
static void initialize_block(zend_basic_block *block) {
|
287 |
+
block->flags = 0;
|
288 |
+
block->successors[0] = -1;
|
289 |
+
block->successors[1] = -1;
|
290 |
+
block->predecessors_count = 0;
|
291 |
+
block->predecessor_offset = -1;
|
292 |
+
block->idom = -1;
|
293 |
+
block->loop_header = -1;
|
294 |
+
block->level = -1;
|
295 |
+
block->children = -1;
|
296 |
+
block->next_child = -1;
|
297 |
+
}
|
298 |
+
|
299 |
+
#define BB_START(i) do { \
|
300 |
+
if (!block_map[i]) { blocks_count++;} \
|
301 |
+
block_map[i]++; \
|
302 |
+
} while (0)
|
303 |
+
|
304 |
+
int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg) /* {{{ */
|
305 |
+
{
|
306 |
+
uint32_t flags = 0;
|
307 |
+
uint32_t i;
|
308 |
+
int j;
|
309 |
+
uint32_t *block_map;
|
310 |
+
zend_function *fn;
|
311 |
+
int blocks_count = 0;
|
312 |
+
zend_basic_block *blocks;
|
313 |
+
zval *zv;
|
314 |
+
zend_bool extra_entry_block = 0;
|
315 |
+
|
316 |
+
cfg->split_at_live_ranges = (build_flags & ZEND_CFG_SPLIT_AT_LIVE_RANGES) != 0;
|
317 |
+
cfg->split_at_calls = (build_flags & ZEND_CFG_STACKLESS) != 0;
|
318 |
+
cfg->split_at_recv = (build_flags & ZEND_CFG_RECV_ENTRY) != 0 && (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0;
|
319 |
+
|
320 |
+
cfg->map = block_map = zend_arena_calloc(arena, op_array->last, sizeof(uint32_t));
|
321 |
+
if (!block_map) {
|
322 |
+
return FAILURE;
|
323 |
+
}
|
324 |
+
|
325 |
+
/* Build CFG, Step 1: Find basic blocks starts, calculate number of blocks */
|
326 |
+
BB_START(0);
|
327 |
+
for (i = 0; i < op_array->last; i++) {
|
328 |
+
zend_op *opline = op_array->opcodes + i;
|
329 |
+
switch(opline->opcode) {
|
330 |
+
case ZEND_RECV:
|
331 |
+
case ZEND_RECV_INIT:
|
332 |
+
if (build_flags & ZEND_CFG_RECV_ENTRY) {
|
333 |
+
BB_START(i + 1);
|
334 |
+
}
|
335 |
+
break;
|
336 |
+
case ZEND_RETURN:
|
337 |
+
case ZEND_RETURN_BY_REF:
|
338 |
+
case ZEND_GENERATOR_RETURN:
|
339 |
+
case ZEND_EXIT:
|
340 |
+
case ZEND_THROW:
|
341 |
+
if (i + 1 < op_array->last) {
|
342 |
+
BB_START(i + 1);
|
343 |
+
}
|
344 |
+
break;
|
345 |
+
case ZEND_INCLUDE_OR_EVAL:
|
346 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
347 |
+
case ZEND_GENERATOR_CREATE:
|
348 |
+
case ZEND_YIELD:
|
349 |
+
case ZEND_YIELD_FROM:
|
350 |
+
if (build_flags & ZEND_CFG_STACKLESS) {
|
351 |
+
BB_START(i + 1);
|
352 |
+
}
|
353 |
+
break;
|
354 |
+
case ZEND_DO_FCALL:
|
355 |
+
case ZEND_DO_UCALL:
|
356 |
+
case ZEND_DO_FCALL_BY_NAME:
|
357 |
+
flags |= ZEND_FUNC_HAS_CALLS;
|
358 |
+
if (build_flags & ZEND_CFG_STACKLESS) {
|
359 |
+
BB_START(i + 1);
|
360 |
+
}
|
361 |
+
break;
|
362 |
+
case ZEND_DO_ICALL:
|
363 |
+
flags |= ZEND_FUNC_HAS_CALLS;
|
364 |
+
break;
|
365 |
+
case ZEND_INIT_FCALL:
|
366 |
+
case ZEND_INIT_NS_FCALL_BY_NAME:
|
367 |
+
zv = CRT_CONSTANT(opline->op2);
|
368 |
+
if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
|
369 |
+
/* The third literal is the lowercased unqualified name */
|
370 |
+
zv += 2;
|
371 |
+
}
|
372 |
+
if ((fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv))) != NULL) {
|
373 |
+
if (fn->type == ZEND_INTERNAL_FUNCTION) {
|
374 |
+
flags |= zend_cfg_classify_function(
|
375 |
+
Z_STR_P(zv), opline->extended_value);
|
376 |
+
}
|
377 |
+
}
|
378 |
+
break;
|
379 |
+
case ZEND_FAST_CALL:
|
380 |
+
BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
|
381 |
+
BB_START(i + 1);
|
382 |
+
break;
|
383 |
+
case ZEND_FAST_RET:
|
384 |
+
if (i + 1 < op_array->last) {
|
385 |
+
BB_START(i + 1);
|
386 |
+
}
|
387 |
+
break;
|
388 |
+
case ZEND_JMP:
|
389 |
+
BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
|
390 |
+
if (i + 1 < op_array->last) {
|
391 |
+
BB_START(i + 1);
|
392 |
+
}
|
393 |
+
break;
|
394 |
+
case ZEND_JMPZNZ:
|
395 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
396 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
397 |
+
if (i + 1 < op_array->last) {
|
398 |
+
BB_START(i + 1);
|
399 |
+
}
|
400 |
+
break;
|
401 |
+
case ZEND_JMPZ:
|
402 |
+
case ZEND_JMPNZ:
|
403 |
+
case ZEND_JMPZ_EX:
|
404 |
+
case ZEND_JMPNZ_EX:
|
405 |
+
case ZEND_JMP_SET:
|
406 |
+
case ZEND_COALESCE:
|
407 |
+
case ZEND_ASSERT_CHECK:
|
408 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
409 |
+
BB_START(i + 1);
|
410 |
+
break;
|
411 |
+
case ZEND_CATCH:
|
412 |
+
if (!opline->result.num) {
|
413 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
414 |
+
}
|
415 |
+
BB_START(i + 1);
|
416 |
+
break;
|
417 |
+
case ZEND_DECLARE_ANON_CLASS:
|
418 |
+
case ZEND_DECLARE_ANON_INHERITED_CLASS:
|
419 |
+
case ZEND_FE_FETCH_R:
|
420 |
+
case ZEND_FE_FETCH_RW:
|
421 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
422 |
+
BB_START(i + 1);
|
423 |
+
break;
|
424 |
+
case ZEND_FE_RESET_R:
|
425 |
+
case ZEND_FE_RESET_RW:
|
426 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
427 |
+
BB_START(i + 1);
|
428 |
+
break;
|
429 |
+
case ZEND_UNSET_VAR:
|
430 |
+
case ZEND_ISSET_ISEMPTY_VAR:
|
431 |
+
if (((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL) &&
|
432 |
+
!(opline->extended_value & ZEND_QUICK_SET)) {
|
433 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
434 |
+
} else if (((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL ||
|
435 |
+
(opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL_LOCK) &&
|
436 |
+
!op_array->function_name) {
|
437 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
438 |
+
}
|
439 |
+
break;
|
440 |
+
case ZEND_FETCH_R:
|
441 |
+
case ZEND_FETCH_W:
|
442 |
+
case ZEND_FETCH_RW:
|
443 |
+
case ZEND_FETCH_FUNC_ARG:
|
444 |
+
case ZEND_FETCH_IS:
|
445 |
+
case ZEND_FETCH_UNSET:
|
446 |
+
if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL) {
|
447 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
448 |
+
} else if (((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL ||
|
449 |
+
(opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL_LOCK) &&
|
450 |
+
!op_array->function_name) {
|
451 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
452 |
+
}
|
453 |
+
break;
|
454 |
+
}
|
455 |
+
}
|
456 |
+
|
457 |
+
/* If the entry block has predecessors, we may need to split it */
|
458 |
+
if ((build_flags & ZEND_CFG_NO_ENTRY_PREDECESSORS)
|
459 |
+
&& op_array->last > 0 && block_map[0] > 1) {
|
460 |
+
extra_entry_block = 1;
|
461 |
+
}
|
462 |
+
|
463 |
+
if (cfg->split_at_live_ranges) {
|
464 |
+
for (j = 0; j < op_array->last_live_range; j++) {
|
465 |
+
BB_START(op_array->live_range[j].start);
|
466 |
+
BB_START(op_array->live_range[j].end);
|
467 |
+
}
|
468 |
+
}
|
469 |
+
|
470 |
+
if (op_array->last_try_catch) {
|
471 |
+
for (j = 0; j < op_array->last_try_catch; j++) {
|
472 |
+
BB_START(op_array->try_catch_array[j].try_op);
|
473 |
+
if (op_array->try_catch_array[j].catch_op) {
|
474 |
+
BB_START(op_array->try_catch_array[j].catch_op);
|
475 |
+
}
|
476 |
+
if (op_array->try_catch_array[j].finally_op) {
|
477 |
+
BB_START(op_array->try_catch_array[j].finally_op);
|
478 |
+
}
|
479 |
+
if (op_array->try_catch_array[j].finally_end) {
|
480 |
+
BB_START(op_array->try_catch_array[j].finally_end);
|
481 |
+
}
|
482 |
+
}
|
483 |
+
}
|
484 |
+
|
485 |
+
blocks_count += extra_entry_block;
|
486 |
+
cfg->blocks_count = blocks_count;
|
487 |
+
|
488 |
+
/* Build CFG, Step 2: Build Array of Basic Blocks */
|
489 |
+
cfg->blocks = blocks = zend_arena_calloc(arena, sizeof(zend_basic_block), blocks_count);
|
490 |
+
if (!blocks) {
|
491 |
+
return FAILURE;
|
492 |
+
}
|
493 |
+
|
494 |
+
blocks_count = -1;
|
495 |
+
|
496 |
+
if (extra_entry_block) {
|
497 |
+
initialize_block(&blocks[0]);
|
498 |
+
blocks[0].start = 0;
|
499 |
+
blocks[0].len = 0;
|
500 |
+
blocks_count++;
|
501 |
+
}
|
502 |
+
|
503 |
+
for (i = 0; i < op_array->last; i++) {
|
504 |
+
if (block_map[i]) {
|
505 |
+
if (blocks_count >= 0) {
|
506 |
+
blocks[blocks_count].len = i - blocks[blocks_count].start;
|
507 |
+
}
|
508 |
+
blocks_count++;
|
509 |
+
initialize_block(&blocks[blocks_count]);
|
510 |
+
blocks[blocks_count].start = i;
|
511 |
+
}
|
512 |
+
block_map[i] = blocks_count;
|
513 |
+
}
|
514 |
+
|
515 |
+
blocks[blocks_count].len = i - blocks[blocks_count].start;
|
516 |
+
blocks_count++;
|
517 |
+
|
518 |
+
/* Build CFG, Step 3: Calculate successors */
|
519 |
+
for (j = 0; j < blocks_count; j++) {
|
520 |
+
zend_op *opline;
|
521 |
+
if (blocks[j].len == 0) {
|
522 |
+
record_successor(blocks, j, 0, j + 1);
|
523 |
+
continue;
|
524 |
+
}
|
525 |
+
|
526 |
+
opline = op_array->opcodes + blocks[j].start + blocks[j].len - 1;
|
527 |
+
switch (opline->opcode) {
|
528 |
+
case ZEND_FAST_RET:
|
529 |
+
case ZEND_RETURN:
|
530 |
+
case ZEND_RETURN_BY_REF:
|
531 |
+
case ZEND_GENERATOR_RETURN:
|
532 |
+
case ZEND_EXIT:
|
533 |
+
case ZEND_THROW:
|
534 |
+
break;
|
535 |
+
case ZEND_JMP:
|
536 |
+
record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes]);
|
537 |
+
break;
|
538 |
+
case ZEND_JMPZNZ:
|
539 |
+
record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]);
|
540 |
+
record_successor(blocks, j, 1, block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
|
541 |
+
break;
|
542 |
+
case ZEND_JMPZ:
|
543 |
+
case ZEND_JMPNZ:
|
544 |
+
case ZEND_JMPZ_EX:
|
545 |
+
case ZEND_JMPNZ_EX:
|
546 |
+
case ZEND_JMP_SET:
|
547 |
+
case ZEND_COALESCE:
|
548 |
+
case ZEND_ASSERT_CHECK:
|
549 |
+
record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]);
|
550 |
+
record_successor(blocks, j, 1, j + 1);
|
551 |
+
break;
|
552 |
+
case ZEND_CATCH:
|
553 |
+
if (!opline->result.num) {
|
554 |
+
record_successor(blocks, j, 0, block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
|
555 |
+
record_successor(blocks, j, 1, j + 1);
|
556 |
+
} else {
|
557 |
+
record_successor(blocks, j, 0, j + 1);
|
558 |
+
}
|
559 |
+
break;
|
560 |
+
case ZEND_DECLARE_ANON_CLASS:
|
561 |
+
case ZEND_DECLARE_ANON_INHERITED_CLASS:
|
562 |
+
case ZEND_FE_FETCH_R:
|
563 |
+
case ZEND_FE_FETCH_RW:
|
564 |
+
record_successor(blocks, j, 0, block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
|
565 |
+
record_successor(blocks, j, 1, j + 1);
|
566 |
+
break;
|
567 |
+
case ZEND_FE_RESET_R:
|
568 |
+
case ZEND_FE_RESET_RW:
|
569 |
+
record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]);
|
570 |
+
record_successor(blocks, j, 1, j + 1);
|
571 |
+
break;
|
572 |
+
case ZEND_FAST_CALL:
|
573 |
+
record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes]);
|
574 |
+
record_successor(blocks, j, 1, j + 1);
|
575 |
+
break;
|
576 |
+
default:
|
577 |
+
record_successor(blocks, j, 0, j + 1);
|
578 |
+
break;
|
579 |
+
}
|
580 |
+
}
|
581 |
+
|
582 |
+
/* Build CFG, Step 4, Mark Reachable Basic Blocks */
|
583 |
+
zend_mark_reachable_blocks(op_array, cfg, 0);
|
584 |
+
|
585 |
+
return SUCCESS;
|
586 |
+
}
|
587 |
+
/* }}} */
|
588 |
+
|
589 |
+
/*
|
590 |
+
* Local variables:
|
591 |
+
* tab-width: 4
|
592 |
+
* c-basic-offset: 4
|
593 |
+
* indent-tabs-mode: t
|
594 |
+
* End:
|
595 |
+
*/
|
pcov-1.0.11/pcov-1.0.11/cfg/701/zend_cfg.h
ADDED
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Zend Engine, CFG - Control Flow Graph |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| Copyright (c) 1998-2018 The PHP Group |
|
6 |
+
+----------------------------------------------------------------------+
|
7 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
8 |
+
| that is bundled with this package in the file LICENSE, and is |
|
9 |
+
| available through the world-wide-web at the following url: |
|
10 |
+
| http://www.php.net/license/3_01.txt |
|
11 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
12 |
+
| obtain it through the world-wide-web, please send a note to |
|
13 |
+
| [email protected] so we can mail you a copy immediately. |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
| Authors: Dmitry Stogov <[email protected]> |
|
16 |
+
+----------------------------------------------------------------------+
|
17 |
+
*/
|
18 |
+
|
19 |
+
#ifndef ZEND_CFG_H
|
20 |
+
#define ZEND_CFG_H
|
21 |
+
|
22 |
+
/* zend_basic_bloc.flags */
|
23 |
+
#define ZEND_BB_START (1<<0) /* fist block */
|
24 |
+
#define ZEND_BB_FOLLOW (1<<1) /* follows the next block */
|
25 |
+
#define ZEND_BB_TARGET (1<<2) /* jump taget */
|
26 |
+
#define ZEND_BB_EXIT (1<<3) /* without successors */
|
27 |
+
#define ZEND_BB_ENTRY (1<<4) /* stackless entry */
|
28 |
+
#define ZEND_BB_TRY (1<<5) /* start of try block */
|
29 |
+
#define ZEND_BB_CATCH (1<<6) /* start of catch block */
|
30 |
+
#define ZEND_BB_FINALLY (1<<7) /* start of finally block */
|
31 |
+
#define ZEND_BB_FINALLY_END (1<<8) /* end of finally block */
|
32 |
+
#define ZEND_BB_GEN_VAR (1<<9) /* start of live range */
|
33 |
+
#define ZEND_BB_KILL_VAR (1<<10) /* end of live range */
|
34 |
+
#define ZEND_BB_UNREACHABLE_FREE (1<<11) /* unreachable loop free */
|
35 |
+
#define ZEND_BB_RECV_ENTRY (1<<12) /* RECV entry */
|
36 |
+
|
37 |
+
#define ZEND_BB_LOOP_HEADER (1<<16)
|
38 |
+
#define ZEND_BB_IRREDUCIBLE_LOOP (1<<17)
|
39 |
+
|
40 |
+
#define ZEND_BB_REACHABLE (1<<31)
|
41 |
+
|
42 |
+
#define ZEND_BB_PROTECTED (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY|ZEND_BB_TRY|ZEND_BB_CATCH|ZEND_BB_FINALLY|ZEND_BB_FINALLY_END|ZEND_BB_GEN_VAR|ZEND_BB_KILL_VAR)
|
43 |
+
|
44 |
+
typedef struct _zend_basic_block {
|
45 |
+
uint32_t flags;
|
46 |
+
uint32_t start; /* first opcode number */
|
47 |
+
uint32_t len; /* number of opcodes */
|
48 |
+
int successors[2]; /* up to 2 successor blocks */
|
49 |
+
int predecessors_count; /* number of predecessors */
|
50 |
+
int predecessor_offset; /* offset of 1-st predecessor */
|
51 |
+
int idom; /* immediate dominator block */
|
52 |
+
int loop_header; /* closest loop header, or -1 */
|
53 |
+
int level; /* steps away from the entry in the dom. tree */
|
54 |
+
int children; /* list of dominated blocks */
|
55 |
+
int next_child; /* next dominated block */
|
56 |
+
} zend_basic_block;
|
57 |
+
|
58 |
+
/*
|
59 |
+
+------------+---+---+---+---+---+
|
60 |
+
| |OP1|OP2|EXT| 0 | 1 |
|
61 |
+
+------------+---+---+---+---+---+
|
62 |
+
|JMP |ADR| | |OP1| - |
|
63 |
+
|JMPZ | |ADR| |OP2|FOL|
|
64 |
+
|JMPNZ | |ADR| |OP2|FOL|
|
65 |
+
|JMPZNZ | |ADR|ADR|OP2|EXT|
|
66 |
+
|JMPZ_EX | |ADR| |OP2|FOL|
|
67 |
+
|JMPNZ_EX | |ADR| |OP2|FOL|
|
68 |
+
|JMP_SET | |ADR| |OP2|FOL|
|
69 |
+
|COALESCE | |ADR| |OP2|FOL|
|
70 |
+
|ASSERT_CHK | |ADR| |OP2|FOL|
|
71 |
+
|NEW | |ADR| |OP2|FOL|
|
72 |
+
|DCL_ANON* |ADR| | |OP1|FOL|
|
73 |
+
|FE_RESET_* | |ADR| |OP2|FOL|
|
74 |
+
|FE_FETCH_* | | |ADR|EXT|FOL|
|
75 |
+
|CATCH | | |ADR|EXT|FOL|
|
76 |
+
|FAST_CALL |ADR| | |OP1|FOL|
|
77 |
+
|FAST_RET | | | | - | - |
|
78 |
+
|RETURN* | | | | - | - |
|
79 |
+
|EXIT | | | | - | - |
|
80 |
+
|THROW | | | | - | - |
|
81 |
+
|* | | | |FOL| - |
|
82 |
+
+------------+---+---+---+---+---+
|
83 |
+
*/
|
84 |
+
|
85 |
+
typedef struct _zend_cfg {
|
86 |
+
int blocks_count; /* number of basic blocks */
|
87 |
+
zend_basic_block *blocks; /* array of basic blocks */
|
88 |
+
int *predecessors;
|
89 |
+
uint32_t *map;
|
90 |
+
unsigned int split_at_live_ranges : 1;
|
91 |
+
unsigned int split_at_calls : 1;
|
92 |
+
unsigned int split_at_recv : 1;
|
93 |
+
} zend_cfg;
|
94 |
+
|
95 |
+
/* Build Flags */
|
96 |
+
#define ZEND_RT_CONSTANTS (1<<31)
|
97 |
+
#define ZEND_CFG_STACKLESS (1<<30)
|
98 |
+
#define ZEND_SSA_DEBUG_LIVENESS (1<<29)
|
99 |
+
#define ZEND_SSA_DEBUG_PHI_PLACEMENT (1<<28)
|
100 |
+
#define ZEND_SSA_RC_INFERENCE (1<<27)
|
101 |
+
#define ZEND_CFG_SPLIT_AT_LIVE_RANGES (1<<26)
|
102 |
+
#define ZEND_CFG_NO_ENTRY_PREDECESSORS (1<<25)
|
103 |
+
#define ZEND_CFG_RECV_ENTRY (1<<24)
|
104 |
+
#define ZEND_CALL_TREE (1<<23)
|
105 |
+
|
106 |
+
#define CRT_CONSTANT_EX(op_array, node, rt_constants) \
|
107 |
+
((rt_constants) ? \
|
108 |
+
RT_CONSTANT(op_array, (node)) \
|
109 |
+
: \
|
110 |
+
CT_CONSTANT_EX(op_array, (node).constant) \
|
111 |
+
)
|
112 |
+
|
113 |
+
#define CRT_CONSTANT(node) \
|
114 |
+
CRT_CONSTANT_EX(op_array, node, (build_flags & ZEND_RT_CONSTANTS))
|
115 |
+
|
116 |
+
#define RETURN_VALUE_USED(opline) \
|
117 |
+
((opline)->result_type != IS_UNUSED)
|
118 |
+
|
119 |
+
BEGIN_EXTERN_C()
|
120 |
+
|
121 |
+
int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg);
|
122 |
+
|
123 |
+
END_EXTERN_C()
|
124 |
+
|
125 |
+
#endif /* ZEND_CFG_H */
|
126 |
+
|
127 |
+
/*
|
128 |
+
* Local variables:
|
129 |
+
* tab-width: 4
|
130 |
+
* c-basic-offset: 4
|
131 |
+
* indent-tabs-mode: t
|
132 |
+
* End:
|
133 |
+
*/
|
pcov-1.0.11/pcov-1.0.11/cfg/701/zend_worklist.h
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Zend Engine |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| Copyright (c) 1998-2018 The PHP Group |
|
6 |
+
+----------------------------------------------------------------------+
|
7 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
8 |
+
| that is bundled with this package in the file LICENSE, and is |
|
9 |
+
| available through the world-wide-web at the following url: |
|
10 |
+
| http://www.php.net/license/3_01.txt |
|
11 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
12 |
+
| obtain it through the world-wide-web, please send a note to |
|
13 |
+
| [email protected] so we can mail you a copy immediately. |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
| Authors: Andy Wingo <[email protected]> |
|
16 |
+
+----------------------------------------------------------------------+
|
17 |
+
*/
|
18 |
+
|
19 |
+
/* $Id:$ */
|
20 |
+
|
21 |
+
#ifndef _ZEND_WORKLIST_H_
|
22 |
+
#define _ZEND_WORKLIST_H_
|
23 |
+
|
24 |
+
#include "zend_arena.h"
|
25 |
+
#include "zend_bitset.h"
|
26 |
+
|
27 |
+
typedef struct _zend_worklist_stack {
|
28 |
+
int *buf;
|
29 |
+
int len;
|
30 |
+
int capacity;
|
31 |
+
} zend_worklist_stack;
|
32 |
+
|
33 |
+
#define ZEND_WORKLIST_STACK_ALLOCA(s, _len, use_heap) do { \
|
34 |
+
(s)->buf = (int*)do_alloca(sizeof(int) * _len, use_heap); \
|
35 |
+
(s)->len = 0; \
|
36 |
+
(s)->capacity = _len; \
|
37 |
+
} while (0)
|
38 |
+
|
39 |
+
#define ZEND_WORKLIST_STACK_FREE_ALLOCA(s, use_heap) \
|
40 |
+
free_alloca((s)->buf, use_heap)
|
41 |
+
|
42 |
+
static inline int zend_worklist_stack_prepare(zend_arena **arena, zend_worklist_stack *stack, int len)
|
43 |
+
{
|
44 |
+
ZEND_ASSERT(len >= 0);
|
45 |
+
|
46 |
+
stack->buf = (int*)zend_arena_calloc(arena, sizeof(*stack->buf), len);
|
47 |
+
if (!stack->buf) {
|
48 |
+
return FAILURE;
|
49 |
+
}
|
50 |
+
stack->len = 0;
|
51 |
+
stack->capacity = len;
|
52 |
+
|
53 |
+
return SUCCESS;
|
54 |
+
}
|
55 |
+
|
56 |
+
static inline void zend_worklist_stack_push(zend_worklist_stack *stack, int i)
|
57 |
+
{
|
58 |
+
ZEND_ASSERT(stack->len < stack->capacity);
|
59 |
+
stack->buf[stack->len++] = i;
|
60 |
+
}
|
61 |
+
|
62 |
+
static inline int zend_worklist_stack_peek(zend_worklist_stack *stack)
|
63 |
+
{
|
64 |
+
ZEND_ASSERT(stack->len);
|
65 |
+
return stack->buf[stack->len - 1];
|
66 |
+
}
|
67 |
+
|
68 |
+
static inline int zend_worklist_stack_pop(zend_worklist_stack *stack)
|
69 |
+
{
|
70 |
+
ZEND_ASSERT(stack->len);
|
71 |
+
return stack->buf[--stack->len];
|
72 |
+
}
|
73 |
+
|
74 |
+
typedef struct _zend_worklist {
|
75 |
+
zend_bitset visited;
|
76 |
+
zend_worklist_stack stack;
|
77 |
+
} zend_worklist;
|
78 |
+
|
79 |
+
#define ZEND_WORKLIST_ALLOCA(w, _len, use_heap) do { \
|
80 |
+
(w)->stack.buf = (int*)do_alloca(ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len) + sizeof(zend_ulong) * zend_bitset_len(_len), use_heap); \
|
81 |
+
(w)->stack.len = 0; \
|
82 |
+
(w)->stack.capacity = _len; \
|
83 |
+
(w)->visited = (zend_bitset)((char*)(w)->stack.buf + ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len)); \
|
84 |
+
memset((w)->visited, 0, sizeof(zend_ulong) * zend_bitset_len(_len)); \
|
85 |
+
} while (0)
|
86 |
+
|
87 |
+
#define ZEND_WORKLIST_FREE_ALLOCA(w, use_heap) \
|
88 |
+
free_alloca((w)->stack.buf, use_heap)
|
89 |
+
|
90 |
+
static inline int zend_worklist_prepare(zend_arena **arena, zend_worklist *worklist, int len)
|
91 |
+
{
|
92 |
+
ZEND_ASSERT(len >= 0);
|
93 |
+
worklist->visited = (zend_bitset)zend_arena_calloc(arena, sizeof(zend_ulong), zend_bitset_len(len));
|
94 |
+
if (!worklist->visited) {
|
95 |
+
return FAILURE;
|
96 |
+
}
|
97 |
+
return zend_worklist_stack_prepare(arena, &worklist->stack, len);
|
98 |
+
}
|
99 |
+
|
100 |
+
static inline int zend_worklist_len(zend_worklist *worklist)
|
101 |
+
{
|
102 |
+
return worklist->stack.len;
|
103 |
+
}
|
104 |
+
|
105 |
+
static inline int zend_worklist_push(zend_worklist *worklist, int i)
|
106 |
+
{
|
107 |
+
ZEND_ASSERT(i >= 0 && i < worklist->stack.capacity);
|
108 |
+
|
109 |
+
if (zend_bitset_in(worklist->visited, i)) {
|
110 |
+
return 0;
|
111 |
+
}
|
112 |
+
|
113 |
+
zend_bitset_incl(worklist->visited, i);
|
114 |
+
zend_worklist_stack_push(&worklist->stack, i);
|
115 |
+
return 1;
|
116 |
+
}
|
117 |
+
|
118 |
+
static inline int zend_worklist_peek(zend_worklist *worklist)
|
119 |
+
{
|
120 |
+
return zend_worklist_stack_peek(&worklist->stack);
|
121 |
+
}
|
122 |
+
|
123 |
+
static inline int zend_worklist_pop(zend_worklist *worklist)
|
124 |
+
{
|
125 |
+
/* Does not clear visited flag */
|
126 |
+
return zend_worklist_stack_pop(&worklist->stack);
|
127 |
+
}
|
128 |
+
|
129 |
+
#endif /* _ZEND_WORKLIST_H_ */
|
130 |
+
|
131 |
+
/*
|
132 |
+
* Local variables:
|
133 |
+
* tab-width: 4
|
134 |
+
* c-basic-offset: 4
|
135 |
+
* indent-tabs-mode: t
|
136 |
+
* End:
|
137 |
+
*/
|
pcov-1.0.11/pcov-1.0.11/cfg/702/zend_cfg.c
ADDED
@@ -0,0 +1,642 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Zend Engine, CFG - Control Flow Graph |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| Copyright (c) 1998-2018 The PHP Group |
|
6 |
+
+----------------------------------------------------------------------+
|
7 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
8 |
+
| that is bundled with this package in the file LICENSE, and is |
|
9 |
+
| available through the world-wide-web at the following url: |
|
10 |
+
| http://www.php.net/license/3_01.txt |
|
11 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
12 |
+
| obtain it through the world-wide-web, please send a note to |
|
13 |
+
| [email protected] so we can mail you a copy immediately. |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
| Authors: Dmitry Stogov <[email protected]> |
|
16 |
+
+----------------------------------------------------------------------+
|
17 |
+
|
18 |
+
This source file has been adapted for pcov so that the CFG from O+ is standalone
|
19 |
+
*/
|
20 |
+
|
21 |
+
#include "php.h"
|
22 |
+
#include "zend_compile.h"
|
23 |
+
#include "zend_cfg.h"
|
24 |
+
#include "zend_worklist.h"
|
25 |
+
|
26 |
+
/* func flags */
|
27 |
+
#define ZEND_FUNC_INDIRECT_VAR_ACCESS (1<<0) /* accesses variables by name */
|
28 |
+
#define ZEND_FUNC_HAS_CALLS (1<<1)
|
29 |
+
#define ZEND_FUNC_VARARG (1<<2) /* uses func_get_args() */
|
30 |
+
#define ZEND_FUNC_NO_LOOPS (1<<3)
|
31 |
+
#define ZEND_FUNC_IRREDUCIBLE (1<<4)
|
32 |
+
#define ZEND_FUNC_RECURSIVE (1<<7)
|
33 |
+
#define ZEND_FUNC_RECURSIVE_DIRECTLY (1<<8)
|
34 |
+
#define ZEND_FUNC_RECURSIVE_INDIRECTLY (1<<9)
|
35 |
+
#define ZEND_FUNC_HAS_EXTENDED_INFO (1<<10)
|
36 |
+
|
37 |
+
/* The following flags are valid only for return values of internal functions
|
38 |
+
* returned by zend_get_func_info()
|
39 |
+
*/
|
40 |
+
#define FUNC_MAY_WARN (1<<30)
|
41 |
+
|
42 |
+
typedef struct _zend_func_info zend_func_info;
|
43 |
+
typedef struct _zend_call_info zend_call_info;
|
44 |
+
|
45 |
+
#define ZEND_FUNC_INFO(op_array) \
|
46 |
+
((zend_func_info*)((op_array)->reserved[zend_func_info_rid]))
|
47 |
+
|
48 |
+
#define ZEND_SET_FUNC_INFO(op_array, info) do { \
|
49 |
+
zend_func_info** pinfo = (zend_func_info**)&(op_array)->reserved[zend_func_info_rid]; \
|
50 |
+
*pinfo = info; \
|
51 |
+
} while (0)
|
52 |
+
|
53 |
+
static uint32_t zend_cfg_classify_function(zend_string *name, uint32_t num_args) {
|
54 |
+
if (zend_string_equals_literal(name, "extract")) {
|
55 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
56 |
+
} else if (zend_string_equals_literal(name, "compact")) {
|
57 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
58 |
+
} else if (zend_string_equals_literal(name, "parse_str") && num_args <= 1) {
|
59 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
60 |
+
} else if (zend_string_equals_literal(name, "mb_parse_str") && num_args <= 1) {
|
61 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
62 |
+
} else if (zend_string_equals_literal(name, "get_defined_vars")) {
|
63 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
64 |
+
} else if (zend_string_equals_literal(name, "assert")) {
|
65 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
66 |
+
} else if (zend_string_equals_literal(name, "func_num_args")) {
|
67 |
+
return ZEND_FUNC_VARARG;
|
68 |
+
} else if (zend_string_equals_literal(name, "func_get_arg")) {
|
69 |
+
return ZEND_FUNC_VARARG;
|
70 |
+
} else if (zend_string_equals_literal(name, "func_get_args")) {
|
71 |
+
return ZEND_FUNC_VARARG;
|
72 |
+
} else {
|
73 |
+
return 0;
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_block *b) /* {{{ */
|
78 |
+
{
|
79 |
+
zend_basic_block *blocks = cfg->blocks;
|
80 |
+
|
81 |
+
while (1) {
|
82 |
+
int i;
|
83 |
+
|
84 |
+
b->flags |= ZEND_BB_REACHABLE;
|
85 |
+
if (b->successors_count == 0) {
|
86 |
+
b->flags |= ZEND_BB_EXIT;
|
87 |
+
return;
|
88 |
+
}
|
89 |
+
|
90 |
+
for (i = 0; i < b->successors_count; i++) {
|
91 |
+
zend_basic_block *succ = blocks + b->successors[i];
|
92 |
+
|
93 |
+
if (b->len != 0) {
|
94 |
+
zend_uchar opcode = opcodes[b->start + b->len - 1].opcode;
|
95 |
+
if (b->successors_count == 1) {
|
96 |
+
if (opcode == ZEND_JMP) {
|
97 |
+
succ->flags |= ZEND_BB_TARGET;
|
98 |
+
} else {
|
99 |
+
succ->flags |= ZEND_BB_FOLLOW;
|
100 |
+
|
101 |
+
if (cfg->split_at_calls) {
|
102 |
+
if (opcode == ZEND_INCLUDE_OR_EVAL ||
|
103 |
+
opcode == ZEND_GENERATOR_CREATE ||
|
104 |
+
opcode == ZEND_YIELD ||
|
105 |
+
opcode == ZEND_YIELD_FROM ||
|
106 |
+
opcode == ZEND_DO_FCALL ||
|
107 |
+
opcode == ZEND_DO_UCALL ||
|
108 |
+
opcode == ZEND_DO_FCALL_BY_NAME) {
|
109 |
+
succ->flags |= ZEND_BB_ENTRY;
|
110 |
+
}
|
111 |
+
}
|
112 |
+
if (cfg->split_at_recv) {
|
113 |
+
if (opcode == ZEND_RECV ||
|
114 |
+
opcode == ZEND_RECV_INIT) {
|
115 |
+
succ->flags |= ZEND_BB_RECV_ENTRY;
|
116 |
+
}
|
117 |
+
}
|
118 |
+
}
|
119 |
+
} else if (b->successors_count == 2) {
|
120 |
+
if (i == 0 || opcode == ZEND_JMPZNZ) {
|
121 |
+
succ->flags |= ZEND_BB_TARGET;
|
122 |
+
} else {
|
123 |
+
succ->flags |= ZEND_BB_FOLLOW;
|
124 |
+
}
|
125 |
+
} else {
|
126 |
+
ZEND_ASSERT(opcode == ZEND_SWITCH_LONG || opcode == ZEND_SWITCH_STRING);
|
127 |
+
if (i == b->successors_count - 1) {
|
128 |
+
succ->flags |= ZEND_BB_FOLLOW | ZEND_BB_TARGET;
|
129 |
+
} else {
|
130 |
+
succ->flags |= ZEND_BB_TARGET;
|
131 |
+
}
|
132 |
+
}
|
133 |
+
} else {
|
134 |
+
succ->flags |= ZEND_BB_FOLLOW;
|
135 |
+
}
|
136 |
+
|
137 |
+
if (i == b->successors_count - 1) {
|
138 |
+
/* Tail call optimization */
|
139 |
+
if (succ->flags & ZEND_BB_REACHABLE) {
|
140 |
+
return;
|
141 |
+
}
|
142 |
+
|
143 |
+
b = succ;
|
144 |
+
break;
|
145 |
+
} else {
|
146 |
+
/* Recusively check reachability */
|
147 |
+
if (!(succ->flags & ZEND_BB_REACHABLE)) {
|
148 |
+
zend_mark_reachable(opcodes, cfg, succ);
|
149 |
+
}
|
150 |
+
}
|
151 |
+
}
|
152 |
+
}
|
153 |
+
}
|
154 |
+
/* }}} */
|
155 |
+
|
156 |
+
static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg *cfg, int start) /* {{{ */
|
157 |
+
{
|
158 |
+
zend_basic_block *blocks = cfg->blocks;
|
159 |
+
|
160 |
+
blocks[start].flags = ZEND_BB_START;
|
161 |
+
zend_mark_reachable(op_array->opcodes, cfg, blocks + start);
|
162 |
+
|
163 |
+
if (op_array->last_live_range || op_array->last_try_catch) {
|
164 |
+
zend_basic_block *b;
|
165 |
+
int j, changed;
|
166 |
+
uint32_t *block_map = cfg->map;
|
167 |
+
|
168 |
+
do {
|
169 |
+
changed = 0;
|
170 |
+
|
171 |
+
/* Add live range paths */
|
172 |
+
for (j = 0; j < op_array->last_live_range; j++) {
|
173 |
+
zend_live_range *live_range = &op_array->live_range[j];
|
174 |
+
if (live_range->var == (uint32_t)-1) {
|
175 |
+
/* this live range already removed */
|
176 |
+
continue;
|
177 |
+
}
|
178 |
+
b = blocks + block_map[live_range->start];
|
179 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
180 |
+
while (b->len > 0 && op_array->opcodes[b->start].opcode == ZEND_NOP) {
|
181 |
+
/* check if NOP breaks incorrect smart branch */
|
182 |
+
if (b->len == 2
|
183 |
+
&& (op_array->opcodes[b->start + 1].opcode == ZEND_JMPZ
|
184 |
+
|| op_array->opcodes[b->start + 1].opcode == ZEND_JMPNZ)
|
185 |
+
&& (op_array->opcodes[b->start + 1].op1_type & (IS_CV|IS_CONST))
|
186 |
+
&& b->start > 0
|
187 |
+
&& zend_is_smart_branch(op_array->opcodes + b->start - 1)) {
|
188 |
+
break;
|
189 |
+
}
|
190 |
+
b->start++;
|
191 |
+
b->len--;
|
192 |
+
}
|
193 |
+
if (b->len == 0 && (uint32_t)b->successors[0] == block_map[live_range->end]) {
|
194 |
+
/* mark as removed (empty live range) */
|
195 |
+
live_range->var = (uint32_t)-1;
|
196 |
+
continue;
|
197 |
+
}
|
198 |
+
b->flags |= ZEND_BB_GEN_VAR;
|
199 |
+
b = blocks + block_map[live_range->end];
|
200 |
+
b->flags |= ZEND_BB_KILL_VAR;
|
201 |
+
if (!(b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE))) {
|
202 |
+
if (cfg->split_at_live_ranges) {
|
203 |
+
changed = 1;
|
204 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
205 |
+
} else {
|
206 |
+
b->flags |= ZEND_BB_UNREACHABLE_FREE;
|
207 |
+
}
|
208 |
+
}
|
209 |
+
} else {
|
210 |
+
ZEND_ASSERT(!(blocks[block_map[live_range->end]].flags & ZEND_BB_REACHABLE));
|
211 |
+
}
|
212 |
+
}
|
213 |
+
|
214 |
+
/* Add exception paths */
|
215 |
+
for (j = 0; j < op_array->last_try_catch; j++) {
|
216 |
+
|
217 |
+
/* check for jumps into the middle of try block */
|
218 |
+
b = blocks + block_map[op_array->try_catch_array[j].try_op];
|
219 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
220 |
+
zend_basic_block *end;
|
221 |
+
|
222 |
+
if (op_array->try_catch_array[j].catch_op) {
|
223 |
+
end = blocks + block_map[op_array->try_catch_array[j].catch_op];
|
224 |
+
while (b != end) {
|
225 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
226 |
+
op_array->try_catch_array[j].try_op = b->start;
|
227 |
+
break;
|
228 |
+
}
|
229 |
+
b++;
|
230 |
+
}
|
231 |
+
}
|
232 |
+
b = blocks + block_map[op_array->try_catch_array[j].try_op];
|
233 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
234 |
+
if (op_array->try_catch_array[j].finally_op) {
|
235 |
+
end = blocks + block_map[op_array->try_catch_array[j].finally_op];
|
236 |
+
while (b != end) {
|
237 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
238 |
+
op_array->try_catch_array[j].try_op = op_array->try_catch_array[j].catch_op;
|
239 |
+
changed = 1;
|
240 |
+
zend_mark_reachable(op_array->opcodes, cfg, blocks + block_map[op_array->try_catch_array[j].try_op]);
|
241 |
+
break;
|
242 |
+
}
|
243 |
+
b++;
|
244 |
+
}
|
245 |
+
}
|
246 |
+
}
|
247 |
+
}
|
248 |
+
|
249 |
+
b = blocks + block_map[op_array->try_catch_array[j].try_op];
|
250 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
251 |
+
b->flags |= ZEND_BB_TRY;
|
252 |
+
if (op_array->try_catch_array[j].catch_op) {
|
253 |
+
b = blocks + block_map[op_array->try_catch_array[j].catch_op];
|
254 |
+
b->flags |= ZEND_BB_CATCH;
|
255 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
256 |
+
changed = 1;
|
257 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
258 |
+
}
|
259 |
+
}
|
260 |
+
if (op_array->try_catch_array[j].finally_op) {
|
261 |
+
b = blocks + block_map[op_array->try_catch_array[j].finally_op];
|
262 |
+
b->flags |= ZEND_BB_FINALLY;
|
263 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
264 |
+
changed = 1;
|
265 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
266 |
+
}
|
267 |
+
}
|
268 |
+
if (op_array->try_catch_array[j].finally_end) {
|
269 |
+
b = blocks + block_map[op_array->try_catch_array[j].finally_end];
|
270 |
+
b->flags |= ZEND_BB_FINALLY_END;
|
271 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
272 |
+
changed = 1;
|
273 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
274 |
+
}
|
275 |
+
}
|
276 |
+
} else {
|
277 |
+
if (op_array->try_catch_array[j].catch_op) {
|
278 |
+
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].catch_op]].flags & ZEND_BB_REACHABLE));
|
279 |
+
}
|
280 |
+
if (op_array->try_catch_array[j].finally_op) {
|
281 |
+
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_op]].flags & ZEND_BB_REACHABLE));
|
282 |
+
}
|
283 |
+
if (op_array->try_catch_array[j].finally_end) {
|
284 |
+
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_end]].flags & ZEND_BB_REACHABLE));
|
285 |
+
}
|
286 |
+
}
|
287 |
+
}
|
288 |
+
} while (changed);
|
289 |
+
}
|
290 |
+
}
|
291 |
+
/* }}} */
|
292 |
+
|
293 |
+
static void initialize_block(zend_basic_block *block) {
|
294 |
+
block->flags = 0;
|
295 |
+
block->successors = block->successors_storage;
|
296 |
+
block->successors_count = 0;
|
297 |
+
block->predecessors_count = 0;
|
298 |
+
block->predecessor_offset = -1;
|
299 |
+
block->idom = -1;
|
300 |
+
block->loop_header = -1;
|
301 |
+
block->level = -1;
|
302 |
+
block->children = -1;
|
303 |
+
block->next_child = -1;
|
304 |
+
}
|
305 |
+
|
306 |
+
#define BB_START(i) do { \
|
307 |
+
if (!block_map[i]) { blocks_count++;} \
|
308 |
+
block_map[i]++; \
|
309 |
+
} while (0)
|
310 |
+
|
311 |
+
int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg) /* {{{ */
|
312 |
+
{
|
313 |
+
uint32_t flags = 0;
|
314 |
+
uint32_t i;
|
315 |
+
int j;
|
316 |
+
uint32_t *block_map;
|
317 |
+
zend_function *fn;
|
318 |
+
int blocks_count = 0;
|
319 |
+
zend_basic_block *blocks;
|
320 |
+
zval *zv;
|
321 |
+
zend_bool extra_entry_block = 0;
|
322 |
+
|
323 |
+
cfg->split_at_live_ranges = (build_flags & ZEND_CFG_SPLIT_AT_LIVE_RANGES) != 0;
|
324 |
+
cfg->split_at_calls = (build_flags & ZEND_CFG_STACKLESS) != 0;
|
325 |
+
cfg->split_at_recv = (build_flags & ZEND_CFG_RECV_ENTRY) != 0 && (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0;
|
326 |
+
|
327 |
+
cfg->map = block_map = zend_arena_calloc(arena, op_array->last, sizeof(uint32_t));
|
328 |
+
|
329 |
+
/* Build CFG, Step 1: Find basic blocks starts, calculate number of blocks */
|
330 |
+
BB_START(0);
|
331 |
+
for (i = 0; i < op_array->last; i++) {
|
332 |
+
zend_op *opline = op_array->opcodes + i;
|
333 |
+
switch(opline->opcode) {
|
334 |
+
case ZEND_RECV:
|
335 |
+
case ZEND_RECV_INIT:
|
336 |
+
if (build_flags & ZEND_CFG_RECV_ENTRY) {
|
337 |
+
BB_START(i + 1);
|
338 |
+
}
|
339 |
+
break;
|
340 |
+
case ZEND_RETURN:
|
341 |
+
case ZEND_RETURN_BY_REF:
|
342 |
+
case ZEND_GENERATOR_RETURN:
|
343 |
+
case ZEND_EXIT:
|
344 |
+
case ZEND_THROW:
|
345 |
+
if (i + 1 < op_array->last) {
|
346 |
+
BB_START(i + 1);
|
347 |
+
}
|
348 |
+
break;
|
349 |
+
case ZEND_INCLUDE_OR_EVAL:
|
350 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
351 |
+
case ZEND_GENERATOR_CREATE:
|
352 |
+
case ZEND_YIELD:
|
353 |
+
case ZEND_YIELD_FROM:
|
354 |
+
if (build_flags & ZEND_CFG_STACKLESS) {
|
355 |
+
BB_START(i + 1);
|
356 |
+
}
|
357 |
+
break;
|
358 |
+
case ZEND_DO_FCALL:
|
359 |
+
case ZEND_DO_UCALL:
|
360 |
+
case ZEND_DO_FCALL_BY_NAME:
|
361 |
+
flags |= ZEND_FUNC_HAS_CALLS;
|
362 |
+
if (build_flags & ZEND_CFG_STACKLESS) {
|
363 |
+
BB_START(i + 1);
|
364 |
+
}
|
365 |
+
break;
|
366 |
+
case ZEND_DO_ICALL:
|
367 |
+
flags |= ZEND_FUNC_HAS_CALLS;
|
368 |
+
break;
|
369 |
+
case ZEND_INIT_FCALL:
|
370 |
+
case ZEND_INIT_NS_FCALL_BY_NAME:
|
371 |
+
zv = CRT_CONSTANT(opline->op2);
|
372 |
+
if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
|
373 |
+
/* The third literal is the lowercased unqualified name */
|
374 |
+
zv += 2;
|
375 |
+
}
|
376 |
+
if ((fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv))) != NULL) {
|
377 |
+
if (fn->type == ZEND_INTERNAL_FUNCTION) {
|
378 |
+
flags |= zend_cfg_classify_function(
|
379 |
+
Z_STR_P(zv), opline->extended_value);
|
380 |
+
}
|
381 |
+
}
|
382 |
+
break;
|
383 |
+
case ZEND_FAST_CALL:
|
384 |
+
BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
|
385 |
+
BB_START(i + 1);
|
386 |
+
break;
|
387 |
+
case ZEND_FAST_RET:
|
388 |
+
if (i + 1 < op_array->last) {
|
389 |
+
BB_START(i + 1);
|
390 |
+
}
|
391 |
+
break;
|
392 |
+
case ZEND_JMP:
|
393 |
+
BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
|
394 |
+
if (i + 1 < op_array->last) {
|
395 |
+
BB_START(i + 1);
|
396 |
+
}
|
397 |
+
break;
|
398 |
+
case ZEND_JMPZNZ:
|
399 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
400 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
401 |
+
if (i + 1 < op_array->last) {
|
402 |
+
BB_START(i + 1);
|
403 |
+
}
|
404 |
+
break;
|
405 |
+
case ZEND_JMPZ:
|
406 |
+
case ZEND_JMPNZ:
|
407 |
+
case ZEND_JMPZ_EX:
|
408 |
+
case ZEND_JMPNZ_EX:
|
409 |
+
case ZEND_JMP_SET:
|
410 |
+
case ZEND_COALESCE:
|
411 |
+
case ZEND_ASSERT_CHECK:
|
412 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
413 |
+
BB_START(i + 1);
|
414 |
+
break;
|
415 |
+
case ZEND_CATCH:
|
416 |
+
if (!opline->result.num) {
|
417 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
418 |
+
}
|
419 |
+
BB_START(i + 1);
|
420 |
+
break;
|
421 |
+
case ZEND_DECLARE_ANON_CLASS:
|
422 |
+
case ZEND_DECLARE_ANON_INHERITED_CLASS:
|
423 |
+
case ZEND_FE_FETCH_R:
|
424 |
+
case ZEND_FE_FETCH_RW:
|
425 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
426 |
+
BB_START(i + 1);
|
427 |
+
break;
|
428 |
+
case ZEND_FE_RESET_R:
|
429 |
+
case ZEND_FE_RESET_RW:
|
430 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
431 |
+
BB_START(i + 1);
|
432 |
+
break;
|
433 |
+
case ZEND_SWITCH_LONG:
|
434 |
+
case ZEND_SWITCH_STRING:
|
435 |
+
{
|
436 |
+
HashTable *jumptable = Z_ARRVAL_P(CRT_CONSTANT(opline->op2));
|
437 |
+
zval *zv;
|
438 |
+
ZEND_HASH_FOREACH_VAL(jumptable, zv) {
|
439 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv)));
|
440 |
+
} ZEND_HASH_FOREACH_END();
|
441 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
442 |
+
BB_START(i + 1);
|
443 |
+
break;
|
444 |
+
}
|
445 |
+
case ZEND_UNSET_VAR:
|
446 |
+
case ZEND_ISSET_ISEMPTY_VAR:
|
447 |
+
if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL) {
|
448 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
449 |
+
} else if (((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL ||
|
450 |
+
(opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL_LOCK) &&
|
451 |
+
!op_array->function_name) {
|
452 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
453 |
+
}
|
454 |
+
break;
|
455 |
+
case ZEND_FETCH_R:
|
456 |
+
case ZEND_FETCH_W:
|
457 |
+
case ZEND_FETCH_RW:
|
458 |
+
case ZEND_FETCH_FUNC_ARG:
|
459 |
+
case ZEND_FETCH_IS:
|
460 |
+
case ZEND_FETCH_UNSET:
|
461 |
+
if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL) {
|
462 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
463 |
+
} else if (((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL ||
|
464 |
+
(opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL_LOCK) &&
|
465 |
+
!op_array->function_name) {
|
466 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
467 |
+
}
|
468 |
+
break;
|
469 |
+
case ZEND_FUNC_GET_ARGS:
|
470 |
+
flags |= ZEND_FUNC_VARARG;
|
471 |
+
break;
|
472 |
+
}
|
473 |
+
}
|
474 |
+
|
475 |
+
/* If the entry block has predecessors, we may need to split it */
|
476 |
+
if ((build_flags & ZEND_CFG_NO_ENTRY_PREDECESSORS)
|
477 |
+
&& op_array->last > 0 && block_map[0] > 1) {
|
478 |
+
extra_entry_block = 1;
|
479 |
+
}
|
480 |
+
|
481 |
+
if (cfg->split_at_live_ranges) {
|
482 |
+
for (j = 0; j < op_array->last_live_range; j++) {
|
483 |
+
BB_START(op_array->live_range[j].start);
|
484 |
+
BB_START(op_array->live_range[j].end);
|
485 |
+
}
|
486 |
+
}
|
487 |
+
|
488 |
+
if (op_array->last_try_catch) {
|
489 |
+
for (j = 0; j < op_array->last_try_catch; j++) {
|
490 |
+
BB_START(op_array->try_catch_array[j].try_op);
|
491 |
+
if (op_array->try_catch_array[j].catch_op) {
|
492 |
+
BB_START(op_array->try_catch_array[j].catch_op);
|
493 |
+
}
|
494 |
+
if (op_array->try_catch_array[j].finally_op) {
|
495 |
+
BB_START(op_array->try_catch_array[j].finally_op);
|
496 |
+
}
|
497 |
+
if (op_array->try_catch_array[j].finally_end) {
|
498 |
+
BB_START(op_array->try_catch_array[j].finally_end);
|
499 |
+
}
|
500 |
+
}
|
501 |
+
}
|
502 |
+
|
503 |
+
blocks_count += extra_entry_block;
|
504 |
+
cfg->blocks_count = blocks_count;
|
505 |
+
|
506 |
+
/* Build CFG, Step 2: Build Array of Basic Blocks */
|
507 |
+
cfg->blocks = blocks = zend_arena_calloc(arena, sizeof(zend_basic_block), blocks_count);
|
508 |
+
|
509 |
+
blocks_count = -1;
|
510 |
+
|
511 |
+
if (extra_entry_block) {
|
512 |
+
initialize_block(&blocks[0]);
|
513 |
+
blocks[0].start = 0;
|
514 |
+
blocks[0].len = 0;
|
515 |
+
blocks_count++;
|
516 |
+
}
|
517 |
+
|
518 |
+
for (i = 0; i < op_array->last; i++) {
|
519 |
+
if (block_map[i]) {
|
520 |
+
if (blocks_count >= 0) {
|
521 |
+
blocks[blocks_count].len = i - blocks[blocks_count].start;
|
522 |
+
}
|
523 |
+
blocks_count++;
|
524 |
+
initialize_block(&blocks[blocks_count]);
|
525 |
+
blocks[blocks_count].start = i;
|
526 |
+
}
|
527 |
+
block_map[i] = blocks_count;
|
528 |
+
}
|
529 |
+
|
530 |
+
blocks[blocks_count].len = i - blocks[blocks_count].start;
|
531 |
+
blocks_count++;
|
532 |
+
|
533 |
+
/* Build CFG, Step 3: Calculate successors */
|
534 |
+
for (j = 0; j < blocks_count; j++) {
|
535 |
+
zend_basic_block *block = &blocks[j];
|
536 |
+
zend_op *opline;
|
537 |
+
if (block->len == 0) {
|
538 |
+
block->successors_count = 1;
|
539 |
+
block->successors[0] = j + 1;
|
540 |
+
continue;
|
541 |
+
}
|
542 |
+
|
543 |
+
opline = op_array->opcodes + block->start + block->len - 1;
|
544 |
+
switch (opline->opcode) {
|
545 |
+
case ZEND_FAST_RET:
|
546 |
+
case ZEND_RETURN:
|
547 |
+
case ZEND_RETURN_BY_REF:
|
548 |
+
case ZEND_GENERATOR_RETURN:
|
549 |
+
case ZEND_EXIT:
|
550 |
+
case ZEND_THROW:
|
551 |
+
break;
|
552 |
+
case ZEND_JMP:
|
553 |
+
block->successors_count = 1;
|
554 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes];
|
555 |
+
break;
|
556 |
+
case ZEND_JMPZNZ:
|
557 |
+
block->successors_count = 2;
|
558 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
|
559 |
+
block->successors[1] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
|
560 |
+
break;
|
561 |
+
case ZEND_JMPZ:
|
562 |
+
case ZEND_JMPNZ:
|
563 |
+
case ZEND_JMPZ_EX:
|
564 |
+
case ZEND_JMPNZ_EX:
|
565 |
+
case ZEND_JMP_SET:
|
566 |
+
case ZEND_COALESCE:
|
567 |
+
case ZEND_ASSERT_CHECK:
|
568 |
+
block->successors_count = 2;
|
569 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
|
570 |
+
block->successors[1] = j + 1;
|
571 |
+
break;
|
572 |
+
case ZEND_CATCH:
|
573 |
+
if (!opline->result.num) {
|
574 |
+
block->successors_count = 2;
|
575 |
+
block->successors[0] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
|
576 |
+
block->successors[1] = j + 1;
|
577 |
+
} else {
|
578 |
+
block->successors_count = 1;
|
579 |
+
block->successors[0] = j + 1;
|
580 |
+
}
|
581 |
+
break;
|
582 |
+
case ZEND_DECLARE_ANON_CLASS:
|
583 |
+
case ZEND_DECLARE_ANON_INHERITED_CLASS:
|
584 |
+
case ZEND_FE_FETCH_R:
|
585 |
+
case ZEND_FE_FETCH_RW:
|
586 |
+
block->successors_count = 2;
|
587 |
+
block->successors[0] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
|
588 |
+
block->successors[1] = j + 1;
|
589 |
+
break;
|
590 |
+
case ZEND_FE_RESET_R:
|
591 |
+
case ZEND_FE_RESET_RW:
|
592 |
+
block->successors_count = 2;
|
593 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
|
594 |
+
block->successors[1] = j + 1;
|
595 |
+
break;
|
596 |
+
case ZEND_FAST_CALL:
|
597 |
+
block->successors_count = 2;
|
598 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes];
|
599 |
+
block->successors[1] = j + 1;
|
600 |
+
break;
|
601 |
+
case ZEND_SWITCH_LONG:
|
602 |
+
case ZEND_SWITCH_STRING:
|
603 |
+
{
|
604 |
+
HashTable *jumptable = Z_ARRVAL_P(CRT_CONSTANT(opline->op2));
|
605 |
+
zval *zv;
|
606 |
+
uint32_t s = 0;
|
607 |
+
|
608 |
+
block->successors_count = 2 + zend_hash_num_elements(jumptable);
|
609 |
+
block->successors = zend_arena_calloc(arena, block->successors_count, sizeof(int));
|
610 |
+
|
611 |
+
ZEND_HASH_FOREACH_VAL(jumptable, zv) {
|
612 |
+
block->successors[s++] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv))];
|
613 |
+
} ZEND_HASH_FOREACH_END();
|
614 |
+
|
615 |
+
block->successors[s++] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
|
616 |
+
block->successors[s++] = j + 1;
|
617 |
+
break;
|
618 |
+
}
|
619 |
+
default:
|
620 |
+
block->successors_count = 1;
|
621 |
+
block->successors[0] = j + 1;
|
622 |
+
break;
|
623 |
+
}
|
624 |
+
}
|
625 |
+
|
626 |
+
/* Build CFG, Step 4, Mark Reachable Basic Blocks */
|
627 |
+
zend_mark_reachable_blocks(op_array, cfg, 0);
|
628 |
+
|
629 |
+
cfg->dynamic = (flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0;
|
630 |
+
cfg->vararg = (flags & ZEND_FUNC_VARARG) != 0;
|
631 |
+
|
632 |
+
return SUCCESS;
|
633 |
+
}
|
634 |
+
/* }}} */
|
635 |
+
|
636 |
+
/*
|
637 |
+
* Local variables:
|
638 |
+
* tab-width: 4
|
639 |
+
* c-basic-offset: 4
|
640 |
+
* indent-tabs-mode: t
|
641 |
+
* End:
|
642 |
+
*/
|
pcov-1.0.11/pcov-1.0.11/cfg/702/zend_cfg.h
ADDED
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Zend Engine, CFG - Control Flow Graph |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| Copyright (c) 1998-2018 The PHP Group |
|
6 |
+
+----------------------------------------------------------------------+
|
7 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
8 |
+
| that is bundled with this package in the file LICENSE, and is |
|
9 |
+
| available through the world-wide-web at the following url: |
|
10 |
+
| http://www.php.net/license/3_01.txt |
|
11 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
12 |
+
| obtain it through the world-wide-web, please send a note to |
|
13 |
+
| [email protected] so we can mail you a copy immediately. |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
| Authors: Dmitry Stogov <[email protected]> |
|
16 |
+
+----------------------------------------------------------------------+
|
17 |
+
*/
|
18 |
+
|
19 |
+
#ifndef ZEND_CFG_H
|
20 |
+
#define ZEND_CFG_H
|
21 |
+
|
22 |
+
/* zend_basic_bloc.flags */
|
23 |
+
#define ZEND_BB_START (1<<0) /* fist block */
|
24 |
+
#define ZEND_BB_FOLLOW (1<<1) /* follows the next block */
|
25 |
+
#define ZEND_BB_TARGET (1<<2) /* jump taget */
|
26 |
+
#define ZEND_BB_EXIT (1<<3) /* without successors */
|
27 |
+
#define ZEND_BB_ENTRY (1<<4) /* stackless entry */
|
28 |
+
#define ZEND_BB_TRY (1<<5) /* start of try block */
|
29 |
+
#define ZEND_BB_CATCH (1<<6) /* start of catch block */
|
30 |
+
#define ZEND_BB_FINALLY (1<<7) /* start of finally block */
|
31 |
+
#define ZEND_BB_FINALLY_END (1<<8) /* end of finally block */
|
32 |
+
#define ZEND_BB_GEN_VAR (1<<9) /* start of live range */
|
33 |
+
#define ZEND_BB_KILL_VAR (1<<10) /* end of live range */
|
34 |
+
#define ZEND_BB_UNREACHABLE_FREE (1<<11) /* unreachable loop free */
|
35 |
+
#define ZEND_BB_RECV_ENTRY (1<<12) /* RECV entry */
|
36 |
+
|
37 |
+
#define ZEND_BB_LOOP_HEADER (1<<16)
|
38 |
+
#define ZEND_BB_IRREDUCIBLE_LOOP (1<<17)
|
39 |
+
|
40 |
+
#define ZEND_BB_REACHABLE (1<<31)
|
41 |
+
|
42 |
+
#define ZEND_BB_PROTECTED (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY|ZEND_BB_TRY|ZEND_BB_CATCH|ZEND_BB_FINALLY|ZEND_BB_FINALLY_END|ZEND_BB_GEN_VAR|ZEND_BB_KILL_VAR)
|
43 |
+
|
44 |
+
typedef struct _zend_basic_block {
|
45 |
+
int *successors; /* successor block indices */
|
46 |
+
uint32_t flags;
|
47 |
+
uint32_t start; /* first opcode number */
|
48 |
+
uint32_t len; /* number of opcodes */
|
49 |
+
int successors_count; /* number of successors */
|
50 |
+
int predecessors_count; /* number of predecessors */
|
51 |
+
int predecessor_offset; /* offset of 1-st predecessor */
|
52 |
+
int idom; /* immediate dominator block */
|
53 |
+
int loop_header; /* closest loop header, or -1 */
|
54 |
+
int level; /* steps away from the entry in the dom. tree */
|
55 |
+
int children; /* list of dominated blocks */
|
56 |
+
int next_child; /* next dominated block */
|
57 |
+
int successors_storage[2]; /* up to 2 successor blocks */
|
58 |
+
} zend_basic_block;
|
59 |
+
|
60 |
+
/*
|
61 |
+
+------------+---+---+---+---+---+
|
62 |
+
| |OP1|OP2|EXT| 0 | 1 |
|
63 |
+
+------------+---+---+---+---+---+
|
64 |
+
|JMP |ADR| | |OP1| - |
|
65 |
+
|JMPZ | |ADR| |OP2|FOL|
|
66 |
+
|JMPNZ | |ADR| |OP2|FOL|
|
67 |
+
|JMPZNZ | |ADR|ADR|OP2|EXT|
|
68 |
+
|JMPZ_EX | |ADR| |OP2|FOL|
|
69 |
+
|JMPNZ_EX | |ADR| |OP2|FOL|
|
70 |
+
|JMP_SET | |ADR| |OP2|FOL|
|
71 |
+
|COALESCE | |ADR| |OP2|FOL|
|
72 |
+
|ASSERT_CHK | |ADR| |OP2|FOL|
|
73 |
+
|NEW | |ADR| |OP2|FOL|
|
74 |
+
|DCL_ANON* |ADR| | |OP1|FOL|
|
75 |
+
|FE_RESET_* | |ADR| |OP2|FOL|
|
76 |
+
|FE_FETCH_* | | |ADR|EXT|FOL|
|
77 |
+
|CATCH | | |ADR|EXT|FOL|
|
78 |
+
|FAST_CALL |ADR| | |OP1|FOL|
|
79 |
+
|FAST_RET | | | | - | - |
|
80 |
+
|RETURN* | | | | - | - |
|
81 |
+
|EXIT | | | | - | - |
|
82 |
+
|THROW | | | | - | - |
|
83 |
+
|* | | | |FOL| - |
|
84 |
+
+------------+---+---+---+---+---+
|
85 |
+
*/
|
86 |
+
|
87 |
+
typedef struct _zend_cfg {
|
88 |
+
int blocks_count; /* number of basic blocks */
|
89 |
+
int edges_count; /* number of edges */
|
90 |
+
zend_basic_block *blocks; /* array of basic blocks */
|
91 |
+
int *predecessors;
|
92 |
+
uint32_t *map;
|
93 |
+
unsigned int split_at_live_ranges : 1;
|
94 |
+
unsigned int split_at_calls : 1;
|
95 |
+
unsigned int split_at_recv : 1;
|
96 |
+
unsigned int dynamic : 1; /* accesses varables by name */
|
97 |
+
unsigned int vararg : 1; /* uses func_get_args() */
|
98 |
+
} zend_cfg;
|
99 |
+
|
100 |
+
/* Build Flags */
|
101 |
+
#define ZEND_RT_CONSTANTS (1<<31)
|
102 |
+
#define ZEND_CFG_STACKLESS (1<<30)
|
103 |
+
#define ZEND_SSA_DEBUG_LIVENESS (1<<29)
|
104 |
+
#define ZEND_SSA_DEBUG_PHI_PLACEMENT (1<<28)
|
105 |
+
#define ZEND_SSA_RC_INFERENCE (1<<27)
|
106 |
+
#define ZEND_CFG_SPLIT_AT_LIVE_RANGES (1<<26)
|
107 |
+
#define ZEND_CFG_NO_ENTRY_PREDECESSORS (1<<25)
|
108 |
+
#define ZEND_CFG_RECV_ENTRY (1<<24)
|
109 |
+
#define ZEND_CALL_TREE (1<<23)
|
110 |
+
#define ZEND_SSA_USE_CV_RESULTS (1<<22)
|
111 |
+
|
112 |
+
#define CRT_CONSTANT_EX(op_array, node, rt_constants) \
|
113 |
+
((rt_constants) ? \
|
114 |
+
RT_CONSTANT(op_array, (node)) \
|
115 |
+
: \
|
116 |
+
CT_CONSTANT_EX(op_array, (node).constant) \
|
117 |
+
)
|
118 |
+
|
119 |
+
#define CRT_CONSTANT(node) \
|
120 |
+
CRT_CONSTANT_EX(op_array, node, (build_flags & ZEND_RT_CONSTANTS))
|
121 |
+
|
122 |
+
#define RETURN_VALUE_USED(opline) \
|
123 |
+
((opline)->result_type != IS_UNUSED)
|
124 |
+
|
125 |
+
BEGIN_EXTERN_C()
|
126 |
+
|
127 |
+
int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg);
|
128 |
+
|
129 |
+
END_EXTERN_C()
|
130 |
+
|
131 |
+
#endif /* ZEND_CFG_H */
|
132 |
+
|
133 |
+
/*
|
134 |
+
* Local variables:
|
135 |
+
* tab-width: 4
|
136 |
+
* c-basic-offset: 4
|
137 |
+
* indent-tabs-mode: t
|
138 |
+
* End:
|
139 |
+
*/
|
pcov-1.0.11/pcov-1.0.11/cfg/702/zend_worklist.h
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Zend Engine |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| Copyright (c) 1998-2018 The PHP Group |
|
6 |
+
+----------------------------------------------------------------------+
|
7 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
8 |
+
| that is bundled with this package in the file LICENSE, and is |
|
9 |
+
| available through the world-wide-web at the following url: |
|
10 |
+
| http://www.php.net/license/3_01.txt |
|
11 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
12 |
+
| obtain it through the world-wide-web, please send a note to |
|
13 |
+
| [email protected] so we can mail you a copy immediately. |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
| Authors: Andy Wingo <[email protected]> |
|
16 |
+
+----------------------------------------------------------------------+
|
17 |
+
*/
|
18 |
+
|
19 |
+
/* $Id:$ */
|
20 |
+
|
21 |
+
#ifndef _ZEND_WORKLIST_H_
|
22 |
+
#define _ZEND_WORKLIST_H_
|
23 |
+
|
24 |
+
#include "zend_arena.h"
|
25 |
+
#include "zend_bitset.h"
|
26 |
+
|
27 |
+
typedef struct _zend_worklist_stack {
|
28 |
+
int *buf;
|
29 |
+
int len;
|
30 |
+
int capacity;
|
31 |
+
} zend_worklist_stack;
|
32 |
+
|
33 |
+
#define ZEND_WORKLIST_STACK_ALLOCA(s, _len, use_heap) do { \
|
34 |
+
(s)->buf = (int*)do_alloca(sizeof(int) * _len, use_heap); \
|
35 |
+
(s)->len = 0; \
|
36 |
+
(s)->capacity = _len; \
|
37 |
+
} while (0)
|
38 |
+
|
39 |
+
#define ZEND_WORKLIST_STACK_FREE_ALLOCA(s, use_heap) \
|
40 |
+
free_alloca((s)->buf, use_heap)
|
41 |
+
|
42 |
+
static inline int zend_worklist_stack_prepare(zend_arena **arena, zend_worklist_stack *stack, int len)
|
43 |
+
{
|
44 |
+
ZEND_ASSERT(len >= 0);
|
45 |
+
|
46 |
+
stack->buf = (int*)zend_arena_calloc(arena, sizeof(*stack->buf), len);
|
47 |
+
stack->len = 0;
|
48 |
+
stack->capacity = len;
|
49 |
+
|
50 |
+
return SUCCESS;
|
51 |
+
}
|
52 |
+
|
53 |
+
static inline void zend_worklist_stack_push(zend_worklist_stack *stack, int i)
|
54 |
+
{
|
55 |
+
ZEND_ASSERT(stack->len < stack->capacity);
|
56 |
+
stack->buf[stack->len++] = i;
|
57 |
+
}
|
58 |
+
|
59 |
+
static inline int zend_worklist_stack_peek(zend_worklist_stack *stack)
|
60 |
+
{
|
61 |
+
ZEND_ASSERT(stack->len);
|
62 |
+
return stack->buf[stack->len - 1];
|
63 |
+
}
|
64 |
+
|
65 |
+
static inline int zend_worklist_stack_pop(zend_worklist_stack *stack)
|
66 |
+
{
|
67 |
+
ZEND_ASSERT(stack->len);
|
68 |
+
return stack->buf[--stack->len];
|
69 |
+
}
|
70 |
+
|
71 |
+
typedef struct _zend_worklist {
|
72 |
+
zend_bitset visited;
|
73 |
+
zend_worklist_stack stack;
|
74 |
+
} zend_worklist;
|
75 |
+
|
76 |
+
#define ZEND_WORKLIST_ALLOCA(w, _len, use_heap) do { \
|
77 |
+
(w)->stack.buf = (int*)do_alloca(ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len) + sizeof(zend_ulong) * zend_bitset_len(_len), use_heap); \
|
78 |
+
(w)->stack.len = 0; \
|
79 |
+
(w)->stack.capacity = _len; \
|
80 |
+
(w)->visited = (zend_bitset)((char*)(w)->stack.buf + ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len)); \
|
81 |
+
memset((w)->visited, 0, sizeof(zend_ulong) * zend_bitset_len(_len)); \
|
82 |
+
} while (0)
|
83 |
+
|
84 |
+
#define ZEND_WORKLIST_FREE_ALLOCA(w, use_heap) \
|
85 |
+
free_alloca((w)->stack.buf, use_heap)
|
86 |
+
|
87 |
+
static inline int zend_worklist_prepare(zend_arena **arena, zend_worklist *worklist, int len)
|
88 |
+
{
|
89 |
+
ZEND_ASSERT(len >= 0);
|
90 |
+
worklist->visited = (zend_bitset)zend_arena_calloc(arena, sizeof(zend_ulong), zend_bitset_len(len));
|
91 |
+
return zend_worklist_stack_prepare(arena, &worklist->stack, len);
|
92 |
+
}
|
93 |
+
|
94 |
+
static inline int zend_worklist_len(zend_worklist *worklist)
|
95 |
+
{
|
96 |
+
return worklist->stack.len;
|
97 |
+
}
|
98 |
+
|
99 |
+
static inline int zend_worklist_push(zend_worklist *worklist, int i)
|
100 |
+
{
|
101 |
+
ZEND_ASSERT(i >= 0 && i < worklist->stack.capacity);
|
102 |
+
|
103 |
+
if (zend_bitset_in(worklist->visited, i)) {
|
104 |
+
return 0;
|
105 |
+
}
|
106 |
+
|
107 |
+
zend_bitset_incl(worklist->visited, i);
|
108 |
+
zend_worklist_stack_push(&worklist->stack, i);
|
109 |
+
return 1;
|
110 |
+
}
|
111 |
+
|
112 |
+
static inline int zend_worklist_peek(zend_worklist *worklist)
|
113 |
+
{
|
114 |
+
return zend_worklist_stack_peek(&worklist->stack);
|
115 |
+
}
|
116 |
+
|
117 |
+
static inline int zend_worklist_pop(zend_worklist *worklist)
|
118 |
+
{
|
119 |
+
/* Does not clear visited flag */
|
120 |
+
return zend_worklist_stack_pop(&worklist->stack);
|
121 |
+
}
|
122 |
+
|
123 |
+
#endif /* _ZEND_WORKLIST_H_ */
|
124 |
+
|
125 |
+
/*
|
126 |
+
* Local variables:
|
127 |
+
* tab-width: 4
|
128 |
+
* c-basic-offset: 4
|
129 |
+
* indent-tabs-mode: t
|
130 |
+
* End:
|
131 |
+
*/
|
pcov-1.0.11/pcov-1.0.11/cfg/703/zend_cfg.c
ADDED
@@ -0,0 +1,643 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Zend Engine, CFG - Control Flow Graph |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| Copyright (c) 1998-2018 The PHP Group |
|
6 |
+
+----------------------------------------------------------------------+
|
7 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
8 |
+
| that is bundled with this package in the file LICENSE, and is |
|
9 |
+
| available through the world-wide-web at the following url: |
|
10 |
+
| http://www.php.net/license/3_01.txt |
|
11 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
12 |
+
| obtain it through the world-wide-web, please send a note to |
|
13 |
+
| [email protected] so we can mail you a copy immediately. |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
| Authors: Dmitry Stogov <[email protected]> |
|
16 |
+
+----------------------------------------------------------------------+
|
17 |
+
|
18 |
+
This source file has been adapted for pcov so that the CFG from O+ is standalone
|
19 |
+
*/
|
20 |
+
|
21 |
+
#include "php.h"
|
22 |
+
#include "zend_compile.h"
|
23 |
+
#include "zend_cfg.h"
|
24 |
+
#include "zend_worklist.h"
|
25 |
+
|
26 |
+
/* func flags */
|
27 |
+
#define ZEND_FUNC_INDIRECT_VAR_ACCESS (1<<0) /* accesses variables by name */
|
28 |
+
#define ZEND_FUNC_HAS_CALLS (1<<1)
|
29 |
+
#define ZEND_FUNC_VARARG (1<<2) /* uses func_get_args() */
|
30 |
+
#define ZEND_FUNC_NO_LOOPS (1<<3)
|
31 |
+
#define ZEND_FUNC_IRREDUCIBLE (1<<4)
|
32 |
+
#define ZEND_FUNC_RECURSIVE (1<<7)
|
33 |
+
#define ZEND_FUNC_RECURSIVE_DIRECTLY (1<<8)
|
34 |
+
#define ZEND_FUNC_RECURSIVE_INDIRECTLY (1<<9)
|
35 |
+
#define ZEND_FUNC_HAS_EXTENDED_INFO (1<<10)
|
36 |
+
|
37 |
+
/* The following flags are valid only for return values of internal functions
|
38 |
+
* returned by zend_get_func_info()
|
39 |
+
*/
|
40 |
+
#define FUNC_MAY_WARN (1<<30)
|
41 |
+
|
42 |
+
typedef struct _zend_func_info zend_func_info;
|
43 |
+
typedef struct _zend_call_info zend_call_info;
|
44 |
+
|
45 |
+
#define ZEND_FUNC_INFO(op_array) \
|
46 |
+
((zend_func_info*)((op_array)->reserved[zend_func_info_rid]))
|
47 |
+
|
48 |
+
#define ZEND_SET_FUNC_INFO(op_array, info) do { \
|
49 |
+
zend_func_info** pinfo = (zend_func_info**)&(op_array)->reserved[zend_func_info_rid]; \
|
50 |
+
*pinfo = info; \
|
51 |
+
} while (0)
|
52 |
+
|
53 |
+
static uint32_t zend_cfg_classify_function(zend_string *name, uint32_t num_args) {
|
54 |
+
if (zend_string_equals_literal(name, "extract")) {
|
55 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
56 |
+
} else if (zend_string_equals_literal(name, "compact")) {
|
57 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
58 |
+
} else if (zend_string_equals_literal(name, "parse_str") && num_args <= 1) {
|
59 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
60 |
+
} else if (zend_string_equals_literal(name, "mb_parse_str") && num_args <= 1) {
|
61 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
62 |
+
} else if (zend_string_equals_literal(name, "get_defined_vars")) {
|
63 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
64 |
+
} else if (zend_string_equals_literal(name, "assert")) {
|
65 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
66 |
+
} else if (zend_string_equals_literal(name, "func_num_args")) {
|
67 |
+
return ZEND_FUNC_VARARG;
|
68 |
+
} else if (zend_string_equals_literal(name, "func_get_arg")) {
|
69 |
+
return ZEND_FUNC_VARARG;
|
70 |
+
} else if (zend_string_equals_literal(name, "func_get_args")) {
|
71 |
+
return ZEND_FUNC_VARARG;
|
72 |
+
} else {
|
73 |
+
return 0;
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_block *b) /* {{{ */
|
78 |
+
{
|
79 |
+
zend_basic_block *blocks = cfg->blocks;
|
80 |
+
|
81 |
+
while (1) {
|
82 |
+
int i;
|
83 |
+
|
84 |
+
b->flags |= ZEND_BB_REACHABLE;
|
85 |
+
if (b->successors_count == 0) {
|
86 |
+
b->flags |= ZEND_BB_EXIT;
|
87 |
+
return;
|
88 |
+
}
|
89 |
+
|
90 |
+
for (i = 0; i < b->successors_count; i++) {
|
91 |
+
zend_basic_block *succ = blocks + b->successors[i];
|
92 |
+
|
93 |
+
if (b->len != 0) {
|
94 |
+
zend_uchar opcode = opcodes[b->start + b->len - 1].opcode;
|
95 |
+
if (b->successors_count == 1) {
|
96 |
+
if (opcode == ZEND_JMP) {
|
97 |
+
succ->flags |= ZEND_BB_TARGET;
|
98 |
+
} else {
|
99 |
+
succ->flags |= ZEND_BB_FOLLOW;
|
100 |
+
|
101 |
+
if ((cfg->flags & ZEND_CFG_STACKLESS)) {
|
102 |
+
if (opcode == ZEND_INCLUDE_OR_EVAL ||
|
103 |
+
opcode == ZEND_GENERATOR_CREATE ||
|
104 |
+
opcode == ZEND_YIELD ||
|
105 |
+
opcode == ZEND_YIELD_FROM ||
|
106 |
+
opcode == ZEND_DO_FCALL ||
|
107 |
+
opcode == ZEND_DO_UCALL ||
|
108 |
+
opcode == ZEND_DO_FCALL_BY_NAME) {
|
109 |
+
succ->flags |= ZEND_BB_ENTRY;
|
110 |
+
}
|
111 |
+
}
|
112 |
+
if ((cfg->flags & ZEND_CFG_RECV_ENTRY)) {
|
113 |
+
if (opcode == ZEND_RECV ||
|
114 |
+
opcode == ZEND_RECV_INIT) {
|
115 |
+
succ->flags |= ZEND_BB_RECV_ENTRY;
|
116 |
+
}
|
117 |
+
}
|
118 |
+
}
|
119 |
+
} else if (b->successors_count == 2) {
|
120 |
+
if (i == 0 || opcode == ZEND_JMPZNZ) {
|
121 |
+
succ->flags |= ZEND_BB_TARGET;
|
122 |
+
} else {
|
123 |
+
succ->flags |= ZEND_BB_FOLLOW;
|
124 |
+
}
|
125 |
+
} else {
|
126 |
+
ZEND_ASSERT(opcode == ZEND_SWITCH_LONG || opcode == ZEND_SWITCH_STRING);
|
127 |
+
if (i == b->successors_count - 1) {
|
128 |
+
succ->flags |= ZEND_BB_FOLLOW | ZEND_BB_TARGET;
|
129 |
+
} else {
|
130 |
+
succ->flags |= ZEND_BB_TARGET;
|
131 |
+
}
|
132 |
+
}
|
133 |
+
} else {
|
134 |
+
succ->flags |= ZEND_BB_FOLLOW;
|
135 |
+
}
|
136 |
+
|
137 |
+
if (i == b->successors_count - 1) {
|
138 |
+
/* Tail call optimization */
|
139 |
+
if (succ->flags & ZEND_BB_REACHABLE) {
|
140 |
+
return;
|
141 |
+
}
|
142 |
+
|
143 |
+
b = succ;
|
144 |
+
break;
|
145 |
+
} else {
|
146 |
+
/* Recusively check reachability */
|
147 |
+
if (!(succ->flags & ZEND_BB_REACHABLE)) {
|
148 |
+
zend_mark_reachable(opcodes, cfg, succ);
|
149 |
+
}
|
150 |
+
}
|
151 |
+
}
|
152 |
+
}
|
153 |
+
}
|
154 |
+
/* }}} */
|
155 |
+
|
156 |
+
static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg *cfg, int start) /* {{{ */
|
157 |
+
{
|
158 |
+
zend_basic_block *blocks = cfg->blocks;
|
159 |
+
|
160 |
+
blocks[start].flags = ZEND_BB_START;
|
161 |
+
zend_mark_reachable(op_array->opcodes, cfg, blocks + start);
|
162 |
+
|
163 |
+
if (op_array->last_live_range || op_array->last_try_catch) {
|
164 |
+
zend_basic_block *b;
|
165 |
+
int j, changed;
|
166 |
+
uint32_t *block_map = cfg->map;
|
167 |
+
|
168 |
+
do {
|
169 |
+
changed = 0;
|
170 |
+
|
171 |
+
/* Add live range paths */
|
172 |
+
for (j = 0; j < op_array->last_live_range; j++) {
|
173 |
+
zend_live_range *live_range = &op_array->live_range[j];
|
174 |
+
if (live_range->var == (uint32_t)-1) {
|
175 |
+
/* this live range already removed */
|
176 |
+
continue;
|
177 |
+
}
|
178 |
+
b = blocks + block_map[live_range->start];
|
179 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
180 |
+
while (b->len > 0 && op_array->opcodes[b->start].opcode == ZEND_NOP) {
|
181 |
+
/* check if NOP breaks incorrect smart branch */
|
182 |
+
if (b->len == 2
|
183 |
+
&& (op_array->opcodes[b->start + 1].opcode == ZEND_JMPZ
|
184 |
+
|| op_array->opcodes[b->start + 1].opcode == ZEND_JMPNZ)
|
185 |
+
&& (op_array->opcodes[b->start + 1].op1_type & (IS_CV|IS_CONST))
|
186 |
+
&& b->start > 0
|
187 |
+
&& zend_is_smart_branch(op_array->opcodes + b->start - 1)) {
|
188 |
+
break;
|
189 |
+
}
|
190 |
+
b->start++;
|
191 |
+
b->len--;
|
192 |
+
}
|
193 |
+
if (b->len == 0 && (uint32_t)b->successors[0] == block_map[live_range->end]) {
|
194 |
+
/* mark as removed (empty live range) */
|
195 |
+
live_range->var = (uint32_t)-1;
|
196 |
+
continue;
|
197 |
+
}
|
198 |
+
b->flags |= ZEND_BB_GEN_VAR;
|
199 |
+
b = blocks + block_map[live_range->end];
|
200 |
+
b->flags |= ZEND_BB_KILL_VAR;
|
201 |
+
if (!(b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE))) {
|
202 |
+
if ((cfg->flags & ZEND_CFG_SPLIT_AT_LIVE_RANGES)) {
|
203 |
+
changed = 1;
|
204 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
205 |
+
} else {
|
206 |
+
b->flags |= ZEND_BB_UNREACHABLE_FREE;
|
207 |
+
}
|
208 |
+
}
|
209 |
+
} else {
|
210 |
+
ZEND_ASSERT(!(blocks[block_map[live_range->end]].flags & ZEND_BB_REACHABLE));
|
211 |
+
}
|
212 |
+
}
|
213 |
+
|
214 |
+
/* Add exception paths */
|
215 |
+
for (j = 0; j < op_array->last_try_catch; j++) {
|
216 |
+
|
217 |
+
/* check for jumps into the middle of try block */
|
218 |
+
b = blocks + block_map[op_array->try_catch_array[j].try_op];
|
219 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
220 |
+
zend_basic_block *end;
|
221 |
+
|
222 |
+
if (op_array->try_catch_array[j].catch_op) {
|
223 |
+
end = blocks + block_map[op_array->try_catch_array[j].catch_op];
|
224 |
+
while (b != end) {
|
225 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
226 |
+
op_array->try_catch_array[j].try_op = b->start;
|
227 |
+
break;
|
228 |
+
}
|
229 |
+
b++;
|
230 |
+
}
|
231 |
+
}
|
232 |
+
b = blocks + block_map[op_array->try_catch_array[j].try_op];
|
233 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
234 |
+
if (op_array->try_catch_array[j].finally_op) {
|
235 |
+
end = blocks + block_map[op_array->try_catch_array[j].finally_op];
|
236 |
+
while (b != end) {
|
237 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
238 |
+
op_array->try_catch_array[j].try_op = op_array->try_catch_array[j].catch_op;
|
239 |
+
changed = 1;
|
240 |
+
zend_mark_reachable(op_array->opcodes, cfg, blocks + block_map[op_array->try_catch_array[j].try_op]);
|
241 |
+
break;
|
242 |
+
}
|
243 |
+
b++;
|
244 |
+
}
|
245 |
+
}
|
246 |
+
}
|
247 |
+
}
|
248 |
+
|
249 |
+
b = blocks + block_map[op_array->try_catch_array[j].try_op];
|
250 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
251 |
+
b->flags |= ZEND_BB_TRY;
|
252 |
+
if (op_array->try_catch_array[j].catch_op) {
|
253 |
+
b = blocks + block_map[op_array->try_catch_array[j].catch_op];
|
254 |
+
b->flags |= ZEND_BB_CATCH;
|
255 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
256 |
+
changed = 1;
|
257 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
258 |
+
}
|
259 |
+
}
|
260 |
+
if (op_array->try_catch_array[j].finally_op) {
|
261 |
+
b = blocks + block_map[op_array->try_catch_array[j].finally_op];
|
262 |
+
b->flags |= ZEND_BB_FINALLY;
|
263 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
264 |
+
changed = 1;
|
265 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
266 |
+
}
|
267 |
+
}
|
268 |
+
if (op_array->try_catch_array[j].finally_end) {
|
269 |
+
b = blocks + block_map[op_array->try_catch_array[j].finally_end];
|
270 |
+
b->flags |= ZEND_BB_FINALLY_END;
|
271 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
272 |
+
changed = 1;
|
273 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
274 |
+
}
|
275 |
+
}
|
276 |
+
} else {
|
277 |
+
if (op_array->try_catch_array[j].catch_op) {
|
278 |
+
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].catch_op]].flags & ZEND_BB_REACHABLE));
|
279 |
+
}
|
280 |
+
if (op_array->try_catch_array[j].finally_op) {
|
281 |
+
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_op]].flags & ZEND_BB_REACHABLE));
|
282 |
+
}
|
283 |
+
if (op_array->try_catch_array[j].finally_end) {
|
284 |
+
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_end]].flags & ZEND_BB_REACHABLE));
|
285 |
+
}
|
286 |
+
}
|
287 |
+
}
|
288 |
+
} while (changed);
|
289 |
+
}
|
290 |
+
}
|
291 |
+
/* }}} */
|
292 |
+
|
293 |
+
static void initialize_block(zend_basic_block *block) {
|
294 |
+
block->flags = 0;
|
295 |
+
block->successors = block->successors_storage;
|
296 |
+
block->successors_count = 0;
|
297 |
+
block->predecessors_count = 0;
|
298 |
+
block->predecessor_offset = -1;
|
299 |
+
block->idom = -1;
|
300 |
+
block->loop_header = -1;
|
301 |
+
block->level = -1;
|
302 |
+
block->children = -1;
|
303 |
+
block->next_child = -1;
|
304 |
+
}
|
305 |
+
|
306 |
+
#define BB_START(i) do { \
|
307 |
+
if (!block_map[i]) { blocks_count++;} \
|
308 |
+
block_map[i]++; \
|
309 |
+
} while (0)
|
310 |
+
|
311 |
+
int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg) /* {{{ */
|
312 |
+
{
|
313 |
+
uint32_t flags = 0;
|
314 |
+
uint32_t i;
|
315 |
+
int j;
|
316 |
+
uint32_t *block_map;
|
317 |
+
zend_function *fn;
|
318 |
+
int blocks_count = 0;
|
319 |
+
zend_basic_block *blocks;
|
320 |
+
zval *zv;
|
321 |
+
zend_bool extra_entry_block = 0;
|
322 |
+
|
323 |
+
cfg->flags = build_flags & (ZEND_CFG_SPLIT_AT_LIVE_RANGES|ZEND_CFG_STACKLESS|ZEND_CFG_RECV_ENTRY);
|
324 |
+
|
325 |
+
cfg->map = block_map = zend_arena_calloc(arena, op_array->last, sizeof(uint32_t));
|
326 |
+
|
327 |
+
/* Build CFG, Step 1: Find basic blocks starts, calculate number of blocks */
|
328 |
+
BB_START(0);
|
329 |
+
for (i = 0; i < op_array->last; i++) {
|
330 |
+
zend_op *opline = op_array->opcodes + i;
|
331 |
+
switch (opline->opcode) {
|
332 |
+
case ZEND_RECV:
|
333 |
+
case ZEND_RECV_INIT:
|
334 |
+
if (build_flags & ZEND_CFG_RECV_ENTRY) {
|
335 |
+
BB_START(i + 1);
|
336 |
+
}
|
337 |
+
break;
|
338 |
+
case ZEND_RETURN:
|
339 |
+
case ZEND_RETURN_BY_REF:
|
340 |
+
case ZEND_GENERATOR_RETURN:
|
341 |
+
case ZEND_EXIT:
|
342 |
+
case ZEND_THROW:
|
343 |
+
if (i + 1 < op_array->last) {
|
344 |
+
BB_START(i + 1);
|
345 |
+
}
|
346 |
+
break;
|
347 |
+
case ZEND_INCLUDE_OR_EVAL:
|
348 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
349 |
+
case ZEND_GENERATOR_CREATE:
|
350 |
+
case ZEND_YIELD:
|
351 |
+
case ZEND_YIELD_FROM:
|
352 |
+
if (build_flags & ZEND_CFG_STACKLESS) {
|
353 |
+
BB_START(i + 1);
|
354 |
+
}
|
355 |
+
break;
|
356 |
+
case ZEND_DO_FCALL:
|
357 |
+
case ZEND_DO_UCALL:
|
358 |
+
case ZEND_DO_FCALL_BY_NAME:
|
359 |
+
flags |= ZEND_FUNC_HAS_CALLS;
|
360 |
+
if (build_flags & ZEND_CFG_STACKLESS) {
|
361 |
+
BB_START(i + 1);
|
362 |
+
}
|
363 |
+
break;
|
364 |
+
case ZEND_DO_ICALL:
|
365 |
+
flags |= ZEND_FUNC_HAS_CALLS;
|
366 |
+
break;
|
367 |
+
case ZEND_INIT_FCALL:
|
368 |
+
case ZEND_INIT_NS_FCALL_BY_NAME:
|
369 |
+
zv = CRT_CONSTANT(opline->op2);
|
370 |
+
if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
|
371 |
+
/* The third literal is the lowercased unqualified name */
|
372 |
+
zv += 2;
|
373 |
+
}
|
374 |
+
if ((fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv))) != NULL) {
|
375 |
+
if (fn->type == ZEND_INTERNAL_FUNCTION) {
|
376 |
+
flags |= zend_cfg_classify_function(
|
377 |
+
Z_STR_P(zv), opline->extended_value);
|
378 |
+
}
|
379 |
+
}
|
380 |
+
break;
|
381 |
+
case ZEND_FAST_CALL:
|
382 |
+
BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
|
383 |
+
BB_START(i + 1);
|
384 |
+
break;
|
385 |
+
case ZEND_FAST_RET:
|
386 |
+
if (i + 1 < op_array->last) {
|
387 |
+
BB_START(i + 1);
|
388 |
+
}
|
389 |
+
break;
|
390 |
+
case ZEND_JMP:
|
391 |
+
BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
|
392 |
+
if (i + 1 < op_array->last) {
|
393 |
+
BB_START(i + 1);
|
394 |
+
}
|
395 |
+
break;
|
396 |
+
case ZEND_JMPZNZ:
|
397 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
398 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
399 |
+
if (i + 1 < op_array->last) {
|
400 |
+
BB_START(i + 1);
|
401 |
+
}
|
402 |
+
break;
|
403 |
+
case ZEND_JMPZ:
|
404 |
+
case ZEND_JMPNZ:
|
405 |
+
case ZEND_JMPZ_EX:
|
406 |
+
case ZEND_JMPNZ_EX:
|
407 |
+
case ZEND_JMP_SET:
|
408 |
+
case ZEND_COALESCE:
|
409 |
+
case ZEND_ASSERT_CHECK:
|
410 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
411 |
+
BB_START(i + 1);
|
412 |
+
break;
|
413 |
+
case ZEND_CATCH:
|
414 |
+
if (!(opline->extended_value & ZEND_LAST_CATCH)) {
|
415 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
416 |
+
}
|
417 |
+
BB_START(i + 1);
|
418 |
+
break;
|
419 |
+
case ZEND_DECLARE_ANON_CLASS:
|
420 |
+
case ZEND_DECLARE_ANON_INHERITED_CLASS:
|
421 |
+
case ZEND_FE_FETCH_R:
|
422 |
+
case ZEND_FE_FETCH_RW:
|
423 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
424 |
+
BB_START(i + 1);
|
425 |
+
break;
|
426 |
+
case ZEND_FE_RESET_R:
|
427 |
+
case ZEND_FE_RESET_RW:
|
428 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
429 |
+
BB_START(i + 1);
|
430 |
+
break;
|
431 |
+
case ZEND_SWITCH_LONG:
|
432 |
+
case ZEND_SWITCH_STRING:
|
433 |
+
{
|
434 |
+
HashTable *jumptable = Z_ARRVAL_P(CRT_CONSTANT(opline->op2));
|
435 |
+
zval *zv;
|
436 |
+
ZEND_HASH_FOREACH_VAL(jumptable, zv) {
|
437 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv)));
|
438 |
+
} ZEND_HASH_FOREACH_END();
|
439 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
440 |
+
BB_START(i + 1);
|
441 |
+
break;
|
442 |
+
}
|
443 |
+
case ZEND_UNSET_VAR:
|
444 |
+
case ZEND_ISSET_ISEMPTY_VAR:
|
445 |
+
if (opline->extended_value & ZEND_FETCH_LOCAL) {
|
446 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
447 |
+
} else if ((opline->extended_value & (ZEND_FETCH_GLOBAL | ZEND_FETCH_GLOBAL_LOCK)) &&
|
448 |
+
!op_array->function_name) {
|
449 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
450 |
+
}
|
451 |
+
break;
|
452 |
+
case ZEND_FETCH_R:
|
453 |
+
case ZEND_FETCH_W:
|
454 |
+
case ZEND_FETCH_RW:
|
455 |
+
case ZEND_FETCH_FUNC_ARG:
|
456 |
+
case ZEND_FETCH_IS:
|
457 |
+
case ZEND_FETCH_UNSET:
|
458 |
+
if (opline->extended_value & ZEND_FETCH_LOCAL) {
|
459 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
460 |
+
} else if ((opline->extended_value & (ZEND_FETCH_GLOBAL | ZEND_FETCH_GLOBAL_LOCK)) &&
|
461 |
+
!op_array->function_name) {
|
462 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
463 |
+
}
|
464 |
+
break;
|
465 |
+
case ZEND_FUNC_GET_ARGS:
|
466 |
+
flags |= ZEND_FUNC_VARARG;
|
467 |
+
break;
|
468 |
+
case ZEND_EXT_NOP:
|
469 |
+
case ZEND_EXT_STMT:
|
470 |
+
case ZEND_EXT_FCALL_BEGIN:
|
471 |
+
case ZEND_EXT_FCALL_END:
|
472 |
+
flags |= ZEND_FUNC_HAS_EXTENDED_INFO;
|
473 |
+
break;
|
474 |
+
}
|
475 |
+
}
|
476 |
+
|
477 |
+
/* If the entry block has predecessors, we may need to split it */
|
478 |
+
if ((build_flags & ZEND_CFG_NO_ENTRY_PREDECESSORS)
|
479 |
+
&& op_array->last > 0 && block_map[0] > 1) {
|
480 |
+
extra_entry_block = 1;
|
481 |
+
}
|
482 |
+
|
483 |
+
if ((cfg->flags & ZEND_CFG_SPLIT_AT_LIVE_RANGES)) {
|
484 |
+
for (j = 0; j < op_array->last_live_range; j++) {
|
485 |
+
BB_START(op_array->live_range[j].start);
|
486 |
+
BB_START(op_array->live_range[j].end);
|
487 |
+
}
|
488 |
+
}
|
489 |
+
|
490 |
+
if (op_array->last_try_catch) {
|
491 |
+
for (j = 0; j < op_array->last_try_catch; j++) {
|
492 |
+
BB_START(op_array->try_catch_array[j].try_op);
|
493 |
+
if (op_array->try_catch_array[j].catch_op) {
|
494 |
+
BB_START(op_array->try_catch_array[j].catch_op);
|
495 |
+
}
|
496 |
+
if (op_array->try_catch_array[j].finally_op) {
|
497 |
+
BB_START(op_array->try_catch_array[j].finally_op);
|
498 |
+
}
|
499 |
+
if (op_array->try_catch_array[j].finally_end) {
|
500 |
+
BB_START(op_array->try_catch_array[j].finally_end);
|
501 |
+
}
|
502 |
+
}
|
503 |
+
}
|
504 |
+
|
505 |
+
blocks_count += extra_entry_block;
|
506 |
+
cfg->blocks_count = blocks_count;
|
507 |
+
|
508 |
+
/* Build CFG, Step 2: Build Array of Basic Blocks */
|
509 |
+
cfg->blocks = blocks = zend_arena_calloc(arena, sizeof(zend_basic_block), blocks_count);
|
510 |
+
|
511 |
+
blocks_count = -1;
|
512 |
+
|
513 |
+
if (extra_entry_block) {
|
514 |
+
initialize_block(&blocks[0]);
|
515 |
+
blocks[0].start = 0;
|
516 |
+
blocks[0].len = 0;
|
517 |
+
blocks_count++;
|
518 |
+
}
|
519 |
+
|
520 |
+
for (i = 0; i < op_array->last; i++) {
|
521 |
+
if (block_map[i]) {
|
522 |
+
if (blocks_count >= 0) {
|
523 |
+
blocks[blocks_count].len = i - blocks[blocks_count].start;
|
524 |
+
}
|
525 |
+
blocks_count++;
|
526 |
+
initialize_block(&blocks[blocks_count]);
|
527 |
+
blocks[blocks_count].start = i;
|
528 |
+
}
|
529 |
+
block_map[i] = blocks_count;
|
530 |
+
}
|
531 |
+
|
532 |
+
blocks[blocks_count].len = i - blocks[blocks_count].start;
|
533 |
+
blocks_count++;
|
534 |
+
|
535 |
+
/* Build CFG, Step 3: Calculate successors */
|
536 |
+
for (j = 0; j < blocks_count; j++) {
|
537 |
+
zend_basic_block *block = &blocks[j];
|
538 |
+
zend_op *opline;
|
539 |
+
if (block->len == 0) {
|
540 |
+
block->successors_count = 1;
|
541 |
+
block->successors[0] = j + 1;
|
542 |
+
continue;
|
543 |
+
}
|
544 |
+
|
545 |
+
opline = op_array->opcodes + block->start + block->len - 1;
|
546 |
+
switch (opline->opcode) {
|
547 |
+
case ZEND_FAST_RET:
|
548 |
+
case ZEND_RETURN:
|
549 |
+
case ZEND_RETURN_BY_REF:
|
550 |
+
case ZEND_GENERATOR_RETURN:
|
551 |
+
case ZEND_EXIT:
|
552 |
+
case ZEND_THROW:
|
553 |
+
break;
|
554 |
+
case ZEND_JMP:
|
555 |
+
block->successors_count = 1;
|
556 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes];
|
557 |
+
break;
|
558 |
+
case ZEND_JMPZNZ:
|
559 |
+
block->successors_count = 2;
|
560 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
|
561 |
+
block->successors[1] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
|
562 |
+
break;
|
563 |
+
case ZEND_JMPZ:
|
564 |
+
case ZEND_JMPNZ:
|
565 |
+
case ZEND_JMPZ_EX:
|
566 |
+
case ZEND_JMPNZ_EX:
|
567 |
+
case ZEND_JMP_SET:
|
568 |
+
case ZEND_COALESCE:
|
569 |
+
case ZEND_ASSERT_CHECK:
|
570 |
+
block->successors_count = 2;
|
571 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
|
572 |
+
block->successors[1] = j + 1;
|
573 |
+
break;
|
574 |
+
case ZEND_CATCH:
|
575 |
+
if (!(opline->extended_value & ZEND_LAST_CATCH)) {
|
576 |
+
block->successors_count = 2;
|
577 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
|
578 |
+
block->successors[1] = j + 1;
|
579 |
+
} else {
|
580 |
+
block->successors_count = 1;
|
581 |
+
block->successors[0] = j + 1;
|
582 |
+
}
|
583 |
+
break;
|
584 |
+
case ZEND_DECLARE_ANON_CLASS:
|
585 |
+
case ZEND_DECLARE_ANON_INHERITED_CLASS:
|
586 |
+
case ZEND_FE_FETCH_R:
|
587 |
+
case ZEND_FE_FETCH_RW:
|
588 |
+
block->successors_count = 2;
|
589 |
+
block->successors[0] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
|
590 |
+
block->successors[1] = j + 1;
|
591 |
+
break;
|
592 |
+
case ZEND_FE_RESET_R:
|
593 |
+
case ZEND_FE_RESET_RW:
|
594 |
+
block->successors_count = 2;
|
595 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
|
596 |
+
block->successors[1] = j + 1;
|
597 |
+
break;
|
598 |
+
case ZEND_FAST_CALL:
|
599 |
+
block->successors_count = 2;
|
600 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes];
|
601 |
+
block->successors[1] = j + 1;
|
602 |
+
break;
|
603 |
+
case ZEND_SWITCH_LONG:
|
604 |
+
case ZEND_SWITCH_STRING:
|
605 |
+
{
|
606 |
+
HashTable *jumptable = Z_ARRVAL_P(CRT_CONSTANT(opline->op2));
|
607 |
+
zval *zv;
|
608 |
+
uint32_t s = 0;
|
609 |
+
|
610 |
+
block->successors_count = 2 + zend_hash_num_elements(jumptable);
|
611 |
+
block->successors = zend_arena_calloc(arena, block->successors_count, sizeof(int));
|
612 |
+
|
613 |
+
ZEND_HASH_FOREACH_VAL(jumptable, zv) {
|
614 |
+
block->successors[s++] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv))];
|
615 |
+
} ZEND_HASH_FOREACH_END();
|
616 |
+
|
617 |
+
block->successors[s++] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
|
618 |
+
block->successors[s++] = j + 1;
|
619 |
+
break;
|
620 |
+
}
|
621 |
+
default:
|
622 |
+
block->successors_count = 1;
|
623 |
+
block->successors[0] = j + 1;
|
624 |
+
break;
|
625 |
+
}
|
626 |
+
}
|
627 |
+
|
628 |
+
/* Build CFG, Step 4, Mark Reachable Basic Blocks */
|
629 |
+
zend_mark_reachable_blocks(op_array, cfg, 0);
|
630 |
+
|
631 |
+
cfg->flags |= flags;
|
632 |
+
|
633 |
+
return SUCCESS;
|
634 |
+
}
|
635 |
+
/* }}} */
|
636 |
+
|
637 |
+
/*
|
638 |
+
* Local variables:
|
639 |
+
* tab-width: 4
|
640 |
+
* c-basic-offset: 4
|
641 |
+
* indent-tabs-mode: t
|
642 |
+
* End:
|
643 |
+
*/
|
pcov-1.0.11/pcov-1.0.11/cfg/703/zend_cfg.h
ADDED
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Zend Engine, CFG - Control Flow Graph |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| Copyright (c) 1998-2018 The PHP Group |
|
6 |
+
+----------------------------------------------------------------------+
|
7 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
8 |
+
| that is bundled with this package in the file LICENSE, and is |
|
9 |
+
| available through the world-wide-web at the following url: |
|
10 |
+
| http://www.php.net/license/3_01.txt |
|
11 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
12 |
+
| obtain it through the world-wide-web, please send a note to |
|
13 |
+
| [email protected] so we can mail you a copy immediately. |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
| Authors: Dmitry Stogov <[email protected]> |
|
16 |
+
+----------------------------------------------------------------------+
|
17 |
+
*/
|
18 |
+
|
19 |
+
#ifndef ZEND_CFG_H
|
20 |
+
#define ZEND_CFG_H
|
21 |
+
|
22 |
+
/* zend_basic_bloc.flags */
|
23 |
+
#define ZEND_BB_START (1<<0) /* fist block */
|
24 |
+
#define ZEND_BB_FOLLOW (1<<1) /* follows the next block */
|
25 |
+
#define ZEND_BB_TARGET (1<<2) /* jump taget */
|
26 |
+
#define ZEND_BB_EXIT (1<<3) /* without successors */
|
27 |
+
#define ZEND_BB_ENTRY (1<<4) /* stackless entry */
|
28 |
+
#define ZEND_BB_TRY (1<<5) /* start of try block */
|
29 |
+
#define ZEND_BB_CATCH (1<<6) /* start of catch block */
|
30 |
+
#define ZEND_BB_FINALLY (1<<7) /* start of finally block */
|
31 |
+
#define ZEND_BB_FINALLY_END (1<<8) /* end of finally block */
|
32 |
+
#define ZEND_BB_GEN_VAR (1<<9) /* start of live range */
|
33 |
+
#define ZEND_BB_KILL_VAR (1<<10) /* end of live range */
|
34 |
+
#define ZEND_BB_UNREACHABLE_FREE (1<<11) /* unreachable loop free */
|
35 |
+
#define ZEND_BB_RECV_ENTRY (1<<12) /* RECV entry */
|
36 |
+
|
37 |
+
#define ZEND_BB_LOOP_HEADER (1<<16)
|
38 |
+
#define ZEND_BB_IRREDUCIBLE_LOOP (1<<17)
|
39 |
+
|
40 |
+
#define ZEND_BB_REACHABLE (1<<31)
|
41 |
+
|
42 |
+
#define ZEND_BB_PROTECTED (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY|ZEND_BB_TRY|ZEND_BB_CATCH|ZEND_BB_FINALLY|ZEND_BB_FINALLY_END|ZEND_BB_GEN_VAR|ZEND_BB_KILL_VAR)
|
43 |
+
|
44 |
+
typedef struct _zend_basic_block {
|
45 |
+
int *successors; /* successor block indices */
|
46 |
+
uint32_t flags;
|
47 |
+
uint32_t start; /* first opcode number */
|
48 |
+
uint32_t len; /* number of opcodes */
|
49 |
+
int successors_count; /* number of successors */
|
50 |
+
int predecessors_count; /* number of predecessors */
|
51 |
+
int predecessor_offset; /* offset of 1-st predecessor */
|
52 |
+
int idom; /* immediate dominator block */
|
53 |
+
int loop_header; /* closest loop header, or -1 */
|
54 |
+
int level; /* steps away from the entry in the dom. tree */
|
55 |
+
int children; /* list of dominated blocks */
|
56 |
+
int next_child; /* next dominated block */
|
57 |
+
int successors_storage[2]; /* up to 2 successor blocks */
|
58 |
+
} zend_basic_block;
|
59 |
+
|
60 |
+
/*
|
61 |
+
+------------+---+---+---+---+---+
|
62 |
+
| |OP1|OP2|EXT| 0 | 1 |
|
63 |
+
+------------+---+---+---+---+---+
|
64 |
+
|JMP |ADR| | |OP1| - |
|
65 |
+
|JMPZ | |ADR| |OP2|FOL|
|
66 |
+
|JMPNZ | |ADR| |OP2|FOL|
|
67 |
+
|JMPZNZ | |ADR|ADR|OP2|EXT|
|
68 |
+
|JMPZ_EX | |ADR| |OP2|FOL|
|
69 |
+
|JMPNZ_EX | |ADR| |OP2|FOL|
|
70 |
+
|JMP_SET | |ADR| |OP2|FOL|
|
71 |
+
|COALESCE | |ADR| |OP2|FOL|
|
72 |
+
|ASSERT_CHK | |ADR| |OP2|FOL|
|
73 |
+
|NEW | |ADR| |OP2|FOL|
|
74 |
+
|DCL_ANON* |ADR| | |OP1|FOL|
|
75 |
+
|FE_RESET_* | |ADR| |OP2|FOL|
|
76 |
+
|FE_FETCH_* | | |ADR|EXT|FOL|
|
77 |
+
|CATCH | | |ADR|EXT|FOL|
|
78 |
+
|FAST_CALL |ADR| | |OP1|FOL|
|
79 |
+
|FAST_RET | | | | - | - |
|
80 |
+
|RETURN* | | | | - | - |
|
81 |
+
|EXIT | | | | - | - |
|
82 |
+
|THROW | | | | - | - |
|
83 |
+
|* | | | |FOL| - |
|
84 |
+
+------------+---+---+---+---+---+
|
85 |
+
*/
|
86 |
+
|
87 |
+
typedef struct _zend_cfg {
|
88 |
+
int blocks_count; /* number of basic blocks */
|
89 |
+
int edges_count; /* number of edges */
|
90 |
+
zend_basic_block *blocks; /* array of basic blocks */
|
91 |
+
int *predecessors;
|
92 |
+
uint32_t *map;
|
93 |
+
uint32_t flags;
|
94 |
+
} zend_cfg;
|
95 |
+
|
96 |
+
/* Build Flags */
|
97 |
+
#define ZEND_RT_CONSTANTS (1<<31)
|
98 |
+
#define ZEND_CFG_STACKLESS (1<<30)
|
99 |
+
#define ZEND_SSA_DEBUG_LIVENESS (1<<29)
|
100 |
+
#define ZEND_SSA_DEBUG_PHI_PLACEMENT (1<<28)
|
101 |
+
#define ZEND_SSA_RC_INFERENCE (1<<27)
|
102 |
+
#define ZEND_CFG_SPLIT_AT_LIVE_RANGES (1<<26)
|
103 |
+
#define ZEND_CFG_NO_ENTRY_PREDECESSORS (1<<25)
|
104 |
+
#define ZEND_CFG_RECV_ENTRY (1<<24)
|
105 |
+
#define ZEND_CALL_TREE (1<<23)
|
106 |
+
#define ZEND_SSA_USE_CV_RESULTS (1<<22)
|
107 |
+
|
108 |
+
#define CRT_CONSTANT_EX(op_array, opline, node, rt_constants) \
|
109 |
+
((rt_constants) ? \
|
110 |
+
RT_CONSTANT(opline, (node)) \
|
111 |
+
: \
|
112 |
+
CT_CONSTANT_EX(op_array, (node).constant) \
|
113 |
+
)
|
114 |
+
|
115 |
+
#define CRT_CONSTANT(node) \
|
116 |
+
CRT_CONSTANT_EX(op_array, opline, node, (build_flags & ZEND_RT_CONSTANTS))
|
117 |
+
|
118 |
+
#define RETURN_VALUE_USED(opline) \
|
119 |
+
((opline)->result_type != IS_UNUSED)
|
120 |
+
|
121 |
+
BEGIN_EXTERN_C()
|
122 |
+
|
123 |
+
int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg);
|
124 |
+
|
125 |
+
END_EXTERN_C()
|
126 |
+
|
127 |
+
#endif /* ZEND_CFG_H */
|
128 |
+
|
129 |
+
/*
|
130 |
+
* Local variables:
|
131 |
+
* tab-width: 4
|
132 |
+
* c-basic-offset: 4
|
133 |
+
* indent-tabs-mode: t
|
134 |
+
* End:
|
135 |
+
*/
|
pcov-1.0.11/pcov-1.0.11/cfg/703/zend_worklist.h
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Zend Engine |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| Copyright (c) 1998-2018 The PHP Group |
|
6 |
+
+----------------------------------------------------------------------+
|
7 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
8 |
+
| that is bundled with this package in the file LICENSE, and is |
|
9 |
+
| available through the world-wide-web at the following url: |
|
10 |
+
| http://www.php.net/license/3_01.txt |
|
11 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
12 |
+
| obtain it through the world-wide-web, please send a note to |
|
13 |
+
| [email protected] so we can mail you a copy immediately. |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
| Authors: Andy Wingo <[email protected]> |
|
16 |
+
+----------------------------------------------------------------------+
|
17 |
+
*/
|
18 |
+
|
19 |
+
#ifndef _ZEND_WORKLIST_H_
|
20 |
+
#define _ZEND_WORKLIST_H_
|
21 |
+
|
22 |
+
#include "zend_arena.h"
|
23 |
+
#include "zend_bitset.h"
|
24 |
+
|
25 |
+
typedef struct _zend_worklist_stack {
|
26 |
+
int *buf;
|
27 |
+
int len;
|
28 |
+
int capacity;
|
29 |
+
} zend_worklist_stack;
|
30 |
+
|
31 |
+
#define ZEND_WORKLIST_STACK_ALLOCA(s, _len, use_heap) do { \
|
32 |
+
(s)->buf = (int*)do_alloca(sizeof(int) * _len, use_heap); \
|
33 |
+
(s)->len = 0; \
|
34 |
+
(s)->capacity = _len; \
|
35 |
+
} while (0)
|
36 |
+
|
37 |
+
#define ZEND_WORKLIST_STACK_FREE_ALLOCA(s, use_heap) \
|
38 |
+
free_alloca((s)->buf, use_heap)
|
39 |
+
|
40 |
+
static inline int zend_worklist_stack_prepare(zend_arena **arena, zend_worklist_stack *stack, int len)
|
41 |
+
{
|
42 |
+
ZEND_ASSERT(len >= 0);
|
43 |
+
|
44 |
+
stack->buf = (int*)zend_arena_calloc(arena, sizeof(*stack->buf), len);
|
45 |
+
stack->len = 0;
|
46 |
+
stack->capacity = len;
|
47 |
+
|
48 |
+
return SUCCESS;
|
49 |
+
}
|
50 |
+
|
51 |
+
static inline void zend_worklist_stack_push(zend_worklist_stack *stack, int i)
|
52 |
+
{
|
53 |
+
ZEND_ASSERT(stack->len < stack->capacity);
|
54 |
+
stack->buf[stack->len++] = i;
|
55 |
+
}
|
56 |
+
|
57 |
+
static inline int zend_worklist_stack_peek(zend_worklist_stack *stack)
|
58 |
+
{
|
59 |
+
ZEND_ASSERT(stack->len);
|
60 |
+
return stack->buf[stack->len - 1];
|
61 |
+
}
|
62 |
+
|
63 |
+
static inline int zend_worklist_stack_pop(zend_worklist_stack *stack)
|
64 |
+
{
|
65 |
+
ZEND_ASSERT(stack->len);
|
66 |
+
return stack->buf[--stack->len];
|
67 |
+
}
|
68 |
+
|
69 |
+
typedef struct _zend_worklist {
|
70 |
+
zend_bitset visited;
|
71 |
+
zend_worklist_stack stack;
|
72 |
+
} zend_worklist;
|
73 |
+
|
74 |
+
#define ZEND_WORKLIST_ALLOCA(w, _len, use_heap) do { \
|
75 |
+
(w)->stack.buf = (int*)do_alloca(ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len) + sizeof(zend_ulong) * zend_bitset_len(_len), use_heap); \
|
76 |
+
(w)->stack.len = 0; \
|
77 |
+
(w)->stack.capacity = _len; \
|
78 |
+
(w)->visited = (zend_bitset)((char*)(w)->stack.buf + ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len)); \
|
79 |
+
memset((w)->visited, 0, sizeof(zend_ulong) * zend_bitset_len(_len)); \
|
80 |
+
} while (0)
|
81 |
+
|
82 |
+
#define ZEND_WORKLIST_FREE_ALLOCA(w, use_heap) \
|
83 |
+
free_alloca((w)->stack.buf, use_heap)
|
84 |
+
|
85 |
+
static inline int zend_worklist_prepare(zend_arena **arena, zend_worklist *worklist, int len)
|
86 |
+
{
|
87 |
+
ZEND_ASSERT(len >= 0);
|
88 |
+
worklist->visited = (zend_bitset)zend_arena_calloc(arena, sizeof(zend_ulong), zend_bitset_len(len));
|
89 |
+
return zend_worklist_stack_prepare(arena, &worklist->stack, len);
|
90 |
+
}
|
91 |
+
|
92 |
+
static inline int zend_worklist_len(zend_worklist *worklist)
|
93 |
+
{
|
94 |
+
return worklist->stack.len;
|
95 |
+
}
|
96 |
+
|
97 |
+
static inline int zend_worklist_push(zend_worklist *worklist, int i)
|
98 |
+
{
|
99 |
+
ZEND_ASSERT(i >= 0 && i < worklist->stack.capacity);
|
100 |
+
|
101 |
+
if (zend_bitset_in(worklist->visited, i)) {
|
102 |
+
return 0;
|
103 |
+
}
|
104 |
+
|
105 |
+
zend_bitset_incl(worklist->visited, i);
|
106 |
+
zend_worklist_stack_push(&worklist->stack, i);
|
107 |
+
return 1;
|
108 |
+
}
|
109 |
+
|
110 |
+
static inline int zend_worklist_peek(zend_worklist *worklist)
|
111 |
+
{
|
112 |
+
return zend_worklist_stack_peek(&worklist->stack);
|
113 |
+
}
|
114 |
+
|
115 |
+
static inline int zend_worklist_pop(zend_worklist *worklist)
|
116 |
+
{
|
117 |
+
/* Does not clear visited flag */
|
118 |
+
return zend_worklist_stack_pop(&worklist->stack);
|
119 |
+
}
|
120 |
+
|
121 |
+
#endif /* _ZEND_WORKLIST_H_ */
|
122 |
+
|
123 |
+
/*
|
124 |
+
* Local variables:
|
125 |
+
* tab-width: 4
|
126 |
+
* c-basic-offset: 4
|
127 |
+
* indent-tabs-mode: t
|
128 |
+
* End:
|
129 |
+
*/
|
pcov-1.0.11/pcov-1.0.11/cfg/704/zend_cfg.c
ADDED
@@ -0,0 +1,612 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Zend Engine, CFG - Control Flow Graph |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| Copyright (c) The PHP Group |
|
6 |
+
+----------------------------------------------------------------------+
|
7 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
8 |
+
| that is bundled with this package in the file LICENSE, and is |
|
9 |
+
| available through the world-wide-web at the following url: |
|
10 |
+
| http://www.php.net/license/3_01.txt |
|
11 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
12 |
+
| obtain it through the world-wide-web, please send a note to |
|
13 |
+
| [email protected] so we can mail you a copy immediately. |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
| Authors: Dmitry Stogov <[email protected]> |
|
16 |
+
+----------------------------------------------------------------------+
|
17 |
+
|
18 |
+
This source file has been adapted for pcov so that the CFG from O+ is standalone
|
19 |
+
*/
|
20 |
+
|
21 |
+
#include "php.h"
|
22 |
+
#include "zend_compile.h"
|
23 |
+
#include "zend_cfg.h"
|
24 |
+
#include "zend_worklist.h"
|
25 |
+
|
26 |
+
/* func flags */
|
27 |
+
#define ZEND_FUNC_INDIRECT_VAR_ACCESS (1<<0) /* accesses variables by name */
|
28 |
+
#define ZEND_FUNC_HAS_CALLS (1<<1)
|
29 |
+
#define ZEND_FUNC_VARARG (1<<2) /* uses func_get_args() */
|
30 |
+
#define ZEND_FUNC_NO_LOOPS (1<<3)
|
31 |
+
#define ZEND_FUNC_IRREDUCIBLE (1<<4)
|
32 |
+
#define ZEND_FUNC_FREE_LOOP_VAR (1<<5)
|
33 |
+
#define ZEND_FUNC_RECURSIVE (1<<7)
|
34 |
+
#define ZEND_FUNC_RECURSIVE_DIRECTLY (1<<8)
|
35 |
+
#define ZEND_FUNC_RECURSIVE_INDIRECTLY (1<<9)
|
36 |
+
#define ZEND_FUNC_HAS_EXTENDED_FCALL (1<<10)
|
37 |
+
#define ZEND_FUNC_HAS_EXTENDED_STMT (1<<11)
|
38 |
+
|
39 |
+
/* The following flags are valid only for return values of internal functions
|
40 |
+
* returned by zend_get_func_info()
|
41 |
+
*/
|
42 |
+
#define FUNC_MAY_WARN (1<<30)
|
43 |
+
|
44 |
+
typedef struct _zend_func_info zend_func_info;
|
45 |
+
typedef struct _zend_call_info zend_call_info;
|
46 |
+
|
47 |
+
#define ZEND_FUNC_INFO(op_array) \
|
48 |
+
((zend_func_info*)((op_array)->reserved[zend_func_info_rid]))
|
49 |
+
|
50 |
+
#define ZEND_SET_FUNC_INFO(op_array, info) do { \
|
51 |
+
zend_func_info** pinfo = (zend_func_info**)&(op_array)->reserved[zend_func_info_rid]; \
|
52 |
+
*pinfo = info; \
|
53 |
+
} while (0)
|
54 |
+
|
55 |
+
static uint32_t zend_cfg_classify_function(zend_string *name, uint32_t num_args) {
|
56 |
+
if (zend_string_equals_literal(name, "extract")) {
|
57 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
58 |
+
} else if (zend_string_equals_literal(name, "compact")) {
|
59 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
60 |
+
} else if (zend_string_equals_literal(name, "parse_str") && num_args <= 1) {
|
61 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
62 |
+
} else if (zend_string_equals_literal(name, "mb_parse_str") && num_args <= 1) {
|
63 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
64 |
+
} else if (zend_string_equals_literal(name, "get_defined_vars")) {
|
65 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
66 |
+
} else if (zend_string_equals_literal(name, "assert")) {
|
67 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
68 |
+
} else if (zend_string_equals_literal(name, "db2_execute")) {
|
69 |
+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
70 |
+
} else if (zend_string_equals_literal(name, "func_num_args")) {
|
71 |
+
return ZEND_FUNC_VARARG;
|
72 |
+
} else if (zend_string_equals_literal(name, "func_get_arg")) {
|
73 |
+
return ZEND_FUNC_VARARG;
|
74 |
+
} else if (zend_string_equals_literal(name, "func_get_args")) {
|
75 |
+
return ZEND_FUNC_VARARG;
|
76 |
+
} else {
|
77 |
+
return 0;
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_block *b) /* {{{ */
|
82 |
+
{
|
83 |
+
zend_basic_block *blocks = cfg->blocks;
|
84 |
+
|
85 |
+
while (1) {
|
86 |
+
int i;
|
87 |
+
|
88 |
+
b->flags |= ZEND_BB_REACHABLE;
|
89 |
+
if (b->successors_count == 0) {
|
90 |
+
b->flags |= ZEND_BB_EXIT;
|
91 |
+
return;
|
92 |
+
}
|
93 |
+
|
94 |
+
for (i = 0; i < b->successors_count; i++) {
|
95 |
+
zend_basic_block *succ = blocks + b->successors[i];
|
96 |
+
|
97 |
+
if (b->len != 0) {
|
98 |
+
zend_uchar opcode = opcodes[b->start + b->len - 1].opcode;
|
99 |
+
if (b->successors_count == 1) {
|
100 |
+
if (opcode == ZEND_JMP) {
|
101 |
+
succ->flags |= ZEND_BB_TARGET;
|
102 |
+
} else {
|
103 |
+
succ->flags |= ZEND_BB_FOLLOW;
|
104 |
+
|
105 |
+
if ((cfg->flags & ZEND_CFG_STACKLESS)) {
|
106 |
+
if (opcode == ZEND_INCLUDE_OR_EVAL ||
|
107 |
+
opcode == ZEND_GENERATOR_CREATE ||
|
108 |
+
opcode == ZEND_YIELD ||
|
109 |
+
opcode == ZEND_YIELD_FROM ||
|
110 |
+
opcode == ZEND_DO_FCALL ||
|
111 |
+
opcode == ZEND_DO_UCALL ||
|
112 |
+
opcode == ZEND_DO_FCALL_BY_NAME) {
|
113 |
+
succ->flags |= ZEND_BB_ENTRY;
|
114 |
+
}
|
115 |
+
}
|
116 |
+
if ((cfg->flags & ZEND_CFG_RECV_ENTRY)) {
|
117 |
+
if (opcode == ZEND_RECV ||
|
118 |
+
opcode == ZEND_RECV_INIT) {
|
119 |
+
succ->flags |= ZEND_BB_RECV_ENTRY;
|
120 |
+
}
|
121 |
+
}
|
122 |
+
}
|
123 |
+
} else if (b->successors_count == 2) {
|
124 |
+
if (i == 0 || opcode == ZEND_JMPZNZ) {
|
125 |
+
succ->flags |= ZEND_BB_TARGET;
|
126 |
+
} else {
|
127 |
+
succ->flags |= ZEND_BB_FOLLOW;
|
128 |
+
}
|
129 |
+
} else {
|
130 |
+
ZEND_ASSERT(opcode == ZEND_SWITCH_LONG || opcode == ZEND_SWITCH_STRING);
|
131 |
+
if (i == b->successors_count - 1) {
|
132 |
+
succ->flags |= ZEND_BB_FOLLOW | ZEND_BB_TARGET;
|
133 |
+
} else {
|
134 |
+
succ->flags |= ZEND_BB_TARGET;
|
135 |
+
}
|
136 |
+
}
|
137 |
+
} else {
|
138 |
+
succ->flags |= ZEND_BB_FOLLOW;
|
139 |
+
}
|
140 |
+
|
141 |
+
if (i == b->successors_count - 1) {
|
142 |
+
/* Tail call optimization */
|
143 |
+
if (succ->flags & ZEND_BB_REACHABLE) {
|
144 |
+
return;
|
145 |
+
}
|
146 |
+
|
147 |
+
b = succ;
|
148 |
+
break;
|
149 |
+
} else {
|
150 |
+
/* Recusively check reachability */
|
151 |
+
if (!(succ->flags & ZEND_BB_REACHABLE)) {
|
152 |
+
zend_mark_reachable(opcodes, cfg, succ);
|
153 |
+
}
|
154 |
+
}
|
155 |
+
}
|
156 |
+
}
|
157 |
+
}
|
158 |
+
/* }}} */
|
159 |
+
|
160 |
+
static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg *cfg, int start) /* {{{ */
|
161 |
+
{
|
162 |
+
zend_basic_block *blocks = cfg->blocks;
|
163 |
+
|
164 |
+
blocks[start].flags = ZEND_BB_START;
|
165 |
+
zend_mark_reachable(op_array->opcodes, cfg, blocks + start);
|
166 |
+
|
167 |
+
if (op_array->last_try_catch) {
|
168 |
+
zend_basic_block *b;
|
169 |
+
int j, changed;
|
170 |
+
uint32_t *block_map = cfg->map;
|
171 |
+
|
172 |
+
do {
|
173 |
+
changed = 0;
|
174 |
+
|
175 |
+
/* Add exception paths */
|
176 |
+
for (j = 0; j < op_array->last_try_catch; j++) {
|
177 |
+
|
178 |
+
/* check for jumps into the middle of try block */
|
179 |
+
b = blocks + block_map[op_array->try_catch_array[j].try_op];
|
180 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
181 |
+
zend_basic_block *end;
|
182 |
+
|
183 |
+
if (op_array->try_catch_array[j].catch_op) {
|
184 |
+
end = blocks + block_map[op_array->try_catch_array[j].catch_op];
|
185 |
+
while (b != end) {
|
186 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
187 |
+
op_array->try_catch_array[j].try_op = b->start;
|
188 |
+
break;
|
189 |
+
}
|
190 |
+
b++;
|
191 |
+
}
|
192 |
+
}
|
193 |
+
b = blocks + block_map[op_array->try_catch_array[j].try_op];
|
194 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
195 |
+
if (op_array->try_catch_array[j].finally_op) {
|
196 |
+
end = blocks + block_map[op_array->try_catch_array[j].finally_op];
|
197 |
+
while (b != end) {
|
198 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
199 |
+
op_array->try_catch_array[j].try_op = op_array->try_catch_array[j].catch_op;
|
200 |
+
changed = 1;
|
201 |
+
zend_mark_reachable(op_array->opcodes, cfg, blocks + block_map[op_array->try_catch_array[j].try_op]);
|
202 |
+
break;
|
203 |
+
}
|
204 |
+
b++;
|
205 |
+
}
|
206 |
+
}
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
b = blocks + block_map[op_array->try_catch_array[j].try_op];
|
211 |
+
if (b->flags & ZEND_BB_REACHABLE) {
|
212 |
+
b->flags |= ZEND_BB_TRY;
|
213 |
+
if (op_array->try_catch_array[j].catch_op) {
|
214 |
+
b = blocks + block_map[op_array->try_catch_array[j].catch_op];
|
215 |
+
b->flags |= ZEND_BB_CATCH;
|
216 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
217 |
+
changed = 1;
|
218 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
219 |
+
}
|
220 |
+
}
|
221 |
+
if (op_array->try_catch_array[j].finally_op) {
|
222 |
+
b = blocks + block_map[op_array->try_catch_array[j].finally_op];
|
223 |
+
b->flags |= ZEND_BB_FINALLY;
|
224 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
225 |
+
changed = 1;
|
226 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
227 |
+
}
|
228 |
+
}
|
229 |
+
if (op_array->try_catch_array[j].finally_end) {
|
230 |
+
b = blocks + block_map[op_array->try_catch_array[j].finally_end];
|
231 |
+
b->flags |= ZEND_BB_FINALLY_END;
|
232 |
+
if (!(b->flags & ZEND_BB_REACHABLE)) {
|
233 |
+
changed = 1;
|
234 |
+
zend_mark_reachable(op_array->opcodes, cfg, b);
|
235 |
+
}
|
236 |
+
}
|
237 |
+
} else {
|
238 |
+
if (op_array->try_catch_array[j].catch_op) {
|
239 |
+
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].catch_op]].flags & ZEND_BB_REACHABLE));
|
240 |
+
}
|
241 |
+
if (op_array->try_catch_array[j].finally_op) {
|
242 |
+
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_op]].flags & ZEND_BB_REACHABLE));
|
243 |
+
}
|
244 |
+
if (op_array->try_catch_array[j].finally_end) {
|
245 |
+
ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_end]].flags & ZEND_BB_REACHABLE));
|
246 |
+
}
|
247 |
+
}
|
248 |
+
}
|
249 |
+
} while (changed);
|
250 |
+
}
|
251 |
+
}
|
252 |
+
/* }}} */
|
253 |
+
|
254 |
+
void zend_cfg_remark_reachable_blocks(const zend_op_array *op_array, zend_cfg *cfg) /* {{{ */
|
255 |
+
{
|
256 |
+
zend_basic_block *blocks = cfg->blocks;
|
257 |
+
int i;
|
258 |
+
int start = 0;
|
259 |
+
|
260 |
+
for (i = 0; i < cfg->blocks_count; i++) {
|
261 |
+
if (blocks[i].flags & ZEND_BB_REACHABLE) {
|
262 |
+
start = i;
|
263 |
+
i++;
|
264 |
+
break;
|
265 |
+
}
|
266 |
+
}
|
267 |
+
|
268 |
+
/* clear all flags */
|
269 |
+
for (i = 0; i < cfg->blocks_count; i++) {
|
270 |
+
blocks[i].flags = 0;
|
271 |
+
}
|
272 |
+
|
273 |
+
zend_mark_reachable_blocks(op_array, cfg, start);
|
274 |
+
}
|
275 |
+
/* }}} */
|
276 |
+
|
277 |
+
static void initialize_block(zend_basic_block *block) {
|
278 |
+
block->flags = 0;
|
279 |
+
block->successors = block->successors_storage;
|
280 |
+
block->successors_count = 0;
|
281 |
+
block->predecessors_count = 0;
|
282 |
+
block->predecessor_offset = -1;
|
283 |
+
block->idom = -1;
|
284 |
+
block->loop_header = -1;
|
285 |
+
block->level = -1;
|
286 |
+
block->children = -1;
|
287 |
+
block->next_child = -1;
|
288 |
+
}
|
289 |
+
|
290 |
+
#define BB_START(i) do { \
|
291 |
+
if (!block_map[i]) { blocks_count++;} \
|
292 |
+
block_map[i]++; \
|
293 |
+
} while (0)
|
294 |
+
|
295 |
+
int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg) /* {{{ */
|
296 |
+
{
|
297 |
+
uint32_t flags = 0;
|
298 |
+
uint32_t i;
|
299 |
+
int j;
|
300 |
+
uint32_t *block_map;
|
301 |
+
zend_function *fn;
|
302 |
+
int blocks_count = 0;
|
303 |
+
zend_basic_block *blocks;
|
304 |
+
zval *zv;
|
305 |
+
zend_bool extra_entry_block = 0;
|
306 |
+
|
307 |
+
cfg->flags = build_flags & (ZEND_CFG_STACKLESS|ZEND_CFG_RECV_ENTRY);
|
308 |
+
|
309 |
+
cfg->map = block_map = zend_arena_calloc(arena, op_array->last, sizeof(uint32_t));
|
310 |
+
|
311 |
+
/* Build CFG, Step 1: Find basic blocks starts, calculate number of blocks */
|
312 |
+
BB_START(0);
|
313 |
+
for (i = 0; i < op_array->last; i++) {
|
314 |
+
zend_op *opline = op_array->opcodes + i;
|
315 |
+
switch (opline->opcode) {
|
316 |
+
case ZEND_RECV:
|
317 |
+
case ZEND_RECV_INIT:
|
318 |
+
if (build_flags & ZEND_CFG_RECV_ENTRY) {
|
319 |
+
BB_START(i + 1);
|
320 |
+
}
|
321 |
+
break;
|
322 |
+
case ZEND_RETURN:
|
323 |
+
case ZEND_RETURN_BY_REF:
|
324 |
+
case ZEND_GENERATOR_RETURN:
|
325 |
+
case ZEND_EXIT:
|
326 |
+
case ZEND_THROW:
|
327 |
+
if (i + 1 < op_array->last) {
|
328 |
+
BB_START(i + 1);
|
329 |
+
}
|
330 |
+
break;
|
331 |
+
case ZEND_INCLUDE_OR_EVAL:
|
332 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
333 |
+
case ZEND_GENERATOR_CREATE:
|
334 |
+
case ZEND_YIELD:
|
335 |
+
case ZEND_YIELD_FROM:
|
336 |
+
if (build_flags & ZEND_CFG_STACKLESS) {
|
337 |
+
BB_START(i + 1);
|
338 |
+
}
|
339 |
+
break;
|
340 |
+
case ZEND_DO_FCALL:
|
341 |
+
case ZEND_DO_UCALL:
|
342 |
+
case ZEND_DO_FCALL_BY_NAME:
|
343 |
+
flags |= ZEND_FUNC_HAS_CALLS;
|
344 |
+
if (build_flags & ZEND_CFG_STACKLESS) {
|
345 |
+
BB_START(i + 1);
|
346 |
+
}
|
347 |
+
break;
|
348 |
+
case ZEND_DO_ICALL:
|
349 |
+
flags |= ZEND_FUNC_HAS_CALLS;
|
350 |
+
break;
|
351 |
+
case ZEND_INIT_FCALL:
|
352 |
+
case ZEND_INIT_NS_FCALL_BY_NAME:
|
353 |
+
zv = CRT_CONSTANT(opline->op2);
|
354 |
+
if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
|
355 |
+
/* The third literal is the lowercased unqualified name */
|
356 |
+
zv += 2;
|
357 |
+
}
|
358 |
+
if ((fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv))) != NULL) {
|
359 |
+
if (fn->type == ZEND_INTERNAL_FUNCTION) {
|
360 |
+
flags |= zend_cfg_classify_function(
|
361 |
+
Z_STR_P(zv), opline->extended_value);
|
362 |
+
}
|
363 |
+
}
|
364 |
+
break;
|
365 |
+
case ZEND_FAST_CALL:
|
366 |
+
BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
|
367 |
+
BB_START(i + 1);
|
368 |
+
break;
|
369 |
+
case ZEND_FAST_RET:
|
370 |
+
if (i + 1 < op_array->last) {
|
371 |
+
BB_START(i + 1);
|
372 |
+
}
|
373 |
+
break;
|
374 |
+
case ZEND_JMP:
|
375 |
+
BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes);
|
376 |
+
if (i + 1 < op_array->last) {
|
377 |
+
BB_START(i + 1);
|
378 |
+
}
|
379 |
+
break;
|
380 |
+
case ZEND_JMPZNZ:
|
381 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
382 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
383 |
+
if (i + 1 < op_array->last) {
|
384 |
+
BB_START(i + 1);
|
385 |
+
}
|
386 |
+
break;
|
387 |
+
case ZEND_JMPZ:
|
388 |
+
case ZEND_JMPNZ:
|
389 |
+
case ZEND_JMPZ_EX:
|
390 |
+
case ZEND_JMPNZ_EX:
|
391 |
+
case ZEND_JMP_SET:
|
392 |
+
case ZEND_COALESCE:
|
393 |
+
case ZEND_ASSERT_CHECK:
|
394 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
395 |
+
BB_START(i + 1);
|
396 |
+
break;
|
397 |
+
case ZEND_CATCH:
|
398 |
+
if (!(opline->extended_value & ZEND_LAST_CATCH)) {
|
399 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
400 |
+
}
|
401 |
+
BB_START(i + 1);
|
402 |
+
break;
|
403 |
+
case ZEND_FE_FETCH_R:
|
404 |
+
case ZEND_FE_FETCH_RW:
|
405 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
406 |
+
BB_START(i + 1);
|
407 |
+
break;
|
408 |
+
case ZEND_FE_RESET_R:
|
409 |
+
case ZEND_FE_RESET_RW:
|
410 |
+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
|
411 |
+
BB_START(i + 1);
|
412 |
+
break;
|
413 |
+
case ZEND_SWITCH_LONG:
|
414 |
+
case ZEND_SWITCH_STRING:
|
415 |
+
{
|
416 |
+
HashTable *jumptable = Z_ARRVAL_P(CRT_CONSTANT(opline->op2));
|
417 |
+
zval *zv;
|
418 |
+
ZEND_HASH_FOREACH_VAL(jumptable, zv) {
|
419 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv)));
|
420 |
+
} ZEND_HASH_FOREACH_END();
|
421 |
+
BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
|
422 |
+
BB_START(i + 1);
|
423 |
+
break;
|
424 |
+
}
|
425 |
+
case ZEND_FETCH_R:
|
426 |
+
case ZEND_FETCH_W:
|
427 |
+
case ZEND_FETCH_RW:
|
428 |
+
case ZEND_FETCH_FUNC_ARG:
|
429 |
+
case ZEND_FETCH_IS:
|
430 |
+
case ZEND_FETCH_UNSET:
|
431 |
+
case ZEND_UNSET_VAR:
|
432 |
+
case ZEND_ISSET_ISEMPTY_VAR:
|
433 |
+
if (opline->extended_value & ZEND_FETCH_LOCAL) {
|
434 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
435 |
+
} else if ((opline->extended_value & (ZEND_FETCH_GLOBAL | ZEND_FETCH_GLOBAL_LOCK)) &&
|
436 |
+
!op_array->function_name) {
|
437 |
+
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
|
438 |
+
}
|
439 |
+
break;
|
440 |
+
case ZEND_FUNC_GET_ARGS:
|
441 |
+
flags |= ZEND_FUNC_VARARG;
|
442 |
+
break;
|
443 |
+
case ZEND_EXT_NOP:
|
444 |
+
case ZEND_EXT_STMT:
|
445 |
+
flags |= ZEND_FUNC_HAS_EXTENDED_STMT;
|
446 |
+
break;
|
447 |
+
case ZEND_EXT_FCALL_BEGIN:
|
448 |
+
case ZEND_EXT_FCALL_END:
|
449 |
+
flags |= ZEND_FUNC_HAS_EXTENDED_FCALL;
|
450 |
+
break;
|
451 |
+
case ZEND_FREE:
|
452 |
+
if (opline->extended_value == ZEND_FREE_SWITCH) {
|
453 |
+
flags |= ZEND_FUNC_FREE_LOOP_VAR;
|
454 |
+
}
|
455 |
+
break;
|
456 |
+
case ZEND_FE_FREE:
|
457 |
+
flags |= ZEND_FUNC_FREE_LOOP_VAR;
|
458 |
+
break;
|
459 |
+
}
|
460 |
+
}
|
461 |
+
|
462 |
+
/* If the entry block has predecessors, we may need to split it */
|
463 |
+
if ((build_flags & ZEND_CFG_NO_ENTRY_PREDECESSORS)
|
464 |
+
&& op_array->last > 0 && block_map[0] > 1) {
|
465 |
+
extra_entry_block = 1;
|
466 |
+
}
|
467 |
+
|
468 |
+
if (op_array->last_try_catch) {
|
469 |
+
for (j = 0; j < op_array->last_try_catch; j++) {
|
470 |
+
BB_START(op_array->try_catch_array[j].try_op);
|
471 |
+
if (op_array->try_catch_array[j].catch_op) {
|
472 |
+
BB_START(op_array->try_catch_array[j].catch_op);
|
473 |
+
}
|
474 |
+
if (op_array->try_catch_array[j].finally_op) {
|
475 |
+
BB_START(op_array->try_catch_array[j].finally_op);
|
476 |
+
}
|
477 |
+
if (op_array->try_catch_array[j].finally_end) {
|
478 |
+
BB_START(op_array->try_catch_array[j].finally_end);
|
479 |
+
}
|
480 |
+
}
|
481 |
+
}
|
482 |
+
|
483 |
+
blocks_count += extra_entry_block;
|
484 |
+
cfg->blocks_count = blocks_count;
|
485 |
+
|
486 |
+
/* Build CFG, Step 2: Build Array of Basic Blocks */
|
487 |
+
cfg->blocks = blocks = zend_arena_calloc(arena, sizeof(zend_basic_block), blocks_count);
|
488 |
+
|
489 |
+
blocks_count = -1;
|
490 |
+
|
491 |
+
if (extra_entry_block) {
|
492 |
+
initialize_block(&blocks[0]);
|
493 |
+
blocks[0].start = 0;
|
494 |
+
blocks[0].len = 0;
|
495 |
+
blocks_count++;
|
496 |
+
}
|
497 |
+
|
498 |
+
for (i = 0; i < op_array->last; i++) {
|
499 |
+
if (block_map[i]) {
|
500 |
+
if (blocks_count >= 0) {
|
501 |
+
blocks[blocks_count].len = i - blocks[blocks_count].start;
|
502 |
+
}
|
503 |
+
blocks_count++;
|
504 |
+
initialize_block(&blocks[blocks_count]);
|
505 |
+
blocks[blocks_count].start = i;
|
506 |
+
}
|
507 |
+
block_map[i] = blocks_count;
|
508 |
+
}
|
509 |
+
|
510 |
+
blocks[blocks_count].len = i - blocks[blocks_count].start;
|
511 |
+
blocks_count++;
|
512 |
+
|
513 |
+
/* Build CFG, Step 3: Calculate successors */
|
514 |
+
for (j = 0; j < blocks_count; j++) {
|
515 |
+
zend_basic_block *block = &blocks[j];
|
516 |
+
zend_op *opline;
|
517 |
+
if (block->len == 0) {
|
518 |
+
block->successors_count = 1;
|
519 |
+
block->successors[0] = j + 1;
|
520 |
+
continue;
|
521 |
+
}
|
522 |
+
|
523 |
+
opline = op_array->opcodes + block->start + block->len - 1;
|
524 |
+
switch (opline->opcode) {
|
525 |
+
case ZEND_FAST_RET:
|
526 |
+
case ZEND_RETURN:
|
527 |
+
case ZEND_RETURN_BY_REF:
|
528 |
+
case ZEND_GENERATOR_RETURN:
|
529 |
+
case ZEND_EXIT:
|
530 |
+
case ZEND_THROW:
|
531 |
+
break;
|
532 |
+
case ZEND_JMP:
|
533 |
+
block->successors_count = 1;
|
534 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes];
|
535 |
+
break;
|
536 |
+
case ZEND_JMPZNZ:
|
537 |
+
block->successors_count = 2;
|
538 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
|
539 |
+
block->successors[1] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
|
540 |
+
break;
|
541 |
+
case ZEND_JMPZ:
|
542 |
+
case ZEND_JMPNZ:
|
543 |
+
case ZEND_JMPZ_EX:
|
544 |
+
case ZEND_JMPNZ_EX:
|
545 |
+
case ZEND_JMP_SET:
|
546 |
+
case ZEND_COALESCE:
|
547 |
+
case ZEND_ASSERT_CHECK:
|
548 |
+
block->successors_count = 2;
|
549 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
|
550 |
+
block->successors[1] = j + 1;
|
551 |
+
break;
|
552 |
+
case ZEND_CATCH:
|
553 |
+
if (!(opline->extended_value & ZEND_LAST_CATCH)) {
|
554 |
+
block->successors_count = 2;
|
555 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
|
556 |
+
block->successors[1] = j + 1;
|
557 |
+
} else {
|
558 |
+
block->successors_count = 1;
|
559 |
+
block->successors[0] = j + 1;
|
560 |
+
}
|
561 |
+
break;
|
562 |
+
case ZEND_FE_FETCH_R:
|
563 |
+
case ZEND_FE_FETCH_RW:
|
564 |
+
block->successors_count = 2;
|
565 |
+
block->successors[0] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
|
566 |
+
block->successors[1] = j + 1;
|
567 |
+
break;
|
568 |
+
case ZEND_FE_RESET_R:
|
569 |
+
case ZEND_FE_RESET_RW:
|
570 |
+
block->successors_count = 2;
|
571 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
|
572 |
+
block->successors[1] = j + 1;
|
573 |
+
break;
|
574 |
+
case ZEND_FAST_CALL:
|
575 |
+
block->successors_count = 2;
|
576 |
+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes];
|
577 |
+
block->successors[1] = j + 1;
|
578 |
+
break;
|
579 |
+
case ZEND_SWITCH_LONG:
|
580 |
+
case ZEND_SWITCH_STRING:
|
581 |
+
{
|
582 |
+
HashTable *jumptable = Z_ARRVAL_P(CRT_CONSTANT(opline->op2));
|
583 |
+
zval *zv;
|
584 |
+
uint32_t s = 0;
|
585 |
+
|
586 |
+
block->successors_count = 2 + zend_hash_num_elements(jumptable);
|
587 |
+
block->successors = zend_arena_calloc(arena, block->successors_count, sizeof(int));
|
588 |
+
|
589 |
+
ZEND_HASH_FOREACH_VAL(jumptable, zv) {
|
590 |
+
block->successors[s++] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv))];
|
591 |
+
} ZEND_HASH_FOREACH_END();
|
592 |
+
|
593 |
+
block->successors[s++] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
|
594 |
+
block->successors[s++] = j + 1;
|
595 |
+
break;
|
596 |
+
}
|
597 |
+
default:
|
598 |
+
block->successors_count = 1;
|
599 |
+
block->successors[0] = j + 1;
|
600 |
+
break;
|
601 |
+
}
|
602 |
+
}
|
603 |
+
|
604 |
+
/* Build CFG, Step 4, Mark Reachable Basic Blocks */
|
605 |
+
cfg->flags |= flags;
|
606 |
+
zend_mark_reachable_blocks(op_array, cfg, 0);
|
607 |
+
|
608 |
+
return SUCCESS;
|
609 |
+
}
|
610 |
+
/* }}} */
|
611 |
+
|
612 |
+
/* }}} */
|
pcov-1.0.11/pcov-1.0.11/cfg/704/zend_cfg.h
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Zend Engine, CFG - Control Flow Graph |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| Copyright (c) The PHP Group |
|
6 |
+
+----------------------------------------------------------------------+
|
7 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
8 |
+
| that is bundled with this package in the file LICENSE, and is |
|
9 |
+
| available through the world-wide-web at the following url: |
|
10 |
+
| http://www.php.net/license/3_01.txt |
|
11 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
12 |
+
| obtain it through the world-wide-web, please send a note to |
|
13 |
+
| [email protected] so we can mail you a copy immediately. |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
| Authors: Dmitry Stogov <[email protected]> |
|
16 |
+
+----------------------------------------------------------------------+
|
17 |
+
*/
|
18 |
+
|
19 |
+
#ifndef ZEND_CFG_H
|
20 |
+
#define ZEND_CFG_H
|
21 |
+
|
22 |
+
/* zend_basic_bloc.flags */
|
23 |
+
#define ZEND_BB_START (1<<0) /* fist block */
|
24 |
+
#define ZEND_BB_FOLLOW (1<<1) /* follows the next block */
|
25 |
+
#define ZEND_BB_TARGET (1<<2) /* jump taget */
|
26 |
+
#define ZEND_BB_EXIT (1<<3) /* without successors */
|
27 |
+
#define ZEND_BB_ENTRY (1<<4) /* stackless entry */
|
28 |
+
#define ZEND_BB_TRY (1<<5) /* start of try block */
|
29 |
+
#define ZEND_BB_CATCH (1<<6) /* start of catch block */
|
30 |
+
#define ZEND_BB_FINALLY (1<<7) /* start of finally block */
|
31 |
+
#define ZEND_BB_FINALLY_END (1<<8) /* end of finally block */
|
32 |
+
#define ZEND_BB_UNREACHABLE_FREE (1<<11) /* unreachable loop free */
|
33 |
+
#define ZEND_BB_RECV_ENTRY (1<<12) /* RECV entry */
|
34 |
+
|
35 |
+
#define ZEND_BB_LOOP_HEADER (1<<16)
|
36 |
+
#define ZEND_BB_IRREDUCIBLE_LOOP (1<<17)
|
37 |
+
|
38 |
+
#define ZEND_BB_REACHABLE (1U<<31)
|
39 |
+
|
40 |
+
#define ZEND_BB_PROTECTED (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY|ZEND_BB_TRY|ZEND_BB_CATCH|ZEND_BB_FINALLY|ZEND_BB_FINALLY_END|ZEND_BB_UNREACHABLE_FREE)
|
41 |
+
|
42 |
+
typedef struct _zend_basic_block {
|
43 |
+
int *successors; /* successor block indices */
|
44 |
+
uint32_t flags;
|
45 |
+
uint32_t start; /* first opcode number */
|
46 |
+
uint32_t len; /* number of opcodes */
|
47 |
+
int successors_count; /* number of successors */
|
48 |
+
int predecessors_count; /* number of predecessors */
|
49 |
+
int predecessor_offset; /* offset of 1-st predecessor */
|
50 |
+
int idom; /* immediate dominator block */
|
51 |
+
int loop_header; /* closest loop header, or -1 */
|
52 |
+
int level; /* steps away from the entry in the dom. tree */
|
53 |
+
int children; /* list of dominated blocks */
|
54 |
+
int next_child; /* next dominated block */
|
55 |
+
int successors_storage[2]; /* up to 2 successor blocks */
|
56 |
+
} zend_basic_block;
|
57 |
+
|
58 |
+
/*
|
59 |
+
+------------+---+---+---+---+---+
|
60 |
+
| |OP1|OP2|EXT| 0 | 1 |
|
61 |
+
+------------+---+---+---+---+---+
|
62 |
+
|JMP |ADR| | |OP1| - |
|
63 |
+
|JMPZ | |ADR| |OP2|FOL|
|
64 |
+
|JMPNZ | |ADR| |OP2|FOL|
|
65 |
+
|JMPZNZ | |ADR|ADR|OP2|EXT|
|
66 |
+
|JMPZ_EX | |ADR| |OP2|FOL|
|
67 |
+
|JMPNZ_EX | |ADR| |OP2|FOL|
|
68 |
+
|JMP_SET | |ADR| |OP2|FOL|
|
69 |
+
|COALESCE | |ADR| |OP2|FOL|
|
70 |
+
|ASSERT_CHK | |ADR| |OP2|FOL|
|
71 |
+
|NEW | |ADR| |OP2|FOL|
|
72 |
+
|DCL_ANON* |ADR| | |OP1|FOL|
|
73 |
+
|FE_RESET_* | |ADR| |OP2|FOL|
|
74 |
+
|FE_FETCH_* | | |ADR|EXT|FOL|
|
75 |
+
|CATCH | | |ADR|EXT|FOL|
|
76 |
+
|FAST_CALL |ADR| | |OP1|FOL|
|
77 |
+
|FAST_RET | | | | - | - |
|
78 |
+
|RETURN* | | | | - | - |
|
79 |
+
|EXIT | | | | - | - |
|
80 |
+
|THROW | | | | - | - |
|
81 |
+
|* | | | |FOL| - |
|
82 |
+
+------------+---+---+---+---+---+
|
83 |
+
*/
|
84 |
+
|
85 |
+
typedef struct _zend_cfg {
|
86 |
+
int blocks_count; /* number of basic blocks */
|
87 |
+
int edges_count; /* number of edges */
|
88 |
+
zend_basic_block *blocks; /* array of basic blocks */
|
89 |
+
int *predecessors;
|
90 |
+
uint32_t *map;
|
91 |
+
uint32_t flags;
|
92 |
+
} zend_cfg;
|
93 |
+
|
94 |
+
/* Build Flags */
|
95 |
+
#define ZEND_RT_CONSTANTS (1U<<31)
|
96 |
+
#define ZEND_CFG_STACKLESS (1<<30)
|
97 |
+
#define ZEND_SSA_DEBUG_LIVENESS (1<<29)
|
98 |
+
#define ZEND_SSA_DEBUG_PHI_PLACEMENT (1<<28)
|
99 |
+
#define ZEND_SSA_RC_INFERENCE (1<<27)
|
100 |
+
#define ZEND_CFG_NO_ENTRY_PREDECESSORS (1<<25)
|
101 |
+
#define ZEND_CFG_RECV_ENTRY (1<<24)
|
102 |
+
#define ZEND_CALL_TREE (1<<23)
|
103 |
+
#define ZEND_SSA_USE_CV_RESULTS (1<<22)
|
104 |
+
|
105 |
+
#define CRT_CONSTANT_EX(op_array, opline, node, rt_constants) \
|
106 |
+
((rt_constants) ? \
|
107 |
+
RT_CONSTANT(opline, (node)) \
|
108 |
+
: \
|
109 |
+
CT_CONSTANT_EX(op_array, (node).constant) \
|
110 |
+
)
|
111 |
+
|
112 |
+
#define CRT_CONSTANT(node) \
|
113 |
+
CRT_CONSTANT_EX(op_array, opline, node, (build_flags & ZEND_RT_CONSTANTS))
|
114 |
+
|
115 |
+
#define RETURN_VALUE_USED(opline) \
|
116 |
+
((opline)->result_type != IS_UNUSED)
|
117 |
+
|
118 |
+
BEGIN_EXTERN_C()
|
119 |
+
|
120 |
+
int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg);
|
121 |
+
void zend_cfg_remark_reachable_blocks(const zend_op_array *op_array, zend_cfg *cfg);
|
122 |
+
int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg);
|
123 |
+
int zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cfg);
|
124 |
+
int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg);
|
125 |
+
|
126 |
+
END_EXTERN_C()
|
127 |
+
|
128 |
+
#endif /* ZEND_CFG_H */
|
pcov-1.0.11/pcov-1.0.11/cfg/704/zend_worklist.h
ADDED
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Zend Engine |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| Copyright (c) The PHP Group |
|
6 |
+
+----------------------------------------------------------------------+
|
7 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
8 |
+
| that is bundled with this package in the file LICENSE, and is |
|
9 |
+
| available through the world-wide-web at the following url: |
|
10 |
+
| http://www.php.net/license/3_01.txt |
|
11 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
12 |
+
| obtain it through the world-wide-web, please send a note to |
|
13 |
+
| [email protected] so we can mail you a copy immediately. |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
| Authors: Andy Wingo <[email protected]> |
|
16 |
+
+----------------------------------------------------------------------+
|
17 |
+
*/
|
18 |
+
|
19 |
+
#ifndef _ZEND_WORKLIST_H_
|
20 |
+
#define _ZEND_WORKLIST_H_
|
21 |
+
|
22 |
+
#include "zend_arena.h"
|
23 |
+
#include "zend_bitset.h"
|
24 |
+
|
25 |
+
typedef struct _zend_worklist_stack {
|
26 |
+
int *buf;
|
27 |
+
int len;
|
28 |
+
int capacity;
|
29 |
+
} zend_worklist_stack;
|
30 |
+
|
31 |
+
#define ZEND_WORKLIST_STACK_ALLOCA(s, _len, use_heap) do { \
|
32 |
+
(s)->buf = (int*)do_alloca(sizeof(int) * _len, use_heap); \
|
33 |
+
(s)->len = 0; \
|
34 |
+
(s)->capacity = _len; \
|
35 |
+
} while (0)
|
36 |
+
|
37 |
+
#define ZEND_WORKLIST_STACK_FREE_ALLOCA(s, use_heap) \
|
38 |
+
free_alloca((s)->buf, use_heap)
|
39 |
+
|
40 |
+
static inline int zend_worklist_stack_prepare(zend_arena **arena, zend_worklist_stack *stack, int len)
|
41 |
+
{
|
42 |
+
ZEND_ASSERT(len >= 0);
|
43 |
+
|
44 |
+
stack->buf = (int*)zend_arena_calloc(arena, sizeof(*stack->buf), len);
|
45 |
+
stack->len = 0;
|
46 |
+
stack->capacity = len;
|
47 |
+
|
48 |
+
return SUCCESS;
|
49 |
+
}
|
50 |
+
|
51 |
+
static inline void zend_worklist_stack_push(zend_worklist_stack *stack, int i)
|
52 |
+
{
|
53 |
+
ZEND_ASSERT(stack->len < stack->capacity);
|
54 |
+
stack->buf[stack->len++] = i;
|
55 |
+
}
|
56 |
+
|
57 |
+
static inline int zend_worklist_stack_peek(zend_worklist_stack *stack)
|
58 |
+
{
|
59 |
+
ZEND_ASSERT(stack->len);
|
60 |
+
return stack->buf[stack->len - 1];
|
61 |
+
}
|
62 |
+
|
63 |
+
static inline int zend_worklist_stack_pop(zend_worklist_stack *stack)
|
64 |
+
{
|
65 |
+
ZEND_ASSERT(stack->len);
|
66 |
+
return stack->buf[--stack->len];
|
67 |
+
}
|
68 |
+
|
69 |
+
typedef struct _zend_worklist {
|
70 |
+
zend_bitset visited;
|
71 |
+
zend_worklist_stack stack;
|
72 |
+
} zend_worklist;
|
73 |
+
|
74 |
+
#define ZEND_WORKLIST_ALLOCA(w, _len, use_heap) do { \
|
75 |
+
(w)->stack.buf = (int*)do_alloca(ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len) + sizeof(zend_ulong) * zend_bitset_len(_len), use_heap); \
|
76 |
+
(w)->stack.len = 0; \
|
77 |
+
(w)->stack.capacity = _len; \
|
78 |
+
(w)->visited = (zend_bitset)((char*)(w)->stack.buf + ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len)); \
|
79 |
+
memset((w)->visited, 0, sizeof(zend_ulong) * zend_bitset_len(_len)); \
|
80 |
+
} while (0)
|
81 |
+
|
82 |
+
#define ZEND_WORKLIST_FREE_ALLOCA(w, use_heap) \
|
83 |
+
free_alloca((w)->stack.buf, use_heap)
|
84 |
+
|
85 |
+
static inline int zend_worklist_prepare(zend_arena **arena, zend_worklist *worklist, int len)
|
86 |
+
{
|
87 |
+
ZEND_ASSERT(len >= 0);
|
88 |
+
worklist->visited = (zend_bitset)zend_arena_calloc(arena, sizeof(zend_ulong), zend_bitset_len(len));
|
89 |
+
return zend_worklist_stack_prepare(arena, &worklist->stack, len);
|
90 |
+
}
|
91 |
+
|
92 |
+
static inline int zend_worklist_len(zend_worklist *worklist)
|
93 |
+
{
|
94 |
+
return worklist->stack.len;
|
95 |
+
}
|
96 |
+
|
97 |
+
static inline int zend_worklist_push(zend_worklist *worklist, int i)
|
98 |
+
{
|
99 |
+
ZEND_ASSERT(i >= 0 && i < worklist->stack.capacity);
|
100 |
+
|
101 |
+
if (zend_bitset_in(worklist->visited, i)) {
|
102 |
+
return 0;
|
103 |
+
}
|
104 |
+
|
105 |
+
zend_bitset_incl(worklist->visited, i);
|
106 |
+
zend_worklist_stack_push(&worklist->stack, i);
|
107 |
+
return 1;
|
108 |
+
}
|
109 |
+
|
110 |
+
static inline int zend_worklist_peek(zend_worklist *worklist)
|
111 |
+
{
|
112 |
+
return zend_worklist_stack_peek(&worklist->stack);
|
113 |
+
}
|
114 |
+
|
115 |
+
static inline int zend_worklist_pop(zend_worklist *worklist)
|
116 |
+
{
|
117 |
+
/* Does not clear visited flag */
|
118 |
+
return zend_worklist_stack_pop(&worklist->stack);
|
119 |
+
}
|
120 |
+
|
121 |
+
#endif /* _ZEND_WORKLIST_H_ */
|
pcov-1.0.11/pcov-1.0.11/config.m4
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
dnl $Id$
|
2 |
+
dnl config.m4 for extension pcov
|
3 |
+
|
4 |
+
PHP_ARG_ENABLE(pcov, whether to enable php coverage support,
|
5 |
+
[ --enable-pcov Enable php coverage support])
|
6 |
+
|
7 |
+
if test "$PHP_PCOV" != "no"; then
|
8 |
+
PHP_VERSION=$($PHP_CONFIG --vernum)
|
9 |
+
|
10 |
+
AC_MSG_CHECKING(PHP version)
|
11 |
+
|
12 |
+
if test $PHP_VERSION -gt 80099; then
|
13 |
+
PHP_NEW_EXTENSION(pcov, pcov.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
|
14 |
+
else
|
15 |
+
if test $PHP_VERSION -lt 70100; then
|
16 |
+
AC_MSG_ERROR([pcov supports PHP 7.1+])
|
17 |
+
elif test $PHP_VERSION -lt 70200; then
|
18 |
+
AC_MSG_RESULT(7.1)
|
19 |
+
PHP_PCOV_CFG_VERSION=701
|
20 |
+
elif test $PHP_VERSION -lt 70300; then
|
21 |
+
AC_MSG_RESULT(7.2)
|
22 |
+
PHP_PCOV_CFG_VERSION=702
|
23 |
+
elif test $PHP_VERSION -lt 70400; then
|
24 |
+
AC_MSG_RESULT(7.3)
|
25 |
+
PHP_PCOV_CFG_VERSION=703
|
26 |
+
else
|
27 |
+
AC_MSG_RESULT(7.4+)
|
28 |
+
PHP_PCOV_CFG_VERSION=704
|
29 |
+
fi
|
30 |
+
|
31 |
+
PHP_NEW_EXTENSION(pcov, pcov.c cfg/$PHP_PCOV_CFG_VERSION/zend_cfg.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
|
32 |
+
PHP_ADD_BUILD_DIR($ext_builddir/cfg/$PHP_PCOV_CFG_VERSION, 1)
|
33 |
+
PHP_ADD_INCLUDE($ext_srcdir/cfg/$PHP_PCOV_CFG_VERSION)
|
34 |
+
fi
|
35 |
+
fi
|
pcov-1.0.11/pcov-1.0.11/config.w32
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// $Id$
|
2 |
+
// vim:ft=javascript
|
3 |
+
|
4 |
+
ARG_ENABLE("pcov", "enable php coverage support", "no");
|
5 |
+
|
6 |
+
if (PHP_PCOV != "no") {
|
7 |
+
if (PHP_VERSION < 7 || PHP_VERSION == 7 && PHP_MINOR_VERSION < 1) {
|
8 |
+
ERROR("pcov supports PHP 7.1+");
|
9 |
+
}
|
10 |
+
|
11 |
+
if (PHP_VERSION > 8 || PHP_VERSION == 8 && PHP_MINOR_VERSION >= 1) {
|
12 |
+
EXTENSION("pcov", "pcov.c", PHP_PCOV_SHARED,
|
13 |
+
"/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
14 |
+
} else {
|
15 |
+
var cfg_dir;
|
16 |
+
|
17 |
+
if (PHP_VERSION == 7 && PHP_MINOR_VERSION < 4) {
|
18 |
+
cfg_dir = PHP_VERSION + "0" + PHP_MINOR_VERSION;
|
19 |
+
} else {
|
20 |
+
cfg_dir = "704";
|
21 |
+
}
|
22 |
+
|
23 |
+
EXTENSION("pcov", "pcov.c", PHP_PCOV_SHARED,
|
24 |
+
"/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 /I" +
|
25 |
+
configure_module_dirname + "/cfg/" + cfg_dir);
|
26 |
+
ADD_SOURCES(
|
27 |
+
configure_module_dirname + "/cfg/" + cfg_dir,
|
28 |
+
"zend_cfg.c",
|
29 |
+
"pcov"
|
30 |
+
);
|
31 |
+
}
|
32 |
+
}
|
pcov-1.0.11/pcov-1.0.11/pcov.c
ADDED
@@ -0,0 +1,909 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Copyright (c) The PHP Group |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
6 |
+
| that is bundled with this package in the file LICENSE, and is |
|
7 |
+
| available through the world-wide-web at the following url: |
|
8 |
+
| http://www.php.net/license/3_01.txt |
|
9 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
10 |
+
| obtain it through the world-wide-web, please send a note to |
|
11 |
+
| [email protected] so we can mail you a copy immediately. |
|
12 |
+
+----------------------------------------------------------------------+
|
13 |
+
| Author: krakjoe |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
*/
|
16 |
+
|
17 |
+
/* $Id$ */
|
18 |
+
|
19 |
+
#ifdef HAVE_CONFIG_H
|
20 |
+
#include "config.h"
|
21 |
+
#endif
|
22 |
+
|
23 |
+
#include "php.h"
|
24 |
+
#include "php_ini.h"
|
25 |
+
#include "ext/standard/info.h"
|
26 |
+
#include "ext/pcre/php_pcre.h"
|
27 |
+
|
28 |
+
#include "zend_arena.h"
|
29 |
+
#if PHP_VERSION_ID < 80100
|
30 |
+
# include "zend_cfg.h"
|
31 |
+
# define PHP_PCOV_CFG ZEND_RT_CONSTANTS
|
32 |
+
#else
|
33 |
+
# include "Zend/Optimizer/zend_cfg.h"
|
34 |
+
# define PHP_PCOV_CFG 0
|
35 |
+
#endif
|
36 |
+
#include "zend_exceptions.h"
|
37 |
+
#include "zend_vm.h"
|
38 |
+
#include "zend_vm_opcodes.h"
|
39 |
+
|
40 |
+
#include "php_pcov.h"
|
41 |
+
|
42 |
+
#define PCOV_FILTER_ALL 0
|
43 |
+
#define PCOV_FILTER_INCLUDE 1
|
44 |
+
#define PCOV_FILTER_EXCLUDE 2
|
45 |
+
|
46 |
+
#define PHP_PCOV_UNCOVERED -1
|
47 |
+
#define PHP_PCOV_COVERED 1
|
48 |
+
|
49 |
+
#ifndef GC_ADDREF
|
50 |
+
# define GC_ADDREF(g) ++GC_REFCOUNT(g)
|
51 |
+
#endif
|
52 |
+
|
53 |
+
#if PHP_VERSION_ID < 70300
|
54 |
+
#define php_pcre_pce_incref(c) (c)->refcount++
|
55 |
+
#define php_pcre_pce_decref(c) (c)->refcount--
|
56 |
+
#define GC_SET_REFCOUNT(ref, rc) (GC_REFCOUNT(ref) = (rc))
|
57 |
+
#endif
|
58 |
+
|
59 |
+
#define PHP_PCOV_API_ENABLED_GUARD() do { \
|
60 |
+
if (!INI_BOOL("pcov.enabled")) { \
|
61 |
+
return; \
|
62 |
+
} \
|
63 |
+
} while (0);
|
64 |
+
|
65 |
+
static zval php_pcov_uncovered;
|
66 |
+
static zval php_pcov_covered;
|
67 |
+
|
68 |
+
void (*zend_execute_ex_function)(zend_execute_data *execute_data);
|
69 |
+
zend_op_array* (*zend_compile_file_function)(zend_file_handle *fh, int type) = NULL;
|
70 |
+
|
71 |
+
ZEND_DECLARE_MODULE_GLOBALS(pcov)
|
72 |
+
|
73 |
+
PHP_INI_BEGIN()
|
74 |
+
STD_PHP_INI_BOOLEAN(
|
75 |
+
"pcov.enabled", "1",
|
76 |
+
PHP_INI_SYSTEM, OnUpdateBool,
|
77 |
+
ini.enabled, zend_pcov_globals, pcov_globals)
|
78 |
+
STD_PHP_INI_ENTRY (
|
79 |
+
"pcov.directory", "",
|
80 |
+
PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString,
|
81 |
+
ini.directory, zend_pcov_globals, pcov_globals)
|
82 |
+
STD_PHP_INI_ENTRY (
|
83 |
+
"pcov.exclude", "",
|
84 |
+
PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString,
|
85 |
+
ini.exclude, zend_pcov_globals, pcov_globals)
|
86 |
+
STD_PHP_INI_ENTRY(
|
87 |
+
"pcov.initial.memory", "65336",
|
88 |
+
PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateLong,
|
89 |
+
ini.memory, zend_pcov_globals, pcov_globals)
|
90 |
+
STD_PHP_INI_ENTRY(
|
91 |
+
"pcov.initial.files", "64",
|
92 |
+
PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateLong,
|
93 |
+
ini.files, zend_pcov_globals, pcov_globals)
|
94 |
+
PHP_INI_END()
|
95 |
+
|
96 |
+
static PHP_GINIT_FUNCTION(pcov)
|
97 |
+
{
|
98 |
+
#if defined(COMPILE_DL_PCOV) && defined(ZTS)
|
99 |
+
ZEND_TSRMLS_CACHE_UPDATE();
|
100 |
+
#endif
|
101 |
+
|
102 |
+
ZEND_SECURE_ZERO(pcov_globals, sizeof(zend_pcov_globals));
|
103 |
+
}
|
104 |
+
|
105 |
+
static zend_always_inline zend_bool php_pcov_wants(zend_string *filename) { /* {{{ */
|
106 |
+
if (!PCG(directory)) {
|
107 |
+
return 1;
|
108 |
+
}
|
109 |
+
|
110 |
+
if (ZSTR_LEN(filename) < ZSTR_LEN(PCG(directory))) {
|
111 |
+
return 0;
|
112 |
+
}
|
113 |
+
|
114 |
+
if (zend_hash_exists(&PCG(wants), filename)) {
|
115 |
+
return 1;
|
116 |
+
}
|
117 |
+
|
118 |
+
if (zend_hash_exists(&PCG(ignores), filename)) {
|
119 |
+
return 0;
|
120 |
+
}
|
121 |
+
|
122 |
+
if (strncmp(
|
123 |
+
ZSTR_VAL(filename),
|
124 |
+
ZSTR_VAL(PCG(directory)),
|
125 |
+
ZSTR_LEN(PCG(directory))) == SUCCESS) {
|
126 |
+
|
127 |
+
if (PCG(exclude)) {
|
128 |
+
zval match;
|
129 |
+
|
130 |
+
ZVAL_UNDEF(&match);
|
131 |
+
|
132 |
+
php_pcre_match_impl(
|
133 |
+
PCG(exclude),
|
134 |
+
#if PHP_VERSION_ID >= 70400
|
135 |
+
filename,
|
136 |
+
#else
|
137 |
+
ZSTR_VAL(filename), ZSTR_LEN(filename),
|
138 |
+
#endif
|
139 |
+
&match, NULL,
|
140 |
+
0, 0, 0, 0);
|
141 |
+
|
142 |
+
if (zend_is_true(&match)) {
|
143 |
+
zend_hash_add_empty_element(
|
144 |
+
&PCG(ignores), filename);
|
145 |
+
return 0;
|
146 |
+
}
|
147 |
+
}
|
148 |
+
|
149 |
+
zend_hash_add_empty_element(&PCG(wants), filename);
|
150 |
+
return 1;
|
151 |
+
}
|
152 |
+
|
153 |
+
zend_hash_add_empty_element(&PCG(ignores), filename);
|
154 |
+
return 0;
|
155 |
+
} /* }}} */
|
156 |
+
|
157 |
+
static zend_always_inline zend_bool php_pcov_ignored_opcode(zend_uchar opcode) { /* {{{ */
|
158 |
+
return
|
159 |
+
opcode == ZEND_NOP ||
|
160 |
+
opcode == ZEND_OP_DATA ||
|
161 |
+
opcode == ZEND_FE_FREE ||
|
162 |
+
opcode == ZEND_FREE ||
|
163 |
+
opcode == ZEND_ASSERT_CHECK ||
|
164 |
+
opcode == ZEND_VERIFY_RETURN_TYPE ||
|
165 |
+
opcode == ZEND_RECV ||
|
166 |
+
opcode == ZEND_RECV_INIT ||
|
167 |
+
opcode == ZEND_RECV_VARIADIC ||
|
168 |
+
opcode == ZEND_SEND_VAL ||
|
169 |
+
opcode == ZEND_SEND_VAR_EX ||
|
170 |
+
opcode == ZEND_SEND_REF ||
|
171 |
+
opcode == ZEND_SEND_UNPACK ||
|
172 |
+
opcode == ZEND_DECLARE_CONST ||
|
173 |
+
opcode == ZEND_DECLARE_CLASS ||
|
174 |
+
#ifdef ZEND_DECLARE_INHERITED_CLASS
|
175 |
+
opcode == ZEND_DECLARE_INHERITED_CLASS ||
|
176 |
+
opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED ||
|
177 |
+
opcode == ZEND_DECLARE_ANON_INHERITED_CLASS ||
|
178 |
+
#else
|
179 |
+
opcode == ZEND_DECLARE_CLASS_DELAYED ||
|
180 |
+
#endif
|
181 |
+
opcode == ZEND_DECLARE_FUNCTION ||
|
182 |
+
opcode == ZEND_DECLARE_ANON_CLASS ||
|
183 |
+
opcode == ZEND_FAST_RET ||
|
184 |
+
opcode == ZEND_FAST_CALL ||
|
185 |
+
opcode == ZEND_TICKS ||
|
186 |
+
opcode == ZEND_EXT_STMT ||
|
187 |
+
opcode == ZEND_EXT_FCALL_BEGIN ||
|
188 |
+
opcode == ZEND_EXT_FCALL_END ||
|
189 |
+
opcode == ZEND_EXT_NOP ||
|
190 |
+
#if PHP_VERSION_ID < 70400
|
191 |
+
opcode == ZEND_VERIFY_ABSTRACT_CLASS ||
|
192 |
+
opcode == ZEND_ADD_TRAIT ||
|
193 |
+
opcode == ZEND_BIND_TRAITS ||
|
194 |
+
#endif
|
195 |
+
opcode == ZEND_BIND_GLOBAL
|
196 |
+
;
|
197 |
+
} /* }}} */
|
198 |
+
|
199 |
+
static zend_always_inline zend_string* php_pcov_interned_string(zend_string *string) { /* {{{ */
|
200 |
+
if (ZSTR_IS_INTERNED(string)) {
|
201 |
+
return string;
|
202 |
+
}
|
203 |
+
|
204 |
+
return zend_new_interned_string(zend_string_copy(string));
|
205 |
+
} /* }}} */
|
206 |
+
|
207 |
+
static zend_always_inline php_coverage_t* php_pcov_create(zend_execute_data *execute_data) { /* {{{ */
|
208 |
+
php_coverage_t *create = (php_coverage_t*) zend_arena_alloc(&PCG(mem), sizeof(php_coverage_t));
|
209 |
+
|
210 |
+
create->file = php_pcov_interned_string(EX(func)->op_array.filename);
|
211 |
+
create->line = EX(opline)->lineno;
|
212 |
+
create->next = NULL;
|
213 |
+
|
214 |
+
zend_hash_add_empty_element(&PCG(waiting), create->file);
|
215 |
+
|
216 |
+
return create;
|
217 |
+
} /* }}} */
|
218 |
+
|
219 |
+
static zend_always_inline int php_pcov_has(zend_string *filename, uint32_t lineno) { /* {{{ */
|
220 |
+
HashTable *table = zend_hash_find_ptr(&PCG(covered), filename);
|
221 |
+
|
222 |
+
if (UNEXPECTED(!table)) {
|
223 |
+
HashTable covering;
|
224 |
+
|
225 |
+
zend_hash_init(&covering, 64, NULL, NULL, 0);
|
226 |
+
|
227 |
+
table = zend_hash_add_mem(
|
228 |
+
&PCG(covered), filename, &covering, sizeof(HashTable));
|
229 |
+
|
230 |
+
zend_hash_index_add_empty_element(table, lineno);
|
231 |
+
return 0;
|
232 |
+
}
|
233 |
+
|
234 |
+
if (EXPECTED(zend_hash_index_exists(table, lineno))) {
|
235 |
+
return 1;
|
236 |
+
}
|
237 |
+
|
238 |
+
zend_hash_index_add_empty_element(table, lineno);
|
239 |
+
return 0;
|
240 |
+
} /* }}} */
|
241 |
+
|
242 |
+
static zend_always_inline int php_pcov_trace(zend_execute_data *execute_data) { /* {{{ */
|
243 |
+
if (PCG(enabled)) {
|
244 |
+
if (php_pcov_wants(EX(func)->op_array.filename) &&
|
245 |
+
!php_pcov_ignored_opcode(EX(opline)->opcode) &&
|
246 |
+
!php_pcov_has(EX(func)->op_array.filename, EX(opline)->lineno)) {
|
247 |
+
|
248 |
+
php_coverage_t *coverage = php_pcov_create(execute_data);
|
249 |
+
|
250 |
+
if (!PCG(start)) {
|
251 |
+
PCG(start) = coverage;
|
252 |
+
} else {
|
253 |
+
*(PCG(next)) = coverage;
|
254 |
+
}
|
255 |
+
|
256 |
+
PCG(next) = &coverage->next;
|
257 |
+
}
|
258 |
+
}
|
259 |
+
|
260 |
+
return zend_vm_call_opcode_handler(execute_data);
|
261 |
+
} /* }}} */
|
262 |
+
|
263 |
+
zend_op_array* php_pcov_compile_file(zend_file_handle *fh, int type) { /* {{{ */
|
264 |
+
zend_op_array *result = zend_compile_file_function(fh, type), *mem;
|
265 |
+
|
266 |
+
if (!result || !result->filename || !php_pcov_wants(result->filename)) {
|
267 |
+
return result;
|
268 |
+
}
|
269 |
+
|
270 |
+
if (zend_hash_exists(&PCG(files), result->filename)) {
|
271 |
+
return result;
|
272 |
+
}
|
273 |
+
|
274 |
+
mem = zend_hash_add_mem(
|
275 |
+
&PCG(files),
|
276 |
+
result->filename,
|
277 |
+
result, sizeof(zend_op_array));
|
278 |
+
|
279 |
+
#if PHP_VERSION_ID >= 70400
|
280 |
+
if (result->refcount) {
|
281 |
+
(*result->refcount)++;
|
282 |
+
}
|
283 |
+
if (result->static_variables) {
|
284 |
+
if (!(GC_FLAGS(result->static_variables) & IS_ARRAY_IMMUTABLE)) {
|
285 |
+
GC_ADDREF(result->static_variables);
|
286 |
+
}
|
287 |
+
}
|
288 |
+
mem->fn_flags &= ~ZEND_ACC_HEAP_RT_CACHE;
|
289 |
+
#else
|
290 |
+
(void)mem;
|
291 |
+
function_add_ref((zend_function*)result);
|
292 |
+
#endif
|
293 |
+
|
294 |
+
return result;
|
295 |
+
} /* }}} */
|
296 |
+
|
297 |
+
void php_pcov_execute_ex(zend_execute_data *execute_data) { /* {{{ */
|
298 |
+
int zrc = 0;
|
299 |
+
|
300 |
+
while (1) {
|
301 |
+
zrc = php_pcov_trace(execute_data);
|
302 |
+
|
303 |
+
if (zrc != SUCCESS) {
|
304 |
+
if (zrc < SUCCESS) {
|
305 |
+
return;
|
306 |
+
}
|
307 |
+
execute_data = EG(current_execute_data);
|
308 |
+
}
|
309 |
+
}
|
310 |
+
} /* }}} */
|
311 |
+
|
312 |
+
void php_pcov_covered_dtor(zval *zv) { /* {{{ */
|
313 |
+
zend_hash_destroy(Z_PTR_P(zv));
|
314 |
+
efree(Z_PTR_P(zv));
|
315 |
+
} /* }}} */
|
316 |
+
|
317 |
+
void php_pcov_files_dtor(zval *zv) { /* {{{ */
|
318 |
+
destroy_op_array(Z_PTR_P(zv));
|
319 |
+
efree(Z_PTR_P(zv));
|
320 |
+
} /* }}} */
|
321 |
+
|
322 |
+
void php_pcov_filename_dtor(zval *zv) { /* {{{ */
|
323 |
+
free(Z_PTR_P(zv));
|
324 |
+
} /* }}} */
|
325 |
+
|
326 |
+
/* {{{ PHP_MINIT_FUNCTION
|
327 |
+
*/
|
328 |
+
PHP_MINIT_FUNCTION(pcov)
|
329 |
+
{
|
330 |
+
REGISTER_NS_LONG_CONSTANT("pcov", "all", PCOV_FILTER_ALL, CONST_CS|CONST_PERSISTENT);
|
331 |
+
REGISTER_NS_LONG_CONSTANT("pcov", "inclusive", PCOV_FILTER_INCLUDE, CONST_CS|CONST_PERSISTENT);
|
332 |
+
REGISTER_NS_LONG_CONSTANT("pcov", "exclusive", PCOV_FILTER_EXCLUDE, CONST_CS|CONST_PERSISTENT);
|
333 |
+
|
334 |
+
REGISTER_NS_STRING_CONSTANT("pcov", "version", PHP_PCOV_VERSION, CONST_CS|CONST_PERSISTENT);
|
335 |
+
|
336 |
+
REGISTER_INI_ENTRIES();
|
337 |
+
|
338 |
+
if (INI_BOOL("pcov.enabled")) {
|
339 |
+
zend_execute_ex_function = zend_execute_ex;
|
340 |
+
zend_execute_ex = php_pcov_execute_ex;
|
341 |
+
}
|
342 |
+
|
343 |
+
ZVAL_LONG(&php_pcov_uncovered, PHP_PCOV_UNCOVERED);
|
344 |
+
ZVAL_LONG(&php_pcov_covered, PHP_PCOV_COVERED);
|
345 |
+
|
346 |
+
return SUCCESS;
|
347 |
+
}
|
348 |
+
/* }}} */
|
349 |
+
|
350 |
+
/* {{{ PHP_MSHUTDOWN_FUNCTION
|
351 |
+
*/
|
352 |
+
PHP_MSHUTDOWN_FUNCTION(pcov)
|
353 |
+
{
|
354 |
+
if (INI_BOOL("pcov.enabled")) {
|
355 |
+
zend_execute_ex = zend_execute_ex_function;
|
356 |
+
}
|
357 |
+
|
358 |
+
UNREGISTER_INI_ENTRIES();
|
359 |
+
|
360 |
+
return SUCCESS;
|
361 |
+
}
|
362 |
+
/* }}} */
|
363 |
+
|
364 |
+
const char *php_pcov_directory_defaults[] = { /* {{{ */
|
365 |
+
"src",
|
366 |
+
"lib",
|
367 |
+
"app",
|
368 |
+
".",
|
369 |
+
NULL
|
370 |
+
}; /* }}} */
|
371 |
+
|
372 |
+
static void php_pcov_setup_directory(char *directory) { /* {{{ */
|
373 |
+
char realpath[MAXPATHLEN];
|
374 |
+
zend_stat_t statbuf;
|
375 |
+
|
376 |
+
if (!directory || !*directory) {
|
377 |
+
const char** try = php_pcov_directory_defaults;
|
378 |
+
|
379 |
+
while (*try) {
|
380 |
+
if (VCWD_REALPATH(*try, realpath) &&
|
381 |
+
VCWD_STAT(realpath, &statbuf) == SUCCESS) {
|
382 |
+
directory = realpath;
|
383 |
+
break;
|
384 |
+
}
|
385 |
+
try++;
|
386 |
+
}
|
387 |
+
} else {
|
388 |
+
if (VCWD_REALPATH(directory, realpath) &&
|
389 |
+
VCWD_STAT(realpath, &statbuf) == SUCCESS) {
|
390 |
+
directory = realpath;
|
391 |
+
}
|
392 |
+
}
|
393 |
+
|
394 |
+
PCG(directory) = zend_string_init(directory, strlen(directory), 0);
|
395 |
+
} /* }}} */
|
396 |
+
|
397 |
+
static zend_always_inline void php_pcov_setup_exclude(char *exclude) { /* {{{ */
|
398 |
+
zend_string *pattern;
|
399 |
+
|
400 |
+
if (!exclude || !*exclude) {
|
401 |
+
return;
|
402 |
+
}
|
403 |
+
|
404 |
+
pattern = zend_string_init(
|
405 |
+
exclude, strlen(exclude), 0);
|
406 |
+
|
407 |
+
PCG(exclude) = pcre_get_compiled_regex_cache(pattern);
|
408 |
+
|
409 |
+
if (PCG(exclude)) {
|
410 |
+
php_pcre_pce_incref(PCG(exclude));
|
411 |
+
}
|
412 |
+
|
413 |
+
zend_string_release(pattern);
|
414 |
+
} /* }}} */
|
415 |
+
|
416 |
+
/* {{{ PHP_RINIT_FUNCTION
|
417 |
+
*/
|
418 |
+
PHP_RINIT_FUNCTION(pcov)
|
419 |
+
{
|
420 |
+
#if defined(COMPILE_DL_PCOV) && defined(ZTS)
|
421 |
+
ZEND_TSRMLS_CACHE_UPDATE();
|
422 |
+
#endif
|
423 |
+
|
424 |
+
if (!INI_BOOL("pcov.enabled")) {
|
425 |
+
return SUCCESS;
|
426 |
+
}
|
427 |
+
|
428 |
+
PCG(mem) = zend_arena_create(INI_INT("pcov.initial.memory"));
|
429 |
+
|
430 |
+
zend_hash_init(&PCG(files), INI_INT("pcov.initial.files"), NULL, php_pcov_files_dtor, 0);
|
431 |
+
zend_hash_init(&PCG(waiting), INI_INT("pcov.initial.files"), NULL, NULL, 0);
|
432 |
+
zend_hash_init(&PCG(ignores), INI_INT("pcov.initial.files"), NULL, NULL, 0);
|
433 |
+
zend_hash_init(&PCG(wants), INI_INT("pcov.initial.files"), NULL, NULL, 0);
|
434 |
+
zend_hash_init(&PCG(discovered), INI_INT("pcov.initial.files"), NULL, ZVAL_PTR_DTOR, 0);
|
435 |
+
zend_hash_init(&PCG(covered), INI_INT("pcov.initial.files"), NULL, php_pcov_covered_dtor, 0);
|
436 |
+
|
437 |
+
php_pcov_setup_directory(INI_STR("pcov.directory"));
|
438 |
+
php_pcov_setup_exclude(INI_STR("pcov.exclude"));
|
439 |
+
|
440 |
+
#ifdef ZEND_COMPILE_NO_JUMPTABLES
|
441 |
+
CG(compiler_options) |= ZEND_COMPILE_NO_JUMPTABLES;
|
442 |
+
#endif
|
443 |
+
|
444 |
+
if (!zend_compile_file_function) {
|
445 |
+
zend_compile_file_function = zend_compile_file;
|
446 |
+
zend_compile_file = php_pcov_compile_file;
|
447 |
+
}
|
448 |
+
|
449 |
+
PCG(start) = NULL;
|
450 |
+
PCG(last) = NULL;
|
451 |
+
PCG(next) = NULL;
|
452 |
+
|
453 |
+
return SUCCESS;
|
454 |
+
}
|
455 |
+
/* }}} */
|
456 |
+
|
457 |
+
/* {{{ PHP_RSHUTDOWN_FUNCTION
|
458 |
+
*/
|
459 |
+
PHP_RSHUTDOWN_FUNCTION(pcov)
|
460 |
+
{
|
461 |
+
if (!INI_BOOL("pcov.enabled") || CG(unclean_shutdown)) {
|
462 |
+
return SUCCESS;
|
463 |
+
}
|
464 |
+
|
465 |
+
zend_hash_destroy(&PCG(files));
|
466 |
+
zend_hash_destroy(&PCG(ignores));
|
467 |
+
zend_hash_destroy(&PCG(wants));
|
468 |
+
zend_hash_destroy(&PCG(discovered));
|
469 |
+
zend_hash_destroy(&PCG(waiting));
|
470 |
+
zend_hash_destroy(&PCG(covered));
|
471 |
+
|
472 |
+
zend_arena_destroy(PCG(mem));
|
473 |
+
|
474 |
+
if (PCG(directory)) {
|
475 |
+
zend_string_release(PCG(directory));
|
476 |
+
}
|
477 |
+
|
478 |
+
if (PCG(exclude)) {
|
479 |
+
php_pcre_pce_decref(PCG(exclude));
|
480 |
+
}
|
481 |
+
|
482 |
+
if (zend_compile_file == php_pcov_compile_file) {
|
483 |
+
zend_compile_file = zend_compile_file_function;
|
484 |
+
zend_compile_file_function = NULL;
|
485 |
+
}
|
486 |
+
|
487 |
+
return SUCCESS;
|
488 |
+
}
|
489 |
+
/* }}} */
|
490 |
+
|
491 |
+
/* {{{ PHP_MINFO_FUNCTION
|
492 |
+
*/
|
493 |
+
PHP_MINFO_FUNCTION(pcov)
|
494 |
+
{
|
495 |
+
char info[64];
|
496 |
+
char *directory = INI_STR("pcov.directory");
|
497 |
+
char *exclude = INI_STR("pcov.exclude");
|
498 |
+
|
499 |
+
php_info_print_table_start();
|
500 |
+
|
501 |
+
php_info_print_table_header(2,
|
502 |
+
"PCOV support",
|
503 |
+
INI_BOOL("pcov.enabled") ? "Enabled" : "Disabled");
|
504 |
+
php_info_print_table_row(2,
|
505 |
+
"PCOV version",
|
506 |
+
PHP_PCOV_VERSION);
|
507 |
+
php_info_print_table_row(2,
|
508 |
+
"pcov.directory",
|
509 |
+
directory && *directory ? directory : (PCG(directory) ? ZSTR_VAL(PCG(directory)) : "auto"));
|
510 |
+
php_info_print_table_row(2,
|
511 |
+
"pcov.exclude",
|
512 |
+
exclude && *exclude ? exclude : "none" );
|
513 |
+
|
514 |
+
snprintf(info, sizeof(info),
|
515 |
+
ZEND_LONG_FMT " bytes",
|
516 |
+
(zend_long) INI_INT("pcov.initial.memory"));
|
517 |
+
php_info_print_table_row(2,
|
518 |
+
"pcov.initial.memory", info);
|
519 |
+
|
520 |
+
snprintf(info, sizeof(info),
|
521 |
+
ZEND_LONG_FMT,
|
522 |
+
(zend_long) INI_INT("pcov.initial.files"));
|
523 |
+
php_info_print_table_row(2,
|
524 |
+
"pcov.initial.files", info);
|
525 |
+
|
526 |
+
php_info_print_table_end();
|
527 |
+
}
|
528 |
+
/* }}} */
|
529 |
+
|
530 |
+
static zend_always_inline void php_pcov_report(php_coverage_t *coverage, zval *filter) { /* {{{ */
|
531 |
+
zval *table;
|
532 |
+
zval *hit;
|
533 |
+
|
534 |
+
if (!coverage) {
|
535 |
+
return;
|
536 |
+
}
|
537 |
+
|
538 |
+
do {
|
539 |
+
if ((table = zend_hash_find(Z_ARRVAL_P(filter), coverage->file))) {
|
540 |
+
if ((hit = zend_hash_index_find(Z_ARRVAL_P(table), coverage->line))) {
|
541 |
+
Z_LVAL_P(hit) = PHP_PCOV_COVERED;
|
542 |
+
}
|
543 |
+
}
|
544 |
+
} while ((coverage = coverage->next));
|
545 |
+
} /* }}} */
|
546 |
+
|
547 |
+
static void php_pcov_discover_code(zend_arena **arena, zend_op_array *ops, zval *return_value) { /* {{{ */
|
548 |
+
zend_cfg cfg;
|
549 |
+
zend_basic_block *block;
|
550 |
+
zend_op *limit = ops->opcodes + ops->last;
|
551 |
+
int i = 0;
|
552 |
+
|
553 |
+
if (ops->fn_flags & ZEND_ACC_ABSTRACT) {
|
554 |
+
return;
|
555 |
+
}
|
556 |
+
|
557 |
+
memset(&cfg, 0, sizeof(zend_cfg));
|
558 |
+
|
559 |
+
zend_build_cfg(arena, ops, PHP_PCOV_CFG, &cfg);
|
560 |
+
|
561 |
+
for (block = cfg.blocks, i = 0; i < cfg.blocks_count; i++, block++) {
|
562 |
+
zend_op *opline = ops->opcodes + block->start,
|
563 |
+
*end = opline + block->len;
|
564 |
+
|
565 |
+
if (!(block->flags & ZEND_BB_REACHABLE)) {
|
566 |
+
/*
|
567 |
+
* Note that, we don't care about unreachable blocks
|
568 |
+
* that would be removed by opcache, because it would
|
569 |
+
* create different reports depending on configuration
|
570 |
+
*/
|
571 |
+
continue;
|
572 |
+
}
|
573 |
+
|
574 |
+
while(opline < end) {
|
575 |
+
if (php_pcov_ignored_opcode(opline->opcode)) {
|
576 |
+
opline++;
|
577 |
+
continue;
|
578 |
+
}
|
579 |
+
|
580 |
+
if (!zend_hash_index_exists(Z_ARRVAL_P(return_value), opline->lineno)) {
|
581 |
+
zend_hash_index_add(
|
582 |
+
Z_ARRVAL_P(return_value),
|
583 |
+
opline->lineno, &php_pcov_uncovered);
|
584 |
+
}
|
585 |
+
|
586 |
+
if ((opline +0)->opcode == ZEND_NEW &&
|
587 |
+
(opline +1)->opcode == ZEND_DO_FCALL) {
|
588 |
+
opline++;
|
589 |
+
}
|
590 |
+
|
591 |
+
opline++;
|
592 |
+
}
|
593 |
+
|
594 |
+
if (block == cfg.blocks && opline == limit) {
|
595 |
+
/*
|
596 |
+
* If the first basic block finishes at the end of the op array
|
597 |
+
* then we don't care about subsequent blocks
|
598 |
+
*/
|
599 |
+
break;
|
600 |
+
}
|
601 |
+
}
|
602 |
+
|
603 |
+
#if PHP_VERSION_ID >= 80100
|
604 |
+
for (uint32_t def = 0; def < ops->num_dynamic_func_defs; def++) {
|
605 |
+
php_pcov_discover_code(arena, ops->dynamic_func_defs[def], return_value);
|
606 |
+
}
|
607 |
+
#endif
|
608 |
+
} /* }}} */
|
609 |
+
|
610 |
+
static void php_pcov_discover_file(zend_string *file, zval *return_value) { /* {{{ */
|
611 |
+
zval discovered;
|
612 |
+
zend_op_array *ops;
|
613 |
+
zval *cache = zend_hash_find(&PCG(discovered), file);
|
614 |
+
zend_arena *mem;
|
615 |
+
|
616 |
+
if (cache) {
|
617 |
+
zval uncached;
|
618 |
+
ZVAL_DUP(&uncached, cache);
|
619 |
+
|
620 |
+
zend_hash_update(Z_ARRVAL_P(return_value), file, &uncached);
|
621 |
+
return;
|
622 |
+
}
|
623 |
+
|
624 |
+
if (!(ops = zend_hash_find_ptr(&PCG(files), file))) {
|
625 |
+
return;
|
626 |
+
}
|
627 |
+
|
628 |
+
array_init(&discovered);
|
629 |
+
|
630 |
+
mem = zend_arena_create(1024 * 1024);
|
631 |
+
|
632 |
+
php_pcov_discover_code(&mem, ops, &discovered);
|
633 |
+
{
|
634 |
+
zend_class_entry *ce;
|
635 |
+
zend_op_array *function;
|
636 |
+
ZEND_HASH_FOREACH_PTR(EG(class_table), ce) {
|
637 |
+
if (ce->type != ZEND_USER_CLASS) {
|
638 |
+
continue;
|
639 |
+
}
|
640 |
+
|
641 |
+
ZEND_HASH_FOREACH_PTR(&ce->function_table, function) {
|
642 |
+
if (function->type == ZEND_USER_FUNCTION &&
|
643 |
+
function->filename &&
|
644 |
+
zend_string_equals(file, function->filename)) {
|
645 |
+
php_pcov_discover_code(&mem, function, &discovered);
|
646 |
+
}
|
647 |
+
} ZEND_HASH_FOREACH_END();
|
648 |
+
} ZEND_HASH_FOREACH_END();
|
649 |
+
}
|
650 |
+
|
651 |
+
{
|
652 |
+
zend_op_array *function;
|
653 |
+
ZEND_HASH_FOREACH_PTR(EG(function_table), function) {
|
654 |
+
if (function->type == ZEND_USER_FUNCTION &&
|
655 |
+
function->filename &&
|
656 |
+
zend_string_equals(file, function->filename)) {
|
657 |
+
php_pcov_discover_code(&mem, function, &discovered);
|
658 |
+
}
|
659 |
+
} ZEND_HASH_FOREACH_END();
|
660 |
+
}
|
661 |
+
|
662 |
+
zend_hash_update(&PCG(discovered), file, &discovered);
|
663 |
+
zend_arena_destroy(mem);
|
664 |
+
|
665 |
+
php_pcov_discover_file(file, return_value);
|
666 |
+
} /* }}} */
|
667 |
+
|
668 |
+
static zend_always_inline void php_pcov_clean(HashTable *table) { /* {{{ */
|
669 |
+
if (table->nNumUsed) {
|
670 |
+
zend_hash_clean(table);
|
671 |
+
}
|
672 |
+
} /* }}} */
|
673 |
+
|
674 |
+
/* {{{ array \pcov\collect(int $type = \pcov\all, array $filter = []); */
|
675 |
+
PHP_NAMED_FUNCTION(php_pcov_collect)
|
676 |
+
{
|
677 |
+
zend_long type = PCOV_FILTER_ALL;
|
678 |
+
zval *filter = NULL;
|
679 |
+
|
680 |
+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|la", &type, &filter) != SUCCESS) {
|
681 |
+
return;
|
682 |
+
}
|
683 |
+
|
684 |
+
PHP_PCOV_API_ENABLED_GUARD();
|
685 |
+
|
686 |
+
if (PCOV_FILTER_ALL != type &&
|
687 |
+
PCOV_FILTER_INCLUDE != type &&
|
688 |
+
PCOV_FILTER_EXCLUDE != type) {
|
689 |
+
zend_throw_error(zend_ce_type_error,
|
690 |
+
"type must be "
|
691 |
+
"\\pcov\\inclusive, "
|
692 |
+
"\\pcov\\exclusive, or \\pcov\\all");
|
693 |
+
return;
|
694 |
+
}
|
695 |
+
|
696 |
+
array_init(return_value);
|
697 |
+
|
698 |
+
if (PCG(last) == PCG(next)) {
|
699 |
+
return;
|
700 |
+
}
|
701 |
+
|
702 |
+
PCG(last) = PCG(next);
|
703 |
+
|
704 |
+
switch(type) {
|
705 |
+
case PCOV_FILTER_INCLUDE: {
|
706 |
+
zval *filtered;
|
707 |
+
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(filter), filtered) {
|
708 |
+
if (Z_TYPE_P(filtered) != IS_STRING) {
|
709 |
+
continue;
|
710 |
+
}
|
711 |
+
|
712 |
+
php_pcov_discover_file(Z_STR_P(filtered), return_value);
|
713 |
+
} ZEND_HASH_FOREACH_END();
|
714 |
+
} break;
|
715 |
+
|
716 |
+
case PCOV_FILTER_EXCLUDE: {
|
717 |
+
zend_string *name;
|
718 |
+
zval *filtered;
|
719 |
+
ZEND_HASH_FOREACH_STR_KEY(&PCG(files), name) {
|
720 |
+
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(filter), filtered) {
|
721 |
+
if (Z_TYPE_P(filtered) != IS_STRING) {
|
722 |
+
continue;
|
723 |
+
}
|
724 |
+
|
725 |
+
if (zend_string_equals(name, Z_STR_P(filtered))) {
|
726 |
+
goto _php_pcov_collect_exclude;
|
727 |
+
}
|
728 |
+
} ZEND_HASH_FOREACH_END();
|
729 |
+
php_pcov_discover_file(name, return_value);
|
730 |
+
|
731 |
+
_php_pcov_collect_exclude:
|
732 |
+
continue;
|
733 |
+
} ZEND_HASH_FOREACH_END();
|
734 |
+
} break;
|
735 |
+
|
736 |
+
case PCOV_FILTER_ALL: {
|
737 |
+
zend_string *name;
|
738 |
+
ZEND_HASH_FOREACH_STR_KEY(&PCG(files), name) {
|
739 |
+
php_pcov_discover_file(name, return_value);
|
740 |
+
} ZEND_HASH_FOREACH_END();
|
741 |
+
} break;
|
742 |
+
}
|
743 |
+
|
744 |
+
php_pcov_report(PCG(start), return_value);
|
745 |
+
} /* }}} */
|
746 |
+
|
747 |
+
/* {{{ void \pcov\start(void) */
|
748 |
+
PHP_NAMED_FUNCTION(php_pcov_start)
|
749 |
+
{
|
750 |
+
if (zend_parse_parameters_none() != SUCCESS) {
|
751 |
+
return;
|
752 |
+
}
|
753 |
+
|
754 |
+
PHP_PCOV_API_ENABLED_GUARD();
|
755 |
+
|
756 |
+
PCG(enabled) = 1;
|
757 |
+
} /* }}} */
|
758 |
+
|
759 |
+
/* {{{ void \pcov\stop(void) */
|
760 |
+
PHP_NAMED_FUNCTION(php_pcov_stop)
|
761 |
+
{
|
762 |
+
if (zend_parse_parameters_none() != SUCCESS) {
|
763 |
+
return;
|
764 |
+
}
|
765 |
+
|
766 |
+
PHP_PCOV_API_ENABLED_GUARD();
|
767 |
+
|
768 |
+
PCG(enabled) = 0;
|
769 |
+
} /* }}} */
|
770 |
+
|
771 |
+
/* {{{ void \pcov\clear(bool $files = 0) */
|
772 |
+
PHP_NAMED_FUNCTION(php_pcov_clear)
|
773 |
+
{
|
774 |
+
zend_bool files = 0;
|
775 |
+
|
776 |
+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &files) != SUCCESS) {
|
777 |
+
return;
|
778 |
+
}
|
779 |
+
|
780 |
+
PHP_PCOV_API_ENABLED_GUARD();
|
781 |
+
|
782 |
+
if (files) {
|
783 |
+
php_pcov_clean(&PCG(files));
|
784 |
+
php_pcov_clean(&PCG(discovered));
|
785 |
+
}
|
786 |
+
|
787 |
+
zend_arena_destroy(PCG(mem));
|
788 |
+
|
789 |
+
PCG(mem) =
|
790 |
+
zend_arena_create(
|
791 |
+
INI_INT("pcov.initial.memory"));
|
792 |
+
|
793 |
+
PCG(start) = NULL;
|
794 |
+
PCG(last) = NULL;
|
795 |
+
PCG(next) = NULL;
|
796 |
+
|
797 |
+
php_pcov_clean(&PCG(waiting));
|
798 |
+
php_pcov_clean(&PCG(covered));
|
799 |
+
} /* }}} */
|
800 |
+
|
801 |
+
/* {{{ array \pcov\waiting(void) */
|
802 |
+
PHP_NAMED_FUNCTION(php_pcov_waiting)
|
803 |
+
{
|
804 |
+
zend_string *waiting;
|
805 |
+
|
806 |
+
if (zend_parse_parameters_none() != SUCCESS) {
|
807 |
+
return;
|
808 |
+
}
|
809 |
+
|
810 |
+
PHP_PCOV_API_ENABLED_GUARD();
|
811 |
+
|
812 |
+
array_init(return_value);
|
813 |
+
|
814 |
+
ZEND_HASH_FOREACH_STR_KEY(&PCG(waiting), waiting) {
|
815 |
+
add_next_index_str(
|
816 |
+
return_value,
|
817 |
+
zend_string_copy(waiting));
|
818 |
+
} ZEND_HASH_FOREACH_END();
|
819 |
+
} /* }}} */
|
820 |
+
|
821 |
+
/* {{{ int \pcov\memory(void) */
|
822 |
+
PHP_NAMED_FUNCTION(php_pcov_memory)
|
823 |
+
{
|
824 |
+
zend_arena *arena = PCG(mem);
|
825 |
+
|
826 |
+
if (zend_parse_parameters_none() != SUCCESS) {
|
827 |
+
return;
|
828 |
+
}
|
829 |
+
|
830 |
+
PHP_PCOV_API_ENABLED_GUARD();
|
831 |
+
|
832 |
+
ZVAL_LONG(return_value, 0);
|
833 |
+
|
834 |
+
do {
|
835 |
+
Z_LVAL_P(return_value) += (arena->end - arena->ptr);
|
836 |
+
} while ((arena = arena->prev));
|
837 |
+
} /* }}} */
|
838 |
+
|
839 |
+
/* {{{ */
|
840 |
+
ZEND_BEGIN_ARG_INFO_EX(php_pcov_collect_arginfo, 0, 0, 0)
|
841 |
+
ZEND_ARG_TYPE_INFO(0, type, IS_LONG, 0)
|
842 |
+
ZEND_ARG_TYPE_INFO(0, filter, IS_ARRAY, 0)
|
843 |
+
ZEND_END_ARG_INFO() /* }}} */
|
844 |
+
|
845 |
+
/* {{{ */
|
846 |
+
ZEND_BEGIN_ARG_INFO_EX(php_pcov_clear_arginfo, 0, 0, 0)
|
847 |
+
ZEND_ARG_TYPE_INFO(0, files, _IS_BOOL, 0)
|
848 |
+
ZEND_END_ARG_INFO() /* }}} */
|
849 |
+
|
850 |
+
/* {{{ */
|
851 |
+
ZEND_BEGIN_ARG_INFO_EX(php_pcov_no_arginfo, 0, 0, 0)
|
852 |
+
ZEND_END_ARG_INFO() /* }}} */
|
853 |
+
|
854 |
+
/* {{{ php_pcov_functions[]
|
855 |
+
*/
|
856 |
+
const zend_function_entry php_pcov_functions[] = {
|
857 |
+
ZEND_NS_FENTRY("pcov", start, php_pcov_start, php_pcov_no_arginfo, 0)
|
858 |
+
ZEND_NS_FENTRY("pcov", stop, php_pcov_stop, php_pcov_no_arginfo, 0)
|
859 |
+
ZEND_NS_FENTRY("pcov", collect, php_pcov_collect, php_pcov_collect_arginfo, 0)
|
860 |
+
ZEND_NS_FENTRY("pcov", clear, php_pcov_clear, php_pcov_clear_arginfo, 0)
|
861 |
+
ZEND_NS_FENTRY("pcov", waiting, php_pcov_waiting, php_pcov_no_arginfo, 0)
|
862 |
+
ZEND_NS_FENTRY("pcov", memory, php_pcov_memory, php_pcov_no_arginfo, 0)
|
863 |
+
PHP_FE_END
|
864 |
+
};
|
865 |
+
/* }}} */
|
866 |
+
|
867 |
+
/* {{{ pcov_module_deps[] */
|
868 |
+
static const zend_module_dep pcov_module_deps[] = {
|
869 |
+
ZEND_MOD_REQUIRED("pcre")
|
870 |
+
ZEND_MOD_END
|
871 |
+
}; /* }}} */
|
872 |
+
|
873 |
+
/* {{{ pcov_module_entry
|
874 |
+
*/
|
875 |
+
zend_module_entry pcov_module_entry = {
|
876 |
+
STANDARD_MODULE_HEADER_EX,
|
877 |
+
NULL,
|
878 |
+
pcov_module_deps,
|
879 |
+
"pcov",
|
880 |
+
php_pcov_functions,
|
881 |
+
PHP_MINIT(pcov),
|
882 |
+
PHP_MSHUTDOWN(pcov),
|
883 |
+
PHP_RINIT(pcov),
|
884 |
+
PHP_RSHUTDOWN(pcov),
|
885 |
+
PHP_MINFO(pcov),
|
886 |
+
PHP_PCOV_VERSION,
|
887 |
+
PHP_MODULE_GLOBALS(pcov),
|
888 |
+
PHP_GINIT(pcov),
|
889 |
+
NULL,
|
890 |
+
NULL,
|
891 |
+
STANDARD_MODULE_PROPERTIES_EX
|
892 |
+
};
|
893 |
+
/* }}} */
|
894 |
+
|
895 |
+
#ifdef COMPILE_DL_PCOV
|
896 |
+
#ifdef ZTS
|
897 |
+
ZEND_TSRMLS_CACHE_DEFINE()
|
898 |
+
#endif
|
899 |
+
ZEND_GET_MODULE(pcov)
|
900 |
+
#endif
|
901 |
+
|
902 |
+
/*
|
903 |
+
* Local variables:
|
904 |
+
* tab-width: 4
|
905 |
+
* c-basic-offset: 4
|
906 |
+
* End:
|
907 |
+
* vim600: noet sw=4 ts=4 fdm=marker
|
908 |
+
* vim<600: noet sw=4 ts=4
|
909 |
+
*/
|
pcov-1.0.11/pcov-1.0.11/php_pcov.h
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
+----------------------------------------------------------------------+
|
3 |
+
| Copyright (c) The PHP Group |
|
4 |
+
+----------------------------------------------------------------------+
|
5 |
+
| This source file is subject to version 3.01 of the PHP license, |
|
6 |
+
| that is bundled with this package in the file LICENSE, and is |
|
7 |
+
| available through the world-wide-web at the following url: |
|
8 |
+
| http://www.php.net/license/3_01.txt |
|
9 |
+
| If you did not receive a copy of the PHP license and are unable to |
|
10 |
+
| obtain it through the world-wide-web, please send a note to |
|
11 |
+
| [email protected] so we can mail you a copy immediately. |
|
12 |
+
+----------------------------------------------------------------------+
|
13 |
+
| Author: krakjoe |
|
14 |
+
+----------------------------------------------------------------------+
|
15 |
+
*/
|
16 |
+
/* $Id$ */
|
17 |
+
|
18 |
+
#ifndef PHP_PCOV_H
|
19 |
+
#define PHP_PCOV_H
|
20 |
+
|
21 |
+
extern zend_module_entry pcov_module_entry;
|
22 |
+
#define phpext_pcov_ptr &pcov_module_entry
|
23 |
+
|
24 |
+
#define PHP_PCOV_VERSION "1.0.11"
|
25 |
+
|
26 |
+
#ifdef PHP_WIN32
|
27 |
+
# define PHP_PCOV_API __declspec(dllexport)
|
28 |
+
#elif defined(__GNUC__) && __GNUC__ >= 4
|
29 |
+
# define PHP_PCOV_API __attribute__ ((visibility("default")))
|
30 |
+
#else
|
31 |
+
# define PHP_PCOV_API
|
32 |
+
#endif
|
33 |
+
|
34 |
+
#ifdef ZTS
|
35 |
+
#include "TSRM.h"
|
36 |
+
#endif
|
37 |
+
|
38 |
+
typedef struct _php_coverage_t php_coverage_t;
|
39 |
+
|
40 |
+
struct _php_coverage_t {
|
41 |
+
zend_string *file;
|
42 |
+
uint32_t line;
|
43 |
+
php_coverage_t *next;
|
44 |
+
};
|
45 |
+
|
46 |
+
ZEND_BEGIN_MODULE_GLOBALS(pcov)
|
47 |
+
zend_bool enabled;
|
48 |
+
zend_arena *mem;
|
49 |
+
php_coverage_t *start;
|
50 |
+
php_coverage_t **next;
|
51 |
+
php_coverage_t **last;
|
52 |
+
HashTable waiting;
|
53 |
+
HashTable files;
|
54 |
+
HashTable ignores;
|
55 |
+
HashTable wants;
|
56 |
+
HashTable discovered;
|
57 |
+
HashTable covered;
|
58 |
+
zend_string *directory;
|
59 |
+
pcre_cache_entry *exclude;
|
60 |
+
struct {
|
61 |
+
zend_bool enabled;
|
62 |
+
zend_long memory;
|
63 |
+
zend_long files;
|
64 |
+
char *directory;
|
65 |
+
char *exclude;
|
66 |
+
} ini;
|
67 |
+
ZEND_END_MODULE_GLOBALS(pcov)
|
68 |
+
|
69 |
+
#define PCG(v) ZEND_MODULE_GLOBALS_ACCESSOR(pcov, v)
|
70 |
+
|
71 |
+
#if defined(ZTS) && defined(COMPILE_DL_PCOV)
|
72 |
+
ZEND_TSRMLS_CACHE_EXTERN()
|
73 |
+
#endif
|
74 |
+
|
75 |
+
#endif /* PHP_PCOV_H */
|
76 |
+
|
77 |
+
/*
|
78 |
+
* Local variables:
|
79 |
+
* tab-width: 4
|
80 |
+
* c-basic-offset: 4
|
81 |
+
* End:
|
82 |
+
* vim600: noet sw=4 ts=4 fdm=marker
|
83 |
+
* vim<600: noet sw=4 ts=4
|
84 |
+
*/
|
pcov-1.0.11/pcov-1.0.11/tests/001.phpt
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
start/stop
|
3 |
+
--SKIPIF--
|
4 |
+
<?php if (!extension_loaded("pcov")) print "skip"; ?>
|
5 |
+
--INI--
|
6 |
+
pcov.enabled = 1
|
7 |
+
--FILE--
|
8 |
+
<?php
|
9 |
+
\pcov\start();
|
10 |
+
$d = [];
|
11 |
+
for ($i = 0; $i < 10; $i++) {
|
12 |
+
$d[] = $i * 42;
|
13 |
+
}
|
14 |
+
\pcov\stop();
|
15 |
+
|
16 |
+
var_dump(\pcov\collect());
|
17 |
+
?>
|
18 |
+
--EXPECTF--
|
19 |
+
array(1) {
|
20 |
+
["%s%e001.php"]=>
|
21 |
+
array(7) {
|
22 |
+
[2]=>
|
23 |
+
int(-1)
|
24 |
+
[3]=>
|
25 |
+
int(1)
|
26 |
+
[4]=>
|
27 |
+
int(1)
|
28 |
+
[5]=>
|
29 |
+
int(1)
|
30 |
+
[7]=>
|
31 |
+
int(1)
|
32 |
+
[9]=>
|
33 |
+
int(-1)
|
34 |
+
[11]=>
|
35 |
+
int(-1)
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
pcov-1.0.11/pcov-1.0.11/tests/002.phpt
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
clear
|
3 |
+
--SKIPIF--
|
4 |
+
<?php if (!extension_loaded("pcov")) print "skip"; ?>
|
5 |
+
--INI--
|
6 |
+
pcov.enabled = 1
|
7 |
+
--FILE--
|
8 |
+
<?php
|
9 |
+
\pcov\start();
|
10 |
+
$d = [];
|
11 |
+
for ($i = 0; $i < 10; $i++) {
|
12 |
+
$d[] = $i * 42;
|
13 |
+
}
|
14 |
+
\pcov\stop();
|
15 |
+
|
16 |
+
var_dump(\pcov\collect());
|
17 |
+
|
18 |
+
\pcov\clear();
|
19 |
+
|
20 |
+
var_dump(\pcov\collect());
|
21 |
+
?>
|
22 |
+
--EXPECTF--
|
23 |
+
array(1) {
|
24 |
+
["%s%e002.php"]=>
|
25 |
+
array(9) {
|
26 |
+
[2]=>
|
27 |
+
int(-1)
|
28 |
+
[3]=>
|
29 |
+
int(1)
|
30 |
+
[4]=>
|
31 |
+
int(1)
|
32 |
+
[5]=>
|
33 |
+
int(1)
|
34 |
+
[7]=>
|
35 |
+
int(1)
|
36 |
+
[9]=>
|
37 |
+
int(-1)
|
38 |
+
[11]=>
|
39 |
+
int(-1)
|
40 |
+
[13]=>
|
41 |
+
int(-1)
|
42 |
+
[15]=>
|
43 |
+
int(-1)
|
44 |
+
}
|
45 |
+
}
|
46 |
+
array(0) {
|
47 |
+
}
|
48 |
+
|
49 |
+
|
pcov-1.0.11/pcov-1.0.11/tests/003.phpt
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
\pcov\collect non array filter
|
3 |
+
--SKIPIF--
|
4 |
+
<?php if (!extension_loaded("pcov")) print "skip"; ?>
|
5 |
+
--INI--
|
6 |
+
pcov.enabled = 0
|
7 |
+
--FILE--
|
8 |
+
<?php
|
9 |
+
var_dump(\pcov\collect(\pcov\inclusive, ""));
|
10 |
+
?>
|
11 |
+
--EXPECTF--
|
12 |
+
Fatal error: Uncaught TypeError: %s type array, string given in %s%e003.php:2
|
13 |
+
Stack trace:
|
14 |
+
#0 %s%e003.php(2): pcov\collect(1, '')
|
15 |
+
#1 {main}
|
16 |
+
thrown in %s%e003.php on line 2
|
pcov-1.0.11/pcov-1.0.11/tests/004.phpt
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
\pcov\collect not recognized filter type
|
3 |
+
--SKIPIF--
|
4 |
+
<?php if (!extension_loaded("pcov")) print "skip"; ?>
|
5 |
+
--INI--
|
6 |
+
pcov.enabled = 1
|
7 |
+
--FILE--
|
8 |
+
<?php
|
9 |
+
var_dump(\pcov\collect(42));
|
10 |
+
?>
|
11 |
+
--EXPECTF--
|
12 |
+
Fatal error: Uncaught TypeError: type must be \pcov\inclusive, \pcov\exclusive, or \pcov\all in %s%e004.php:2
|
13 |
+
Stack trace:
|
14 |
+
#0 %s%e004.php(2): pcov\collect(42)
|
15 |
+
#1 {main}
|
16 |
+
thrown in %s%e004.php on line 2
|
17 |
+
|
pcov-1.0.11/pcov-1.0.11/tests/005.phpt
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
anonymous class
|
3 |
+
--SKIPIF--
|
4 |
+
<?php if (!extension_loaded("pcov")) print "skip"; ?>
|
5 |
+
--INI--
|
6 |
+
pcov.enabled = 1
|
7 |
+
--FILE--
|
8 |
+
<?php
|
9 |
+
\pcov\start();
|
10 |
+
$a = new class() {};
|
11 |
+
\pcov\stop();
|
12 |
+
var_dump(\pcov\collect());
|
13 |
+
?>
|
14 |
+
--EXPECTF--
|
15 |
+
array(1) {
|
16 |
+
["%s%e005.php"]=>
|
17 |
+
array(5) {
|
18 |
+
[2]=>
|
19 |
+
int(-1)
|
20 |
+
[3]=>
|
21 |
+
int(1)
|
22 |
+
[4]=>
|
23 |
+
int(1)
|
24 |
+
[5]=>
|
25 |
+
int(-1)
|
26 |
+
[7]=>
|
27 |
+
int(-1)
|
28 |
+
}
|
29 |
+
}
|
pcov-1.0.11/pcov-1.0.11/tests/006.phpt
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
phpinfo
|
3 |
+
--SKIPIF--
|
4 |
+
<?php if (!extension_loaded("pcov")) print "skip"; ?>
|
5 |
+
--INI--
|
6 |
+
pcov.enabled = 0
|
7 |
+
--FILE--
|
8 |
+
<?php
|
9 |
+
phpinfo(INFO_MODULES);
|
10 |
+
?>
|
11 |
+
--EXPECTF--
|
12 |
+
%A
|
13 |
+
PCOV support => Disabled
|
14 |
+
PCOV version => %s
|
15 |
+
pcov.directory => auto
|
16 |
+
pcov.exclude => none
|
17 |
+
pcov.initial.memory => 65336 bytes
|
18 |
+
pcov.initial.files => 64
|
19 |
+
%A
|
pcov-1.0.11/pcov-1.0.11/tests/007.phpt
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
anonymous function
|
3 |
+
--SKIPIF--
|
4 |
+
<?php
|
5 |
+
if (!extension_loaded("pcov")) print "skip";
|
6 |
+
if (PHP_VERSION_ID < 80000) print "skip only for PHP 8";
|
7 |
+
?>
|
8 |
+
--INI--
|
9 |
+
pcov.enabled = 1
|
10 |
+
--FILE--
|
11 |
+
<?php
|
12 |
+
\pcov\start();
|
13 |
+
$a = function() {
|
14 |
+
return 'a';
|
15 |
+
};
|
16 |
+
$a();
|
17 |
+
\pcov\stop();
|
18 |
+
var_dump(\pcov\collect());
|
19 |
+
?>
|
20 |
+
--EXPECTF--
|
21 |
+
array(1) {
|
22 |
+
["%s%e007.php"]=>
|
23 |
+
array(7) {
|
24 |
+
[2]=>
|
25 |
+
int(-1)
|
26 |
+
[3]=>
|
27 |
+
int(1)
|
28 |
+
[6]=>
|
29 |
+
int(1)
|
30 |
+
[7]=>
|
31 |
+
int(1)
|
32 |
+
[8]=>
|
33 |
+
int(-1)
|
34 |
+
[10]=>
|
35 |
+
int(-1)
|
36 |
+
[4]=>
|
37 |
+
int(1)
|
38 |
+
}
|
39 |
+
}
|
tests/Feature/DatabaseTest.php
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Tests\Feature;
|
4 |
+
|
5 |
+
use Illuminate\Foundation\Testing\RefreshDatabase;
|
6 |
+
use Illuminate\Foundation\Testing\WithFaker;
|
7 |
+
use Tests\TestCase;
|
8 |
+
|
9 |
+
use App\Models\ListItem;
|
10 |
+
|
11 |
+
class DatabaseTest extends TestCase
|
12 |
+
{
|
13 |
+
use RefreshDatabase;
|
14 |
+
|
15 |
+
public function test_data_added(): void
|
16 |
+
{
|
17 |
+
ListItem::factory()->count(3)->create(); // means that we are are creating 3 fake data
|
18 |
+
// print(json_encode(ListItem::all()));
|
19 |
+
$this->assertDatabaseCount('list_items',3);
|
20 |
+
}
|
21 |
+
|
22 |
+
public function test_data_removed(){
|
23 |
+
ListItem::factory()->count(5)->create();
|
24 |
+
$allitems = ListItem::all();
|
25 |
+
|
26 |
+
for($i=0;$i<3;$i++){ // delete 3 items
|
27 |
+
$allitems[$i]->delete();
|
28 |
+
}
|
29 |
+
|
30 |
+
$this->assertDatabaseCount("list_items",2);
|
31 |
+
}
|
32 |
+
}
|
tests/Feature/TODOListControllerTest.php
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Tests\Feature;
|
4 |
+
|
5 |
+
use Illuminate\Foundation\Testing\RefreshDatabase;
|
6 |
+
use Illuminate\Foundation\Testing\WithFaker;
|
7 |
+
use Tests\TestCase;
|
8 |
+
use App\Http\Controllers\TODOListController;
|
9 |
+
use App\Models\ListItem;
|
10 |
+
|
11 |
+
class TODOListControllerTest extends TestCase
|
12 |
+
{
|
13 |
+
|
14 |
+
use RefreshDatabase;
|
15 |
+
|
16 |
+
public function test_index(){
|
17 |
+
|
18 |
+
$response = $this->get("/");
|
19 |
+
// print(json_encode($response));
|
20 |
+
$response->assertStatus($response->status(),200);
|
21 |
+
|
22 |
+
}
|
23 |
+
public function test_saveItem(){
|
24 |
+
|
25 |
+
$this->assertDatabaseCount('list_items',0);
|
26 |
+
|
27 |
+
$response = $this->call("POST", route("saveItem"),[
|
28 |
+
"text"=>"task 1"
|
29 |
+
]);
|
30 |
+
|
31 |
+
$this->assertDatabaseCount('list_items',1); // Check if item is added to the database
|
32 |
+
$this->assertEquals(ListItem::all()->first()->is_complete,0); // to check if the status was is incomplete by default
|
33 |
+
|
34 |
+
$this->assertEquals($response->status(),302); // status code 302 means redirect
|
35 |
+
|
36 |
+
}
|
37 |
+
|
38 |
+
public function test_changeStatus_to_done(){
|
39 |
+
|
40 |
+
$this->test_saveItem(); // add 1 item
|
41 |
+
|
42 |
+
$response = $this->call("POST", route("changeStatus",1),[
|
43 |
+
"checked"=>"on"
|
44 |
+
]);
|
45 |
+
|
46 |
+
$this->assertEquals(ListItem::all()->first()->is_complete,1); // to check if the status was changed to completed
|
47 |
+
|
48 |
+
$this->assertEquals($response->status(),302); // status code 302 means redirect
|
49 |
+
|
50 |
+
}
|
51 |
+
|
52 |
+
public function test_changeStatus_to_not_done(){
|
53 |
+
|
54 |
+
$this->test_changeStatus_to_done(); // get to the point where the status is done
|
55 |
+
|
56 |
+
$response = $this->call("POST", route("changeStatus",1),[
|
57 |
+
]);
|
58 |
+
|
59 |
+
$this->assertEquals(ListItem::all()->first()->is_complete,0); // to check if the status was changed to incomplete
|
60 |
+
|
61 |
+
$this->assertEquals($response->status(),302); // status code 302 means redirect
|
62 |
+
|
63 |
+
}
|
64 |
+
|
65 |
+
public function test_deleteItem(){
|
66 |
+
|
67 |
+
$this->test_saveItem(); // create an item
|
68 |
+
$response = $this->call("POST",route("deleteItem"),[
|
69 |
+
'id'=>"1",
|
70 |
+
]);
|
71 |
+
|
72 |
+
$this->assertDatabaseCount("list_items",0); // check if the item is deleted
|
73 |
+
$this->assertEquals($response->status(),302); // status code 302 means redirect
|
74 |
+
}
|
75 |
+
}
|