Coverage Report

Created: 2024-01-18 09:20

/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
}