Coverage Report

Created: 2022-02-19 20:30

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