/src/php-src/Zend/zend_extensions.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Zend Engine | |
4 | | +----------------------------------------------------------------------+ |
5 | | | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | |
6 | | +----------------------------------------------------------------------+ |
7 | | | This source file is subject to version 2.00 of the Zend 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.zend.com/license/2_00.txt. | |
11 | | | If you did not receive a copy of the Zend license and are unable to | |
12 | | | obtain it through the world-wide-web, please send a note to | |
13 | | | license@zend.com so we can mail you a copy immediately. | |
14 | | +----------------------------------------------------------------------+ |
15 | | | Authors: Andi Gutmans <andi@php.net> | |
16 | | | Zeev Suraski <zeev@php.net> | |
17 | | +----------------------------------------------------------------------+ |
18 | | */ |
19 | | |
20 | | #include "zend_extensions.h" |
21 | | #include "zend_system_id.h" |
22 | | |
23 | | ZEND_API zend_llist zend_extensions; |
24 | | ZEND_API uint32_t zend_extension_flags = 0; |
25 | | ZEND_API int zend_op_array_extension_handles = 0; |
26 | | static int last_resource_number; |
27 | | |
28 | | zend_result zend_load_extension(const char *path) |
29 | 0 | { |
30 | 0 | #if ZEND_EXTENSIONS_SUPPORT |
31 | 0 | DL_HANDLE handle; |
32 | |
|
33 | 0 | handle = DL_LOAD(path); |
34 | 0 | if (!handle) { |
35 | 0 | #ifndef ZEND_WIN32 |
36 | 0 | fprintf(stderr, "Failed loading %s: %s\n", path, DL_ERROR()); |
37 | | #else |
38 | | fprintf(stderr, "Failed loading %s\n", path); |
39 | | /* See http://support.microsoft.com/kb/190351 */ |
40 | | fflush(stderr); |
41 | | #endif |
42 | 0 | return FAILURE; |
43 | 0 | } |
44 | | #ifdef ZEND_WIN32 |
45 | | char *err; |
46 | | if (!php_win32_image_compatible(handle, &err)) { |
47 | | zend_error(E_CORE_WARNING, err); |
48 | | return FAILURE; |
49 | | } |
50 | | #endif |
51 | 0 | return zend_load_extension_handle(handle, path); |
52 | | #else |
53 | | fprintf(stderr, "Extensions are not supported on this platform.\n"); |
54 | | /* See http://support.microsoft.com/kb/190351 */ |
55 | | #ifdef ZEND_WIN32 |
56 | | fflush(stderr); |
57 | | #endif |
58 | | return FAILURE; |
59 | | #endif |
60 | 0 | } |
61 | | |
62 | | zend_result zend_load_extension_handle(DL_HANDLE handle, const char *path) |
63 | 0 | { |
64 | 0 | #if ZEND_EXTENSIONS_SUPPORT |
65 | 0 | zend_extension *new_extension; |
66 | 0 | zend_extension_version_info *extension_version_info; |
67 | |
|
68 | 0 | extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "extension_version_info"); |
69 | 0 | if (!extension_version_info) { |
70 | 0 | extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "_extension_version_info"); |
71 | 0 | } |
72 | 0 | new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "zend_extension_entry"); |
73 | 0 | if (!new_extension) { |
74 | 0 | new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "_zend_extension_entry"); |
75 | 0 | } |
76 | 0 | if (!extension_version_info || !new_extension) { |
77 | 0 | fprintf(stderr, "%s doesn't appear to be a valid Zend extension\n", path); |
78 | | /* See http://support.microsoft.com/kb/190351 */ |
79 | | #ifdef ZEND_WIN32 |
80 | | fflush(stderr); |
81 | | #endif |
82 | 0 | DL_UNLOAD(handle); |
83 | 0 | return FAILURE; |
84 | 0 | } |
85 | | |
86 | | /* allow extension to proclaim compatibility with any Zend version */ |
87 | 0 | if (extension_version_info->zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { |
88 | 0 | if (extension_version_info->zend_extension_api_no > ZEND_EXTENSION_API_NO) { |
89 | 0 | fprintf(stderr, "%s requires Zend Engine API version %d.\n" |
90 | 0 | "The Zend Engine API version %d which is installed, is outdated.\n\n", |
91 | 0 | new_extension->name, |
92 | 0 | extension_version_info->zend_extension_api_no, |
93 | 0 | ZEND_EXTENSION_API_NO); |
94 | | /* See http://support.microsoft.com/kb/190351 */ |
95 | | #ifdef ZEND_WIN32 |
96 | | fflush(stderr); |
97 | | #endif |
98 | 0 | DL_UNLOAD(handle); |
99 | 0 | return FAILURE; |
100 | 0 | } else if (extension_version_info->zend_extension_api_no < ZEND_EXTENSION_API_NO) { |
101 | 0 | fprintf(stderr, "%s requires Zend Engine API version %d.\n" |
102 | 0 | "The Zend Engine API version %d which is installed, is newer.\n" |
103 | 0 | "Contact %s at %s for a later version of %s.\n\n", |
104 | 0 | new_extension->name, |
105 | 0 | extension_version_info->zend_extension_api_no, |
106 | 0 | ZEND_EXTENSION_API_NO, |
107 | 0 | new_extension->author, |
108 | 0 | new_extension->URL, |
109 | 0 | new_extension->name); |
110 | | /* See http://support.microsoft.com/kb/190351 */ |
111 | | #ifdef ZEND_WIN32 |
112 | | fflush(stderr); |
113 | | #endif |
114 | 0 | DL_UNLOAD(handle); |
115 | 0 | return FAILURE; |
116 | 0 | } |
117 | 0 | } else if (strcmp(ZEND_EXTENSION_BUILD_ID, extension_version_info->build_id) && |
118 | 0 | (!new_extension->build_id_check || new_extension->build_id_check(ZEND_EXTENSION_BUILD_ID) != SUCCESS)) { |
119 | 0 | fprintf(stderr, "Cannot load %s - it was built with configuration %s, whereas running engine is %s\n", |
120 | 0 | new_extension->name, extension_version_info->build_id, ZEND_EXTENSION_BUILD_ID); |
121 | | /* See http://support.microsoft.com/kb/190351 */ |
122 | | #ifdef ZEND_WIN32 |
123 | | fflush(stderr); |
124 | | #endif |
125 | 0 | DL_UNLOAD(handle); |
126 | 0 | return FAILURE; |
127 | 0 | } else if (zend_get_extension(new_extension->name)) { |
128 | 0 | fprintf(stderr, "Cannot load %s - it was already loaded\n", new_extension->name); |
129 | | /* See http://support.microsoft.com/kb/190351 */ |
130 | | #ifdef ZEND_WIN32 |
131 | | fflush(stderr); |
132 | | #endif |
133 | 0 | DL_UNLOAD(handle); |
134 | 0 | return FAILURE; |
135 | 0 | } |
136 | | |
137 | 0 | zend_register_extension(new_extension, handle); |
138 | 0 | return SUCCESS; |
139 | | #else |
140 | | fprintf(stderr, "Extensions are not supported on this platform.\n"); |
141 | | /* See http://support.microsoft.com/kb/190351 */ |
142 | | #ifdef ZEND_WIN32 |
143 | | fflush(stderr); |
144 | | #endif |
145 | | return FAILURE; |
146 | | #endif |
147 | 0 | } |
148 | | |
149 | | |
150 | | void zend_register_extension(zend_extension *new_extension, DL_HANDLE handle) |
151 | 0 | { |
152 | 0 | #if ZEND_EXTENSIONS_SUPPORT |
153 | 0 | zend_extension extension; |
154 | |
|
155 | 0 | extension = *new_extension; |
156 | 0 | extension.handle = handle; |
157 | |
|
158 | 0 | zend_extension_dispatch_message(ZEND_EXTMSG_NEW_EXTENSION, &extension); |
159 | |
|
160 | 0 | zend_llist_add_element(&zend_extensions, &extension); |
161 | |
|
162 | 0 | if (extension.op_array_ctor) { |
163 | 0 | zend_extension_flags |= ZEND_EXTENSIONS_HAVE_OP_ARRAY_CTOR; |
164 | 0 | } |
165 | 0 | if (extension.op_array_dtor) { |
166 | 0 | zend_extension_flags |= ZEND_EXTENSIONS_HAVE_OP_ARRAY_DTOR; |
167 | 0 | } |
168 | 0 | if (extension.op_array_handler) { |
169 | 0 | zend_extension_flags |= ZEND_EXTENSIONS_HAVE_OP_ARRAY_HANDLER; |
170 | 0 | } |
171 | 0 | if (extension.op_array_persist_calc) { |
172 | 0 | zend_extension_flags |= ZEND_EXTENSIONS_HAVE_OP_ARRAY_PERSIST_CALC; |
173 | 0 | } |
174 | 0 | if (extension.op_array_persist) { |
175 | 0 | zend_extension_flags |= ZEND_EXTENSIONS_HAVE_OP_ARRAY_PERSIST; |
176 | 0 | } |
177 | | /*fprintf(stderr, "Loaded %s, version %s\n", extension.name, extension.version);*/ |
178 | 0 | #endif |
179 | 0 | } |
180 | | |
181 | | |
182 | | static void zend_extension_shutdown(zend_extension *extension) |
183 | 0 | { |
184 | 0 | #if ZEND_EXTENSIONS_SUPPORT |
185 | 0 | if (extension->shutdown) { |
186 | 0 | extension->shutdown(extension); |
187 | 0 | } |
188 | 0 | #endif |
189 | 0 | } |
190 | | |
191 | | /* int return due to zend linked list API */ |
192 | | static int zend_extension_startup(zend_extension *extension) |
193 | 0 | { |
194 | 0 | #if ZEND_EXTENSIONS_SUPPORT |
195 | 0 | if (extension->startup) { |
196 | 0 | if (extension->startup(extension)!=SUCCESS) { |
197 | 0 | return 1; |
198 | 0 | } |
199 | 0 | zend_append_version_info(extension); |
200 | 0 | } |
201 | 0 | #endif |
202 | 0 | return 0; |
203 | 0 | } |
204 | | |
205 | | |
206 | | void zend_startup_extensions_mechanism(void) |
207 | 1.48k | { |
208 | | /* Startup extensions mechanism */ |
209 | 1.48k | zend_llist_init(&zend_extensions, sizeof(zend_extension), (void (*)(void *)) zend_extension_dtor, 1); |
210 | 1.48k | zend_op_array_extension_handles = 0; |
211 | 1.48k | last_resource_number = 0; |
212 | 1.48k | } |
213 | | |
214 | | |
215 | | void zend_startup_extensions(void) |
216 | 1.48k | { |
217 | 1.48k | zend_llist_apply_with_del(&zend_extensions, (int (*)(void *)) zend_extension_startup); |
218 | 1.48k | } |
219 | | |
220 | | |
221 | | void zend_shutdown_extensions(void) |
222 | 0 | { |
223 | 0 | zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_shutdown); |
224 | 0 | zend_llist_destroy(&zend_extensions); |
225 | 0 | } |
226 | | |
227 | | |
228 | | void zend_extension_dtor(zend_extension *extension) |
229 | 0 | { |
230 | | #if ZEND_EXTENSIONS_SUPPORT && !ZEND_DEBUG |
231 | | if (extension->handle && !getenv("ZEND_DONT_UNLOAD_MODULES")) { |
232 | | DL_UNLOAD(extension->handle); |
233 | | } |
234 | | #endif |
235 | 0 | } |
236 | | |
237 | | |
238 | | static void zend_extension_message_dispatcher(const zend_extension *extension, int num_args, va_list args) |
239 | 0 | { |
240 | 0 | int message; |
241 | 0 | void *arg; |
242 | |
|
243 | 0 | if (!extension->message_handler || num_args!=2) { |
244 | 0 | return; |
245 | 0 | } |
246 | 0 | message = va_arg(args, int); |
247 | 0 | arg = va_arg(args, void *); |
248 | 0 | extension->message_handler(message, arg); |
249 | 0 | } |
250 | | |
251 | | |
252 | | ZEND_API void zend_extension_dispatch_message(int message, void *arg) |
253 | 0 | { |
254 | 0 | zend_llist_apply_with_arguments(&zend_extensions, (llist_apply_with_args_func_t) zend_extension_message_dispatcher, 2, message, arg); |
255 | 0 | } |
256 | | |
257 | | |
258 | | ZEND_API int zend_get_resource_handle(const char *module_name) |
259 | 1.48k | { |
260 | 1.48k | if (last_resource_number<ZEND_MAX_RESERVED_RESOURCES) { |
261 | 1.48k | zend_add_system_entropy(module_name, "zend_get_resource_handle", &last_resource_number, sizeof(int)); |
262 | 1.48k | return last_resource_number++; |
263 | 1.48k | } else { |
264 | 0 | return -1; |
265 | 0 | } |
266 | 1.48k | } |
267 | | |
268 | | ZEND_API int zend_get_op_array_extension_handle(const char *module_name) |
269 | 0 | { |
270 | 0 | int handle = zend_op_array_extension_handles++; |
271 | 0 | zend_add_system_entropy(module_name, "zend_get_op_array_extension_handle", &zend_op_array_extension_handles, sizeof(int)); |
272 | 0 | return handle; |
273 | 0 | } |
274 | | |
275 | | ZEND_API int zend_get_op_array_extension_handles(const char *module_name, int handles) |
276 | 0 | { |
277 | 0 | int handle = zend_op_array_extension_handles; |
278 | 0 | zend_op_array_extension_handles += handles; |
279 | 0 | zend_add_system_entropy(module_name, "zend_get_op_array_extension_handle", &zend_op_array_extension_handles, sizeof(int)); |
280 | 0 | return handle; |
281 | 0 | } |
282 | | |
283 | | ZEND_API zend_extension *zend_get_extension(const char *extension_name) |
284 | 0 | { |
285 | 0 | zend_llist_element *element; |
286 | |
|
287 | 0 | for (element = zend_extensions.head; element; element = element->next) { |
288 | 0 | zend_extension *extension = (zend_extension *) element->data; |
289 | |
|
290 | 0 | if (!strcmp(extension->name, extension_name)) { |
291 | 0 | return extension; |
292 | 0 | } |
293 | 0 | } |
294 | 0 | return NULL; |
295 | 0 | } |
296 | | |
297 | | typedef struct _zend_extension_persist_data { |
298 | | zend_op_array *op_array; |
299 | | size_t size; |
300 | | char *mem; |
301 | | } zend_extension_persist_data; |
302 | | |
303 | | static void zend_extension_op_array_persist_calc_handler(zend_extension *extension, zend_extension_persist_data *data) |
304 | 0 | { |
305 | 0 | if (extension->op_array_persist_calc) { |
306 | 0 | data->size += extension->op_array_persist_calc(data->op_array); |
307 | 0 | } |
308 | 0 | } |
309 | | |
310 | | static void zend_extension_op_array_persist_handler(zend_extension *extension, zend_extension_persist_data *data) |
311 | 0 | { |
312 | 0 | if (extension->op_array_persist) { |
313 | 0 | size_t size = extension->op_array_persist(data->op_array, data->mem); |
314 | 0 | if (size) { |
315 | 0 | data->mem = (void*)((char*)data->mem + size); |
316 | 0 | data->size += size; |
317 | 0 | } |
318 | 0 | } |
319 | 0 | } |
320 | | |
321 | | ZEND_API size_t zend_extensions_op_array_persist_calc(zend_op_array *op_array) |
322 | 0 | { |
323 | 0 | if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_PERSIST_CALC) { |
324 | 0 | zend_extension_persist_data data; |
325 | |
|
326 | 0 | data.op_array = op_array; |
327 | 0 | data.size = 0; |
328 | 0 | data.mem = NULL; |
329 | 0 | zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_persist_calc_handler, &data); |
330 | 0 | return data.size; |
331 | 0 | } |
332 | 0 | return 0; |
333 | 0 | } |
334 | | |
335 | | ZEND_API size_t zend_extensions_op_array_persist(zend_op_array *op_array, void *mem) |
336 | 0 | { |
337 | 0 | if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_PERSIST) { |
338 | 0 | zend_extension_persist_data data; |
339 | |
|
340 | 0 | data.op_array = op_array; |
341 | 0 | data.size = 0; |
342 | 0 | data.mem = mem; |
343 | 0 | zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_persist_handler, &data); |
344 | 0 | return data.size; |
345 | 0 | } |
346 | 0 | return 0; |
347 | 0 | } |