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