Coverage Report

Created: 2026-09-14 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/opcache/zend_accelerator_module.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend OPcache                                                         |
4
   +----------------------------------------------------------------------+
5
   | Copyright © The PHP Group and Contributors.                          |
6
   +----------------------------------------------------------------------+
7
   | This source file is subject to the Modified BSD License that is      |
8
   | bundled with this package in the file LICENSE, and is available      |
9
   | through the World Wide Web at <https://www.php.net/license/>.        |
10
   |                                                                      |
11
   | SPDX-License-Identifier: BSD-3-Clause                                |
12
   +----------------------------------------------------------------------+
13
   | Authors: Andi Gutmans <andi@php.net>                                 |
14
   |          Zeev Suraski <zeev@php.net>                                 |
15
   |          Stanislav Malyshev <stas@zend.com>                          |
16
   |          Dmitry Stogov <dmitry@php.net>                              |
17
   +----------------------------------------------------------------------+
18
*/
19
20
#include <time.h>
21
22
#include "php.h"
23
#include "ZendAccelerator.h"
24
#include "zend_API.h"
25
#include "zend_closures.h"
26
#include "zend_extensions.h"
27
#include "zend_modules.h"
28
#include "zend_shared_alloc.h"
29
#include "zend_accelerator_blacklist.h"
30
#include "zend_file_cache.h"
31
#include "php_ini.h"
32
#include "SAPI.h"
33
#include "zend_virtual_cwd.h"
34
#include "ext/standard/info.h"
35
#include "ext/date/php_date.h"
36
#include "opcache_arginfo.h"
37
38
#ifdef HAVE_JIT
39
#include "jit/zend_jit.h"
40
#endif
41
42
0
#define STRING_NOT_NULL(s) (NULL == (s)?"":s)
43
16
#define MIN_ACCEL_FILES 200
44
16
#define MAX_ACCEL_FILES 1000000
45
/* Max value of opcache.interned_strings_buffer */
46
16
#define MAX_INTERNED_STRINGS_BUFFER_SIZE ((zend_long)MIN( \
47
16
  MIN( \
48
16
    /* STRTAB_STR_TO_POS() must not overflow (zend_string_table_pos_t) */ \
49
16
    (ZEND_STRING_TABLE_POS_MAX - sizeof(zend_string_table)) / (1024 * 1024 / ZEND_STRING_TABLE_POS_ALIGNMENT), \
50
16
    /* nTableMask must not overflow (uint32_t) */ \
51
16
    UINT32_MAX / (32 * 1024 * sizeof(zend_string_table_pos_t)) \
52
16
  ), \
53
16
  /* SHM allocation must not overflow (size_t) */ \
54
16
  (SIZE_MAX - sizeof(zend_accel_shared_globals)) / (1024 * 1024) \
55
16
))
56
#define TOKENTOSTR(X) #X
57
58
static zif_handler orig_file_exists = NULL;
59
static zif_handler orig_is_file = NULL;
60
static zif_handler orig_is_readable = NULL;
61
62
static bool validate_api_restriction(void)
63
72.6k
{
64
72.6k
  if (ZCG(accel_directives).restrict_api && *ZCG(accel_directives).restrict_api) {
65
0
    size_t len = strlen(ZCG(accel_directives).restrict_api);
66
67
0
    if (!SG(request_info).path_translated ||
68
0
        strlen(SG(request_info).path_translated) < len ||
69
0
        memcmp(SG(request_info).path_translated, ZCG(accel_directives).restrict_api, len) != 0) {
70
0
      zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " API is restricted by \"restrict_api\" configuration directive");
71
0
      return false;
72
0
    }
73
0
  }
74
72.6k
  return true;
75
72.6k
}
76
77
static ZEND_INI_MH(OnUpdateMemoryConsumption)
78
16
{
79
16
  if (accel_startup_ok) {
80
0
    if (strcmp(sapi_module.name, "fpm-fcgi") == 0) {
81
0
      zend_accel_error(ACCEL_LOG_WARNING, "opcache.memory_consumption cannot be changed when OPcache is already set up. Are you using php_admin_value[opcache.memory_consumption] in an individual pool's configuration?\n");
82
0
    } else {
83
0
      zend_accel_error(ACCEL_LOG_WARNING, "opcache.memory_consumption cannot be changed when OPcache is already set up.\n");
84
0
    }
85
0
    return FAILURE;
86
0
  }
87
88
16
  zend_long *p = ZEND_INI_GET_ADDR();
89
16
  zend_long memsize = atoi(ZSTR_VAL(new_value));
90
  /* sanity check we must use at least 8 MB */
91
16
  if (memsize < 8) {
92
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache.memory_consumption is set below the required 8MB.\n");
93
0
    return FAILURE;
94
0
  }
95
16
  if (UNEXPECTED(memsize > ZEND_LONG_MAX / (1024 * 1024))) {
96
0
    *p = ZEND_LONG_MAX & ~(1024 * 1024 - 1);
97
16
  } else {
98
16
    *p = memsize * (1024 * 1024);
99
16
  }
100
16
  return SUCCESS;
101
16
}
102
103
static ZEND_INI_MH(OnUpdateInternedStringsBuffer)
104
16
{
105
16
  if (accel_startup_ok) {
106
0
    if (strcmp(sapi_module.name, "fpm-fcgi") == 0) {
107
0
      zend_accel_error(ACCEL_LOG_WARNING, "opcache.interned_strings_buffer cannot be changed when OPcache is already set up. Are you using php_admin_value[opcache.interned_strings_buffer] in an individual pool's configuration?\n");
108
0
    } else {
109
0
      zend_accel_error(ACCEL_LOG_WARNING, "opcache.interned_strings_buffer cannot be changed when OPcache is already set up.\n");
110
0
    }
111
0
    return FAILURE;
112
0
  }
113
114
16
  zend_long *p = ZEND_INI_GET_ADDR();
115
16
  zend_long size = zend_ini_parse_quantity_warn(new_value, entry->name);
116
117
16
  if (size < 0) {
118
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache.interned_strings_buffer must be greater than or equal to 0, " ZEND_LONG_FMT " given.\n", size);
119
0
    return FAILURE;
120
0
  }
121
16
  if (size > MAX_INTERNED_STRINGS_BUFFER_SIZE) {
122
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache.interned_strings_buffer must be less than or equal to " ZEND_LONG_FMT ", " ZEND_LONG_FMT " given.\n", MAX_INTERNED_STRINGS_BUFFER_SIZE, size);
123
0
    return FAILURE;
124
0
  }
125
126
16
  *p = size;
127
128
16
  return SUCCESS;
129
16
}
130
131
static ZEND_INI_MH(OnUpdateMaxAcceleratedFiles)
132
16
{
133
16
  zend_long *p = ZEND_INI_GET_ADDR();
134
16
  zend_long size = atoi(ZSTR_VAL(new_value));
135
  /* sanity check we must use a value between MIN_ACCEL_FILES and MAX_ACCEL_FILES */
136
16
  if (size < MIN_ACCEL_FILES) {
137
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_accelerated_files is set below the required minimum (%d).\n", MIN_ACCEL_FILES);
138
0
    return FAILURE;
139
0
  }
140
16
  if (size > MAX_ACCEL_FILES) {
141
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_accelerated_files is set above the limit (%d).\n", MAX_ACCEL_FILES);
142
0
    return FAILURE;
143
0
  }
144
16
  *p = size;
145
16
  return SUCCESS;
146
16
}
147
148
static ZEND_INI_MH(OnUpdateMaxWastedPercentage)
149
16
{
150
16
  double *p = ZEND_INI_GET_ADDR();
151
16
  zend_long percentage = atoi(ZSTR_VAL(new_value));
152
153
16
  if (percentage <= 0 || percentage > 50) {
154
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_wasted_percentage must be set between 1 and 50.\n");
155
0
    return FAILURE;
156
0
  }
157
16
  *p = (double)percentage / 100.0;
158
16
  return SUCCESS;
159
16
}
160
161
static ZEND_INI_MH(OnEnable)
162
16
{
163
16
  if (stage == ZEND_INI_STAGE_STARTUP ||
164
0
      stage == ZEND_INI_STAGE_SHUTDOWN ||
165
16
      stage == ZEND_INI_STAGE_DEACTIVATE) {
166
16
    return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
167
16
  } else {
168
    /* It may be only temporarily disabled */
169
0
    bool *p = ZEND_INI_GET_ADDR();
170
0
    if (zend_ini_parse_bool(new_value)) {
171
0
      if (*p) {
172
        /* Do not warn if OPcache is enabled, as the update would be a noop anyways. */
173
0
        return SUCCESS;
174
0
      }
175
176
0
      if (stage == ZEND_INI_STAGE_ACTIVATE) {
177
0
        if (strcmp(sapi_module.name, "fpm-fcgi") == 0) {
178
0
          zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " can't be temporarily enabled. Are you using php_admin_value[opcache.enable]=1 in an individual pool's configuration?");
179
0
        } else {
180
0
          zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " can't be temporarily enabled (it may be only disabled until the end of request)");
181
0
        }
182
0
      } else {
183
0
        zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " can't be temporarily enabled (it may be only disabled until the end of request)");
184
0
      }
185
0
      return FAILURE;
186
0
    } else {
187
0
      *p = false;
188
0
      ZCG(accelerator_enabled) = false;
189
0
      return SUCCESS;
190
0
    }
191
0
  }
192
16
}
193
194
static ZEND_INI_MH(OnUpdateFileCache)
195
16
{
196
16
  if (new_value) {
197
0
    if (!ZSTR_LEN(new_value)) {
198
0
      new_value = NULL;
199
0
    }
200
0
  }
201
16
  OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
202
16
  return SUCCESS;
203
16
}
204
205
#ifdef HAVE_JIT
206
static ZEND_INI_MH(OnUpdateJit)
207
145k
{
208
145k
  if (zend_jit_config(new_value, stage) == SUCCESS) {
209
16
    return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
210
16
  }
211
145k
  return FAILURE;
212
145k
}
213
214
static ZEND_INI_MH(OnUpdateJitDebug)
215
16
{
216
16
  zend_long *p = ZEND_INI_GET_ADDR();
217
16
  zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name);
218
219
16
  if (zend_jit_debug_config(*p, val, stage) == SUCCESS) {
220
16
    *p = val;
221
16
    return SUCCESS;
222
16
  }
223
0
  return FAILURE;
224
16
}
225
226
static ZEND_INI_MH(OnUpdateCounter)
227
96
{
228
96
  zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name);
229
96
  if (val >= 0 && val < 256) {
230
96
    zend_long *p = ZEND_INI_GET_ADDR();
231
96
    *p = val;
232
96
    return SUCCESS;
233
96
  }
234
0
  zend_error(E_WARNING, "Invalid \"%s\" setting; using default value instead. Should be between 0 and 255", ZSTR_VAL(entry->name));
235
0
  return FAILURE;
236
96
}
237
238
static ZEND_INI_MH(OnUpdateUnrollC)
239
16
{
240
16
  zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name);
241
16
  if (val > 0 && val < ZEND_JIT_TRACE_MAX_CALL_DEPTH) {
242
16
    zend_long *p = ZEND_INI_GET_ADDR();
243
16
    *p = val;
244
16
    return SUCCESS;
245
16
  }
246
0
  zend_error(E_WARNING, "Invalid \"%s\" setting. Should be between 1 and %d", ZSTR_VAL(entry->name),
247
0
    ZEND_JIT_TRACE_MAX_CALL_DEPTH);
248
0
  return FAILURE;
249
16
}
250
251
static ZEND_INI_MH(OnUpdateUnrollR)
252
16
{
253
16
  zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name);
254
16
  if (val >= 0 && val < ZEND_JIT_TRACE_MAX_RET_DEPTH) {
255
16
    zend_long *p = ZEND_INI_GET_ADDR();
256
16
    *p = val;
257
16
    return SUCCESS;
258
16
  }
259
0
  zend_error(E_WARNING, "Invalid \"%s\" setting. Should be between 0 and %d", ZSTR_VAL(entry->name),
260
0
    ZEND_JIT_TRACE_MAX_RET_DEPTH);
261
0
  return FAILURE;
262
16
}
263
264
static ZEND_INI_MH(OnUpdateUnrollL)
265
16
{
266
16
  zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name);
267
16
  if (val > 0 && val < ZEND_JIT_TRACE_MAX_LOOPS_UNROLL) {
268
16
    zend_long *p = ZEND_INI_GET_ADDR();
269
16
    *p = val;
270
16
    return SUCCESS;
271
16
  }
272
0
  zend_error(E_WARNING, "Invalid \"%s\" setting. Should be between 1 and %d", ZSTR_VAL(entry->name),
273
0
    ZEND_JIT_TRACE_MAX_LOOPS_UNROLL);
274
0
  return FAILURE;
275
16
}
276
277
static ZEND_INI_MH(OnUpdateMaxTraceLength)
278
16
{
279
16
  zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name);
280
16
  if (val > 3 && val <= ZEND_JIT_TRACE_MAX_LENGTH) {
281
16
    zend_long *p = ZEND_INI_GET_ADDR();
282
16
    *p = val;
283
16
    return SUCCESS;
284
16
  }
285
0
  zend_error(E_WARNING, "Invalid \"%s\" setting. Should be between 4 and %d", ZSTR_VAL(entry->name),
286
0
    ZEND_JIT_TRACE_MAX_LENGTH);
287
0
  return FAILURE;
288
16
}
289
#endif
290
291
ZEND_INI_BEGIN()
292
  STD_PHP_INI_BOOLEAN("opcache.enable"             , "1", PHP_INI_ALL,    OnEnable,     enabled                             , zend_accel_globals, accel_globals)
293
  STD_PHP_INI_BOOLEAN("opcache.use_cwd"            , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.use_cwd            , zend_accel_globals, accel_globals)
294
  STD_PHP_INI_BOOLEAN("opcache.validate_timestamps", "1", PHP_INI_ALL   , OnUpdateBool, accel_directives.validate_timestamps, zend_accel_globals, accel_globals)
295
  STD_PHP_INI_BOOLEAN("opcache.validate_permission", "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_permission, zend_accel_globals, accel_globals)
296
#ifndef ZEND_WIN32
297
  STD_PHP_INI_BOOLEAN("opcache.validate_root"      , "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_root      , zend_accel_globals, accel_globals)
298
#endif
299
  STD_PHP_INI_BOOLEAN("opcache.dups_fix"           , "0", PHP_INI_ALL   , OnUpdateBool, accel_directives.ignore_dups        , zend_accel_globals, accel_globals)
300
  STD_PHP_INI_BOOLEAN("opcache.revalidate_path"    , "0", PHP_INI_ALL   , OnUpdateBool, accel_directives.revalidate_path    , zend_accel_globals, accel_globals)
301
302
  STD_PHP_INI_ENTRY("opcache.log_verbosity_level"   , "1"   , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.log_verbosity_level,       zend_accel_globals, accel_globals)
303
  STD_PHP_INI_ENTRY("opcache.memory_consumption"    , "128"  , PHP_INI_SYSTEM, OnUpdateMemoryConsumption,    accel_directives.memory_consumption,        zend_accel_globals, accel_globals)
304
  STD_PHP_INI_ENTRY("opcache.interned_strings_buffer", "8"  , PHP_INI_SYSTEM, OnUpdateInternedStringsBuffer,   accel_directives.interned_strings_buffer,   zend_accel_globals, accel_globals)
305
  STD_PHP_INI_ENTRY("opcache.max_accelerated_files" , "10000", PHP_INI_SYSTEM, OnUpdateMaxAcceleratedFiles,  accel_directives.max_accelerated_files,     zend_accel_globals, accel_globals)
306
  STD_PHP_INI_ENTRY("opcache.max_wasted_percentage" , "5"   , PHP_INI_SYSTEM, OnUpdateMaxWastedPercentage,   accel_directives.max_wasted_percentage,     zend_accel_globals, accel_globals)
307
  STD_PHP_INI_ENTRY("opcache.force_restart_timeout" , "180" , PHP_INI_SYSTEM, OnUpdateLong,              accel_directives.force_restart_timeout,     zend_accel_globals, accel_globals)
308
  STD_PHP_INI_ENTRY("opcache.revalidate_freq"       , "2"   , PHP_INI_ALL   , OnUpdateLong,              accel_directives.revalidate_freq,           zend_accel_globals, accel_globals)
309
  STD_PHP_INI_ENTRY("opcache.file_update_protection", "2"   , PHP_INI_ALL   , OnUpdateLong,                accel_directives.file_update_protection,    zend_accel_globals, accel_globals)
310
  STD_PHP_INI_ENTRY("opcache.preferred_memory_model", ""    , PHP_INI_SYSTEM, OnUpdateStringUnempty,       accel_directives.memory_model,              zend_accel_globals, accel_globals)
311
  STD_PHP_INI_ENTRY("opcache.blacklist_filename"    , ""    , PHP_INI_SYSTEM, OnUpdateString,              accel_directives.user_blacklist_filename,   zend_accel_globals, accel_globals)
312
  STD_PHP_INI_ENTRY("opcache.max_file_size"         , "0"   , PHP_INI_SYSTEM, OnUpdateLong,              accel_directives.max_file_size,             zend_accel_globals, accel_globals)
313
314
  STD_PHP_INI_BOOLEAN("opcache.protect_memory"        , "0"  , PHP_INI_SYSTEM, OnUpdateBool,                  accel_directives.protect_memory,            zend_accel_globals, accel_globals)
315
  STD_PHP_INI_BOOLEAN("opcache.save_comments"         , "1"  , PHP_INI_SYSTEM, OnUpdateBool,                  accel_directives.save_comments,             zend_accel_globals, accel_globals)
316
  STD_PHP_INI_BOOLEAN("opcache.record_warnings"       , "0"  , PHP_INI_SYSTEM, OnUpdateBool,                  accel_directives.record_warnings,           zend_accel_globals, accel_globals)
317
318
  STD_PHP_INI_ENTRY("opcache.optimization_level"    , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level,   zend_accel_globals, accel_globals)
319
  STD_PHP_INI_ENTRY("opcache.opt_debug_level"       , "0"      , PHP_INI_SYSTEM, OnUpdateLong,             accel_directives.opt_debug_level,            zend_accel_globals, accel_globals)
320
  STD_PHP_INI_BOOLEAN("opcache.enable_file_override"  , "0"   , PHP_INI_SYSTEM, OnUpdateBool,              accel_directives.file_override_enabled,     zend_accel_globals, accel_globals)
321
  STD_PHP_INI_BOOLEAN("opcache.enable_cli"             , "0"   , PHP_INI_SYSTEM, OnUpdateBool,              accel_directives.enable_cli,                zend_accel_globals, accel_globals)
322
  STD_PHP_INI_ENTRY("opcache.error_log"                , ""    , PHP_INI_SYSTEM, OnUpdateString,           accel_directives.error_log,                 zend_accel_globals, accel_globals)
323
  STD_PHP_INI_ENTRY("opcache.restrict_api"             , ""    , PHP_INI_SYSTEM, OnUpdateString,           accel_directives.restrict_api,              zend_accel_globals, accel_globals)
324
325
#ifndef ZEND_WIN32
326
  STD_PHP_INI_ENTRY("opcache.lockfile_path"             , "/tmp"    , PHP_INI_SYSTEM, OnUpdateString,           accel_directives.lockfile_path,              zend_accel_globals, accel_globals)
327
#else
328
  STD_PHP_INI_ENTRY("opcache.mmap_base", NULL, PHP_INI_SYSTEM,  OnUpdateString,                              accel_directives.mmap_base,                 zend_accel_globals, accel_globals)
329
#endif
330
331
  STD_PHP_INI_ENTRY("opcache.file_cache"                    , NULL  , PHP_INI_SYSTEM, OnUpdateFileCache, accel_directives.file_cache,                    zend_accel_globals, accel_globals)
332
  STD_PHP_INI_BOOLEAN("opcache.file_cache_read_only"          , "0"   , PHP_INI_SYSTEM, OnUpdateBool,    accel_directives.file_cache_read_only,          zend_accel_globals, accel_globals)
333
  STD_PHP_INI_BOOLEAN("opcache.file_cache_only"               , "0"   , PHP_INI_SYSTEM, OnUpdateBool,    accel_directives.file_cache_only,               zend_accel_globals, accel_globals)
334
  STD_PHP_INI_BOOLEAN("opcache.file_cache_consistency_checks" , "1"   , PHP_INI_SYSTEM, OnUpdateBool,    accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals)
335
#if ENABLE_FILE_CACHE_FALLBACK
336
  STD_PHP_INI_BOOLEAN("opcache.file_cache_fallback"           , "1"   , PHP_INI_SYSTEM, OnUpdateBool,    accel_directives.file_cache_fallback,           zend_accel_globals, accel_globals)
337
#endif
338
#ifdef HAVE_HUGE_CODE_PAGES
339
  STD_PHP_INI_BOOLEAN("opcache.huge_code_pages"             , "0"   , PHP_INI_SYSTEM, OnUpdateBool,      accel_directives.huge_code_pages,               zend_accel_globals, accel_globals)
340
#endif
341
  STD_PHP_INI_ENTRY("opcache.preload"                       , ""    , PHP_INI_SYSTEM, OnUpdateStringUnempty,    accel_directives.preload,                zend_accel_globals, accel_globals)
342
#ifndef ZEND_WIN32
343
  STD_PHP_INI_ENTRY("opcache.preload_user"                  , ""    , PHP_INI_SYSTEM, OnUpdateStringUnempty,    accel_directives.preload_user,           zend_accel_globals, accel_globals)
344
#endif
345
#ifdef ZEND_WIN32
346
  STD_PHP_INI_ENTRY("opcache.cache_id"                      , ""    , PHP_INI_SYSTEM, OnUpdateString,           accel_directives.cache_id,               zend_accel_globals, accel_globals)
347
#endif
348
#ifdef HAVE_JIT
349
  STD_PHP_INI_ENTRY("opcache.jit"                           , "disable",                    PHP_INI_ALL,    OnUpdateJit,      options,               zend_jit_globals, jit_globals)
350
  STD_PHP_INI_ENTRY("opcache.jit_buffer_size"               , ZEND_JIT_DEFAULT_BUFFER_SIZE, PHP_INI_SYSTEM, OnUpdateLong,     buffer_size,           zend_jit_globals, jit_globals)
351
  STD_PHP_INI_ENTRY("opcache.jit_debug"                     , "0",                          PHP_INI_ALL,    OnUpdateJitDebug, debug,                 zend_jit_globals, jit_globals)
352
  STD_PHP_INI_ENTRY("opcache.jit_bisect_limit"              , "0",                          PHP_INI_ALL,    OnUpdateLong,     bisect_limit,          zend_jit_globals, jit_globals)
353
  STD_PHP_INI_ENTRY("opcache.jit_prof_threshold"            , "0.005",                      PHP_INI_ALL,    OnUpdateReal,     prof_threshold,        zend_jit_globals, jit_globals)
354
  STD_PHP_INI_ENTRY("opcache.jit_max_root_traces"           , "1024",                       PHP_INI_SYSTEM, OnUpdateLong,     max_root_traces,       zend_jit_globals, jit_globals)
355
  STD_PHP_INI_ENTRY("opcache.jit_max_side_traces"           , "128",                        PHP_INI_SYSTEM, OnUpdateLong,     max_side_traces,       zend_jit_globals, jit_globals)
356
  STD_PHP_INI_ENTRY("opcache.jit_max_exit_counters"         , "8192",                       PHP_INI_SYSTEM, OnUpdateLong,     max_exit_counters,     zend_jit_globals, jit_globals)
357
  /* Default value should be a prime number, to reduce the chances of loop iterations being a factor of opcache.jit_hot_loop */
358
  STD_PHP_INI_ENTRY("opcache.jit_hot_loop"                  , "61",                         PHP_INI_SYSTEM, OnUpdateCounter,  hot_loop,              zend_jit_globals, jit_globals)
359
  STD_PHP_INI_ENTRY("opcache.jit_hot_func"                  , "127",                        PHP_INI_SYSTEM, OnUpdateCounter,  hot_func,              zend_jit_globals, jit_globals)
360
  STD_PHP_INI_ENTRY("opcache.jit_hot_return"                , "8",                          PHP_INI_SYSTEM, OnUpdateCounter,  hot_return,            zend_jit_globals, jit_globals)
361
  STD_PHP_INI_ENTRY("opcache.jit_hot_side_exit"             , "8",                          PHP_INI_ALL,    OnUpdateCounter,  hot_side_exit,         zend_jit_globals, jit_globals)
362
  STD_PHP_INI_ENTRY("opcache.jit_blacklist_root_trace"      , "16",                         PHP_INI_ALL,    OnUpdateCounter,  blacklist_root_trace,  zend_jit_globals, jit_globals)
363
  STD_PHP_INI_ENTRY("opcache.jit_blacklist_side_trace"      , "8",                          PHP_INI_ALL,    OnUpdateCounter,  blacklist_side_trace,  zend_jit_globals, jit_globals)
364
  STD_PHP_INI_ENTRY("opcache.jit_max_loop_unrolls"          , "8",                          PHP_INI_ALL,    OnUpdateUnrollL,  max_loop_unrolls,      zend_jit_globals, jit_globals)
365
  STD_PHP_INI_ENTRY("opcache.jit_max_recursive_calls"       , "2",                          PHP_INI_ALL,    OnUpdateUnrollC,  max_recursive_calls,   zend_jit_globals, jit_globals)
366
  STD_PHP_INI_ENTRY("opcache.jit_max_recursive_returns"     , "2",                          PHP_INI_ALL,    OnUpdateUnrollR,  max_recursive_returns, zend_jit_globals, jit_globals)
367
  STD_PHP_INI_ENTRY("opcache.jit_max_polymorphic_calls"     , "2",                          PHP_INI_ALL,    OnUpdateLong,     max_polymorphic_calls, zend_jit_globals, jit_globals)
368
    STD_PHP_INI_ENTRY("opcache.jit_max_trace_length"          , "1024",                       PHP_INI_ALL,    OnUpdateMaxTraceLength, max_trace_length, zend_jit_globals, jit_globals)
369
#endif
370
ZEND_INI_END()
371
372
static bool filename_is_in_cache(zend_string *filename)
373
0
{
374
0
  zend_string *key;
375
376
0
  key = accel_make_persistent_key(filename);
377
0
  if (key != NULL) {
378
0
    zend_persistent_script *persistent_script = zend_accel_hash_find(&ZCSG(hash), key);
379
0
    if (persistent_script && !persistent_script->corrupted) {
380
0
      if (ZCG(accel_directives).validate_timestamps) {
381
0
        zend_file_handle handle;
382
0
        bool ret;
383
384
0
        zend_stream_init_filename_ex(&handle, filename);
385
0
        ret = validate_timestamp_and_record_ex(persistent_script, &handle) == SUCCESS;
386
0
        zend_destroy_file_handle(&handle);
387
0
        return ret;
388
0
      }
389
390
0
      return true;
391
0
    }
392
0
  }
393
394
0
  return false;
395
0
}
396
397
static bool filename_is_in_file_cache(zend_string *filename)
398
0
{
399
0
  zend_string *realpath = zend_resolve_path(filename);
400
0
  if (!realpath) {
401
0
    return false;
402
0
  }
403
404
0
  zend_file_handle handle;
405
0
  zend_stream_init_filename_ex(&handle, filename);
406
0
  handle.opened_path = realpath;
407
408
0
  zend_persistent_script *result = zend_file_cache_script_load_ex(&handle, true);
409
0
  zend_destroy_file_handle(&handle);
410
411
0
  return result != NULL;
412
0
}
413
414
static bool accel_file_in_cache(INTERNAL_FUNCTION_PARAMETERS)
415
0
{
416
0
  if (ZEND_NUM_ARGS() == 1) {
417
0
    zval *zv = ZEND_CALL_ARG(execute_data , 1);
418
419
0
    if (Z_TYPE_P(zv) == IS_STRING && Z_STRLEN_P(zv) != 0) {
420
0
      return filename_is_in_cache(Z_STR_P(zv));
421
0
    }
422
0
  }
423
0
  return false;
424
0
}
425
426
static ZEND_NAMED_FUNCTION(accel_file_exists)
427
0
{
428
0
  if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
429
0
    RETURN_TRUE;
430
0
  } else {
431
0
    orig_file_exists(INTERNAL_FUNCTION_PARAM_PASSTHRU);
432
0
  }
433
0
}
434
435
static ZEND_NAMED_FUNCTION(accel_is_file)
436
0
{
437
0
  if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
438
0
    RETURN_TRUE;
439
0
  } else {
440
0
    orig_is_file(INTERNAL_FUNCTION_PARAM_PASSTHRU);
441
0
  }
442
0
}
443
444
static ZEND_NAMED_FUNCTION(accel_is_readable)
445
0
{
446
0
  if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
447
0
    RETURN_TRUE;
448
0
  } else {
449
0
    orig_is_readable(INTERNAL_FUNCTION_PARAM_PASSTHRU);
450
0
  }
451
0
}
452
453
static ZEND_MINIT_FUNCTION(zend_accelerator)
454
16
{
455
16
  start_accel_extension();
456
457
16
  return SUCCESS;
458
16
}
459
460
void zend_accel_register_ini_entries(void)
461
16
{
462
16
  zend_module_entry *module = zend_hash_str_find_ptr_lc(&module_registry,
463
16
      ACCELERATOR_PRODUCT_NAME, strlen(ACCELERATOR_PRODUCT_NAME));
464
465
16
  zend_register_ini_entries_ex(ini_entries, module->module_number, module->type);
466
16
}
467
468
void zend_accel_override_file_functions(void)
469
16
{
470
16
  zend_function *old_function;
471
16
  if (ZCG(enabled) && accel_startup_ok && ZCG(accel_directives).file_override_enabled) {
472
0
    if (file_cache_only) {
473
0
      zend_accel_error(ACCEL_LOG_WARNING, "file_override_enabled has no effect when file_cache_only is set");
474
0
      return;
475
0
    }
476
    /* override file_exists */
477
0
    if ((old_function = zend_hash_str_find_ptr(CG(function_table), "file_exists", sizeof("file_exists")-1)) != NULL) {
478
0
      orig_file_exists = old_function->internal_function.handler;
479
0
      old_function->internal_function.handler = accel_file_exists;
480
0
    }
481
0
    if ((old_function = zend_hash_str_find_ptr(CG(function_table), "is_file", sizeof("is_file")-1)) != NULL) {
482
0
      orig_is_file = old_function->internal_function.handler;
483
0
      old_function->internal_function.handler = accel_is_file;
484
0
    }
485
0
    if ((old_function = zend_hash_str_find_ptr(CG(function_table), "is_readable", sizeof("is_readable")-1)) != NULL) {
486
0
      orig_is_readable = old_function->internal_function.handler;
487
0
      old_function->internal_function.handler = accel_is_readable;
488
0
    }
489
0
  }
490
16
}
491
492
static ZEND_MSHUTDOWN_FUNCTION(zend_accelerator)
493
0
{
494
0
  (void)type; /* keep the compiler happy */
495
496
0
  UNREGISTER_INI_ENTRIES();
497
0
  accel_shutdown();
498
499
0
  return SUCCESS;
500
0
}
501
502
void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS)
503
8
{
504
8
  php_info_print_table_start();
505
506
8
  if (ZCG(accelerator_enabled) || file_cache_only) {
507
8
    php_info_print_table_row(2, "Opcode Caching", "Up and Running");
508
8
  } else {
509
0
    php_info_print_table_row(2, "Opcode Caching", "Disabled");
510
0
  }
511
8
  if (ZCG(enabled) && accel_startup_ok && ZCG(accel_directives).optimization_level) {
512
8
    php_info_print_table_row(2, "Optimization", "Enabled");
513
8
  } else {
514
0
    php_info_print_table_row(2, "Optimization", "Disabled");
515
0
  }
516
8
  if (!file_cache_only) {
517
8
    php_info_print_table_row(2, "SHM Cache", "Enabled");
518
8
  } else {
519
0
    php_info_print_table_row(2, "SHM Cache", "Disabled");
520
0
  }
521
8
  if (ZCG(accel_directives).file_cache) {
522
0
    php_info_print_table_row(2, "File Cache", "Enabled");
523
8
  } else {
524
8
    php_info_print_table_row(2, "File Cache", "Disabled");
525
8
  }
526
8
#ifdef HAVE_JIT
527
8
  if (JIT_G(enabled)) {
528
0
    if (JIT_G(on)) {
529
0
      php_info_print_table_row(2, "JIT", "On");
530
0
    } else {
531
0
      php_info_print_table_row(2, "JIT", "Off");
532
0
    }
533
8
  } else {
534
8
    php_info_print_table_row(2, "JIT", "Disabled");
535
8
  }
536
#else
537
  php_info_print_table_row(2, "JIT", "Not Available");
538
#endif
539
8
  if (file_cache_only) {
540
0
    if (!accel_startup_ok || zps_api_failure_reason) {
541
0
      php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason);
542
0
    } else {
543
0
      php_info_print_table_row(2, "Startup", "OK");
544
0
    }
545
0
  } else
546
8
  if (ZCG(enabled)) {
547
8
    if (!accel_startup_ok || zps_api_failure_reason) {
548
0
      php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason);
549
8
    } else {
550
8
      char buf[32];
551
8
      zend_string *start_time, *restart_time, *force_restart_time;
552
8
      zval *date_ISO8601 = zend_get_constant_str("DATE_ISO8601", sizeof("DATE_ISO8601")-1);
553
554
8
      php_info_print_table_row(2, "Startup", "OK");
555
8
      php_info_print_table_row(2, "Shared memory model", zend_accel_get_shared_model());
556
8
      snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(hits));
557
8
      php_info_print_table_row(2, "Cache hits", buf);
558
8
      snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
559
8
      php_info_print_table_row(2, "Cache misses", buf);
560
8
      snprintf(buf, sizeof(buf), ZEND_LONG_FMT, ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
561
8
      php_info_print_table_row(2, "Used memory", buf);
562
8
      snprintf(buf, sizeof(buf), "%zu", zend_shared_alloc_get_free_memory());
563
8
      php_info_print_table_row(2, "Free memory", buf);
564
8
      snprintf(buf, sizeof(buf), "%zu", ZSMMG(wasted_shared_memory));
565
8
      php_info_print_table_row(2, "Wasted memory", buf);
566
8
      if (ZCSG(interned_strings).start && ZCSG(interned_strings).end) {
567
8
        snprintf(buf, sizeof(buf), "%zu", (size_t)((char*)ZCSG(interned_strings).top - (char*)(accel_shared_globals + 1)));
568
8
        php_info_print_table_row(2, "Interned Strings Used memory", buf);
569
8
        snprintf(buf, sizeof(buf), "%zu", (size_t)((char*)ZCSG(interned_strings).end - (char*)ZCSG(interned_strings).top));
570
8
        php_info_print_table_row(2, "Interned Strings Free memory", buf);
571
8
      }
572
8
      snprintf(buf, sizeof(buf), "%" PRIu32, ZCSG(hash).num_direct_entries);
573
8
      php_info_print_table_row(2, "Cached scripts", buf);
574
8
      snprintf(buf, sizeof(buf), "%" PRIu32, ZCSG(hash).num_entries);
575
8
      php_info_print_table_row(2, "Cached keys", buf);
576
8
      snprintf(buf, sizeof(buf), "%" PRIu32, ZCSG(hash).max_num_entries);
577
8
      php_info_print_table_row(2, "Max keys", buf);
578
8
      snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(oom_restarts));
579
8
      php_info_print_table_row(2, "OOM restarts", buf);
580
8
      snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(hash_restarts));
581
8
      php_info_print_table_row(2, "Hash keys restarts", buf);
582
8
      snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(manual_restarts));
583
8
      php_info_print_table_row(2, "Manual restarts", buf);
584
585
8
      start_time = php_format_date(Z_STRVAL_P(date_ISO8601), Z_STRLEN_P(date_ISO8601), ZCSG(start_time), 1);
586
8
      php_info_print_table_row(2, "Start time", ZSTR_VAL(start_time));
587
8
      zend_string_release(start_time);
588
589
8
      if (ZCSG(last_restart_time)) {
590
0
        restart_time = php_format_date(Z_STRVAL_P(date_ISO8601), Z_STRLEN_P(date_ISO8601), ZCSG(last_restart_time), 1);
591
0
        php_info_print_table_row(2, "Last restart time", ZSTR_VAL(restart_time));
592
0
        zend_string_release(restart_time);
593
8
      } else {
594
8
        php_info_print_table_row(2, "Last restart time", "none");
595
8
      }
596
597
8
      if (ZCSG(force_restart_time)) {
598
0
        force_restart_time = php_format_date(Z_STRVAL_P(date_ISO8601), Z_STRLEN_P(date_ISO8601), ZCSG(force_restart_time), 1);
599
0
        php_info_print_table_row(2, "Last force restart time", ZSTR_VAL(force_restart_time));
600
0
        zend_string_release(force_restart_time);
601
8
      } else {
602
8
        php_info_print_table_row(2, "Last force restart time", "none");
603
8
      }
604
8
    }
605
8
  }
606
607
8
  php_info_print_table_end();
608
8
  DISPLAY_INI_ENTRIES();
609
8
}
610
611
zend_module_entry opcache_module_entry = {
612
  STANDARD_MODULE_HEADER,
613
  ACCELERATOR_PRODUCT_NAME,
614
  ext_functions,
615
  ZEND_MINIT(zend_accelerator),
616
  ZEND_MSHUTDOWN(zend_accelerator),
617
  ZEND_RINIT(zend_accelerator),
618
  NULL,
619
  zend_accel_info,
620
  PHP_VERSION,
621
  NO_MODULE_GLOBALS,
622
  accel_post_deactivate,
623
  STANDARD_MODULE_PROPERTIES_EX
624
};
625
626
/* {{{ Get the scripts which are accelerated by ZendAccelerator */
627
static int accelerator_get_scripts(zval *return_value)
628
41
{
629
41
  uint32_t i;
630
41
  zval persistent_script_report;
631
41
  zend_accel_hash_entry *cache_entry;
632
41
  struct tm *ta;
633
634
41
  if (!ZCG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) {
635
0
    return 0;
636
0
  }
637
638
41
  array_init(return_value);
639
665k
  for (i = 0; i<ZCSG(hash).max_num_entries; i++) {
640
673k
    for (cache_entry = ZCSG(hash).hash_table[i]; cache_entry; cache_entry = cache_entry->next) {
641
8.29k
      zend_persistent_script *script;
642
8.29k
      char *str;
643
8.29k
      size_t len;
644
645
8.29k
      if (cache_entry->indirect) continue;
646
647
8.29k
      script = (zend_persistent_script *)cache_entry->data;
648
649
8.29k
      array_init(&persistent_script_report);
650
8.29k
      add_assoc_str(&persistent_script_report, "full_path", zend_string_dup(script->script.filename, 0));
651
8.29k
      add_assoc_long(&persistent_script_report, "hits", script->dynamic_members.hits);
652
8.29k
      add_assoc_long(&persistent_script_report, "memory_consumption", script->dynamic_members.memory_consumption);
653
8.29k
      ta = localtime(&script->dynamic_members.last_used);
654
8.29k
      str = asctime(ta);
655
8.29k
      len = strlen(str);
656
8.29k
      if (len > 0 && str[len - 1] == '\n') len--;
657
8.29k
      add_assoc_stringl(&persistent_script_report, "last_used", str, len);
658
8.29k
      add_assoc_long(&persistent_script_report, "last_used_timestamp", script->dynamic_members.last_used);
659
8.29k
      if (ZCG(accel_directives).validate_timestamps) {
660
0
        add_assoc_long(&persistent_script_report, "timestamp", (zend_long)script->timestamp);
661
0
      }
662
663
8.29k
      add_assoc_long(&persistent_script_report, "revalidate", (zend_long)script->dynamic_members.revalidate);
664
665
8.29k
      zend_hash_update(Z_ARRVAL_P(return_value), cache_entry->key, &persistent_script_report);
666
8.29k
    }
667
665k
  }
668
41
  accelerator_shm_read_unlock();
669
670
41
  return 1;
671
41
}
672
673
/* {{{ Obtain statistics information regarding code acceleration */
674
ZEND_FUNCTION(opcache_get_status)
675
41
{
676
41
  zend_long reqs;
677
41
  zval memory_usage, statistics, scripts;
678
41
  bool fetch_scripts = true;
679
680
41
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &fetch_scripts) == FAILURE) {
681
0
    RETURN_THROWS();
682
0
  }
683
684
41
  if (!validate_api_restriction()) {
685
0
    RETURN_FALSE;
686
0
  }
687
688
41
  if (!accel_startup_ok) {
689
0
    RETURN_FALSE;
690
0
  }
691
692
41
  array_init(return_value);
693
694
  /* Trivia */
695
41
  add_assoc_bool(return_value, "opcache_enabled", ZCG(accelerator_enabled));
696
697
41
  if (ZCG(accel_directives).file_cache) {
698
0
    add_assoc_string(return_value, "file_cache", ZCG(accel_directives).file_cache);
699
0
  }
700
41
  if (file_cache_only) {
701
0
    add_assoc_bool(return_value, "file_cache_only", 1);
702
0
    return;
703
0
  }
704
705
41
  add_assoc_bool(return_value, "cache_full", ZSMMG(memory_exhausted));
706
41
  add_assoc_bool(return_value, "restart_pending", ZCSG(restart_pending));
707
41
  add_assoc_bool(return_value, "restart_in_progress", ZCSG(restart_in_progress));
708
709
  /* Memory usage statistics */
710
41
  array_init(&memory_usage);
711
41
  add_assoc_long(&memory_usage, "used_memory", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
712
41
  add_assoc_long(&memory_usage, "free_memory", zend_shared_alloc_get_free_memory());
713
41
  add_assoc_long(&memory_usage, "wasted_memory", ZSMMG(wasted_shared_memory));
714
41
  add_assoc_double(&memory_usage, "current_wasted_percentage", (((double) ZSMMG(wasted_shared_memory))/ZCG(accel_directives).memory_consumption)*100.0);
715
41
  add_assoc_zval(return_value, "memory_usage", &memory_usage);
716
717
41
  if (ZCSG(interned_strings).start && ZCSG(interned_strings).end) {
718
41
    zval interned_strings_usage;
719
720
41
    array_init(&interned_strings_usage);
721
41
    add_assoc_long(&interned_strings_usage, "buffer_size", (char*)ZCSG(interned_strings).end - (char*)(accel_shared_globals + 1));
722
41
    add_assoc_long(&interned_strings_usage, "used_memory", (char*)ZCSG(interned_strings).top - (char*)(accel_shared_globals + 1));
723
41
    add_assoc_long(&interned_strings_usage, "free_memory", (char*)ZCSG(interned_strings).end - (char*)ZCSG(interned_strings).top);
724
41
    add_assoc_long(&interned_strings_usage, "number_of_strings", ZCSG(interned_strings).nNumOfElements);
725
41
    add_assoc_zval(return_value, "interned_strings_usage", &interned_strings_usage);
726
41
  }
727
728
  /* Accelerator statistics */
729
41
  array_init(&statistics);
730
41
  add_assoc_long(&statistics, "num_cached_scripts", ZCSG(hash).num_direct_entries);
731
41
  add_assoc_long(&statistics, "num_cached_keys",    ZCSG(hash).num_entries);
732
41
  add_assoc_long(&statistics, "max_cached_keys",    ZCSG(hash).max_num_entries);
733
41
  add_assoc_long(&statistics, "hits", (zend_long)ZCSG(hits));
734
41
  add_assoc_long(&statistics, "start_time", ZCSG(start_time));
735
41
  add_assoc_long(&statistics, "last_restart_time", ZCSG(last_restart_time));
736
41
  add_assoc_long(&statistics, "oom_restarts", ZCSG(oom_restarts));
737
41
  add_assoc_long(&statistics, "hash_restarts", ZCSG(hash_restarts));
738
41
  add_assoc_long(&statistics, "manual_restarts", ZCSG(manual_restarts));
739
41
  add_assoc_long(&statistics, "misses", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
740
41
  add_assoc_long(&statistics, "blacklist_misses", ZCSG(blacklist_misses));
741
41
  reqs = ZCSG(hits)+ZCSG(misses);
742
41
  add_assoc_double(&statistics, "blacklist_miss_ratio", reqs?(((double) ZCSG(blacklist_misses))/reqs)*100.0:0);
743
41
  add_assoc_double(&statistics, "opcache_hit_rate", reqs?(((double) ZCSG(hits))/reqs)*100.0:0);
744
41
  add_assoc_zval(return_value, "opcache_statistics", &statistics);
745
746
41
  if (ZCSG(preload_script)) {
747
0
    array_init(&statistics);
748
749
0
    add_assoc_long(&statistics, "memory_consumption", ZCSG(preload_script)->dynamic_members.memory_consumption);
750
751
0
    if (zend_hash_num_elements(&ZCSG(preload_script)->script.function_table)) {
752
0
      zend_op_array *op_array;
753
754
0
      array_init(&scripts);
755
0
      ZEND_HASH_MAP_FOREACH_PTR(&ZCSG(preload_script)->script.function_table, op_array) {
756
0
        add_next_index_str(&scripts, op_array->function_name);
757
0
      } ZEND_HASH_FOREACH_END();
758
0
      add_assoc_zval(&statistics, "functions", &scripts);
759
0
    }
760
761
0
    if (zend_hash_num_elements(&ZCSG(preload_script)->script.class_table)) {
762
0
      zval *zv;
763
0
      zend_string *key;
764
765
0
      array_init(&scripts);
766
0
      ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(&ZCSG(preload_script)->script.class_table, key, zv) {
767
0
        if (Z_TYPE_P(zv) == IS_ALIAS_PTR) {
768
0
          add_next_index_str(&scripts, key);
769
0
        } else {
770
0
          add_next_index_str(&scripts, Z_CE_P(zv)->name);
771
0
        }
772
0
      } ZEND_HASH_FOREACH_END();
773
0
      add_assoc_zval(&statistics, "classes", &scripts);
774
0
    }
775
776
0
    if (ZCSG(saved_scripts)) {
777
0
      zend_persistent_script **p = ZCSG(saved_scripts);
778
779
0
      array_init(&scripts);
780
0
      while (*p) {
781
0
        add_next_index_str(&scripts, (*p)->script.filename);
782
0
        p++;
783
0
      }
784
0
      add_assoc_zval(&statistics, "scripts", &scripts);
785
0
    }
786
0
    add_assoc_zval(return_value, "preload_statistics", &statistics);
787
0
  }
788
789
41
  if (fetch_scripts) {
790
    /* accelerated scripts */
791
41
    if (accelerator_get_scripts(&scripts)) {
792
41
      add_assoc_zval(return_value, "scripts", &scripts);
793
41
    }
794
41
  }
795
41
#ifdef HAVE_JIT
796
41
  zend_jit_status(return_value);
797
41
#endif
798
41
}
799
800
static int add_blacklist_path(zend_blacklist_entry *p, zval *return_value)
801
0
{
802
0
  add_next_index_stringl(return_value, p->path, p->path_length);
803
0
  return 0;
804
0
}
805
806
/* {{{ Obtain configuration information */
807
ZEND_FUNCTION(opcache_get_configuration)
808
0
{
809
0
  zval directives, version, blacklist;
810
811
0
  ZEND_PARSE_PARAMETERS_NONE();
812
813
0
  if (!validate_api_restriction()) {
814
0
    RETURN_FALSE;
815
0
  }
816
817
0
  array_init(return_value);
818
819
  /* directives */
820
0
  array_init(&directives);
821
0
  add_assoc_bool(&directives, "opcache.enable",              ZCG(enabled));
822
0
  add_assoc_bool(&directives, "opcache.enable_cli",          ZCG(accel_directives).enable_cli);
823
0
  add_assoc_bool(&directives, "opcache.use_cwd",             ZCG(accel_directives).use_cwd);
824
0
  add_assoc_bool(&directives, "opcache.validate_timestamps", ZCG(accel_directives).validate_timestamps);
825
0
  add_assoc_bool(&directives, "opcache.validate_permission", ZCG(accel_directives).validate_permission);
826
0
#ifndef ZEND_WIN32
827
0
  add_assoc_bool(&directives, "opcache.validate_root",       ZCG(accel_directives).validate_root);
828
0
#endif
829
0
  add_assoc_bool(&directives, "opcache.dups_fix",            ZCG(accel_directives).ignore_dups);
830
0
  add_assoc_bool(&directives, "opcache.revalidate_path",     ZCG(accel_directives).revalidate_path);
831
832
0
  add_assoc_long(&directives,   "opcache.log_verbosity_level",    ZCG(accel_directives).log_verbosity_level);
833
0
  add_assoc_long(&directives,  "opcache.memory_consumption",     ZCG(accel_directives).memory_consumption);
834
0
  add_assoc_long(&directives,  "opcache.interned_strings_buffer",ZCG(accel_directives).interned_strings_buffer);
835
0
  add_assoc_long(&directives,    "opcache.max_accelerated_files",  ZCG(accel_directives).max_accelerated_files);
836
0
  add_assoc_double(&directives, "opcache.max_wasted_percentage",  ZCG(accel_directives).max_wasted_percentage);
837
0
  add_assoc_long(&directives,    "opcache.force_restart_timeout",  ZCG(accel_directives).force_restart_timeout);
838
0
  add_assoc_long(&directives,    "opcache.revalidate_freq",        ZCG(accel_directives).revalidate_freq);
839
0
  add_assoc_string(&directives, "opcache.preferred_memory_model", STRING_NOT_NULL(ZCG(accel_directives).memory_model));
840
0
  add_assoc_string(&directives, "opcache.blacklist_filename",     STRING_NOT_NULL(ZCG(accel_directives).user_blacklist_filename));
841
0
  add_assoc_long(&directives,   "opcache.max_file_size",          ZCG(accel_directives).max_file_size);
842
0
  add_assoc_string(&directives, "opcache.error_log",              STRING_NOT_NULL(ZCG(accel_directives).error_log));
843
844
0
  add_assoc_bool(&directives,   "opcache.protect_memory",         ZCG(accel_directives).protect_memory);
845
0
  add_assoc_bool(&directives,   "opcache.save_comments",          ZCG(accel_directives).save_comments);
846
0
  add_assoc_bool(&directives,   "opcache.record_warnings",        ZCG(accel_directives).record_warnings);
847
0
  add_assoc_bool(&directives,   "opcache.enable_file_override",   ZCG(accel_directives).file_override_enabled);
848
0
  add_assoc_long(&directives,    "opcache.optimization_level",     ZCG(accel_directives).optimization_level);
849
850
0
#ifndef ZEND_WIN32
851
0
  add_assoc_string(&directives, "opcache.lockfile_path",          STRING_NOT_NULL(ZCG(accel_directives).lockfile_path));
852
#else
853
  add_assoc_string(&directives, "opcache.mmap_base",              STRING_NOT_NULL(ZCG(accel_directives).mmap_base));
854
#endif
855
856
0
  add_assoc_string(&directives, "opcache.file_cache",                    ZCG(accel_directives).file_cache ? ZCG(accel_directives).file_cache : "");
857
0
  add_assoc_bool(&directives,   "opcache.file_cache_read_only",          ZCG(accel_directives).file_cache_read_only);
858
0
  add_assoc_bool(&directives,   "opcache.file_cache_only",               ZCG(accel_directives).file_cache_only);
859
0
  add_assoc_bool(&directives,   "opcache.file_cache_consistency_checks", ZCG(accel_directives).file_cache_consistency_checks);
860
#if ENABLE_FILE_CACHE_FALLBACK
861
  add_assoc_bool(&directives,   "opcache.file_cache_fallback",           ZCG(accel_directives).file_cache_fallback);
862
#endif
863
864
0
  add_assoc_long(&directives,   "opcache.file_update_protection",  ZCG(accel_directives).file_update_protection);
865
0
  add_assoc_long(&directives,   "opcache.opt_debug_level",         ZCG(accel_directives).opt_debug_level);
866
0
  add_assoc_string(&directives, "opcache.restrict_api",            STRING_NOT_NULL(ZCG(accel_directives).restrict_api));
867
0
#ifdef HAVE_HUGE_CODE_PAGES
868
0
  add_assoc_bool(&directives,   "opcache.huge_code_pages",         ZCG(accel_directives).huge_code_pages);
869
0
#endif
870
0
  add_assoc_string(&directives, "opcache.preload", STRING_NOT_NULL(ZCG(accel_directives).preload));
871
0
#ifndef ZEND_WIN32
872
0
  add_assoc_string(&directives, "opcache.preload_user", STRING_NOT_NULL(ZCG(accel_directives).preload_user));
873
0
#endif
874
#ifdef ZEND_WIN32
875
  add_assoc_string(&directives, "opcache.cache_id", STRING_NOT_NULL(ZCG(accel_directives).cache_id));
876
#endif
877
0
#ifdef HAVE_JIT
878
0
  add_assoc_string(&directives, "opcache.jit", JIT_G(options));
879
0
  add_assoc_long(&directives,   "opcache.jit_buffer_size", JIT_G(buffer_size));
880
0
  add_assoc_long(&directives,   "opcache.jit_debug", JIT_G(debug));
881
0
  add_assoc_long(&directives,   "opcache.jit_bisect_limit", JIT_G(bisect_limit));
882
0
  add_assoc_long(&directives,   "opcache.jit_blacklist_root_trace", JIT_G(blacklist_root_trace));
883
0
  add_assoc_long(&directives,   "opcache.jit_blacklist_side_trace", JIT_G(blacklist_side_trace));
884
0
  add_assoc_long(&directives,   "opcache.jit_hot_func", JIT_G(hot_func));
885
0
  add_assoc_long(&directives,   "opcache.jit_hot_loop", JIT_G(hot_loop));
886
0
  add_assoc_long(&directives,   "opcache.jit_hot_return", JIT_G(hot_return));
887
0
  add_assoc_long(&directives,   "opcache.jit_hot_side_exit", JIT_G(hot_side_exit));
888
0
  add_assoc_long(&directives,   "opcache.jit_max_exit_counters", JIT_G(max_exit_counters));
889
0
  add_assoc_long(&directives,   "opcache.jit_max_loop_unrolls", JIT_G(max_loop_unrolls));
890
0
  add_assoc_long(&directives,   "opcache.jit_max_polymorphic_calls", JIT_G(max_polymorphic_calls));
891
0
  add_assoc_long(&directives,   "opcache.jit_max_recursive_calls", JIT_G(max_recursive_calls));
892
0
  add_assoc_long(&directives,   "opcache.jit_max_recursive_returns", JIT_G(max_recursive_returns));
893
0
  add_assoc_long(&directives,   "opcache.jit_max_root_traces", JIT_G(max_root_traces));
894
0
  add_assoc_long(&directives,   "opcache.jit_max_side_traces", JIT_G(max_side_traces));
895
0
  add_assoc_double(&directives, "opcache.jit_prof_threshold", JIT_G(prof_threshold));
896
0
  add_assoc_long(&directives,   "opcache.jit_max_trace_length", JIT_G(max_trace_length));
897
0
#endif
898
899
0
  add_assoc_zval(return_value, "directives", &directives);
900
901
  /*version */
902
0
  array_init(&version);
903
0
  add_assoc_string(&version, "version", PHP_VERSION);
904
0
  add_assoc_string(&version, "opcache_product_name", ACCELERATOR_PRODUCT_NAME);
905
0
  add_assoc_zval(return_value, "version", &version);
906
907
  /* blacklist */
908
0
  array_init(&blacklist);
909
0
  zend_accel_blacklist_apply(&accel_blacklist, add_blacklist_path, &blacklist);
910
0
  add_assoc_zval(return_value, "blacklist", &blacklist);
911
0
}
912
913
/* {{{ Request that the contents of the opcode cache to be reset */
914
ZEND_FUNCTION(opcache_reset)
915
0
{
916
0
  ZEND_PARSE_PARAMETERS_NONE();
917
918
0
  if (!validate_api_restriction()) {
919
0
    RETURN_FALSE;
920
0
  }
921
922
0
  if ((!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled))
923
#if ENABLE_FILE_CACHE_FALLBACK
924
  && !fallback_process
925
#endif
926
0
  ) {
927
0
    RETURN_FALSE;
928
0
  }
929
930
  /* exclusive lock */
931
0
  zend_shared_alloc_lock();
932
0
  zend_accel_schedule_restart(ACCEL_RESTART_USER);
933
0
  zend_shared_alloc_unlock();
934
0
  RETURN_TRUE;
935
0
}
936
937
/* {{{ Invalidates cached script (in necessary or forced) */
938
ZEND_FUNCTION(opcache_invalidate)
939
72.5k
{
940
72.5k
  zend_string *script_name;
941
72.5k
  bool force = false;
942
943
72.5k
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|b", &script_name, &force) == FAILURE) {
944
0
    RETURN_THROWS();
945
0
  }
946
947
72.5k
  if (!validate_api_restriction()) {
948
0
    RETURN_FALSE;
949
0
  }
950
951
72.5k
  RETURN_BOOL(zend_accel_invalidate(script_name, force) == SUCCESS);
952
72.5k
}
953
954
/* {{{ Prevents JIT on function. Call it before the first invocation of the given function. */
955
ZEND_FUNCTION(opcache_jit_blacklist)
956
12
{
957
12
  zval *closure;
958
959
12
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &closure, zend_ce_closure) == FAILURE) {
960
0
    RETURN_THROWS();
961
0
  }
962
963
12
#ifdef HAVE_JIT
964
12
  const zend_function *func = zend_get_closure_method_def(Z_OBJ_P(closure));
965
12
  if (ZEND_USER_CODE(func->type)) {
966
12
    zend_jit_blacklist_function((zend_op_array *)&func->op_array);
967
12
  }
968
12
#endif
969
12
}
970
971
ZEND_FUNCTION(opcache_compile_file)
972
0
{
973
0
  zend_string *script_name;
974
0
  zend_file_handle handle;
975
0
  zend_op_array *op_array = NULL;
976
0
  zend_execute_data *orig_execute_data = NULL;
977
0
  uint32_t orig_compiler_options;
978
979
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &script_name) == FAILURE) {
980
0
    RETURN_THROWS();
981
0
  }
982
983
0
  if (!accel_startup_ok) {
984
0
    zend_error(E_NOTICE, ACCELERATOR_PRODUCT_NAME " has not been properly started, can't compile file");
985
0
    RETURN_FALSE;
986
0
  }
987
988
0
  zend_stream_init_filename_ex(&handle, script_name);
989
990
0
  orig_execute_data = EG(current_execute_data);
991
0
  orig_compiler_options = CG(compiler_options);
992
0
  CG(compiler_options) |= ZEND_COMPILE_WITHOUT_EXECUTION;
993
994
0
  if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
995
    /* During preloading, a failure in opcache_compile_file() should result in an overall
996
     * preloading failure. Otherwise we may include partially compiled files in the preload
997
     * state. */
998
0
    op_array = persistent_compile_file(&handle, ZEND_INCLUDE);
999
0
  } else {
1000
0
    zend_try {
1001
0
      op_array = persistent_compile_file(&handle, ZEND_INCLUDE);
1002
0
    } zend_catch {
1003
0
      EG(current_execute_data) = orig_execute_data;
1004
0
      zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " could not compile file %s", ZSTR_VAL(handle.filename));
1005
0
    } zend_end_try();
1006
0
  }
1007
1008
0
  CG(compiler_options) = orig_compiler_options;
1009
1010
0
  if(op_array != NULL) {
1011
0
    destroy_op_array(op_array);
1012
0
    efree(op_array);
1013
0
    RETVAL_TRUE;
1014
0
  } else {
1015
0
    RETVAL_FALSE;
1016
0
  }
1017
0
  zend_destroy_file_handle(&handle);
1018
0
}
1019
1020
/* {{{ Return true if the script is cached in OPCache, false if it is not cached or if OPCache is not running. */
1021
ZEND_FUNCTION(opcache_is_script_cached)
1022
0
{
1023
0
  zend_string *script_name;
1024
1025
0
  ZEND_PARSE_PARAMETERS_START(1, 1)
1026
0
    Z_PARAM_STR(script_name)
1027
0
  ZEND_PARSE_PARAMETERS_END();
1028
1029
0
  if (!validate_api_restriction()) {
1030
0
    RETURN_FALSE;
1031
0
  }
1032
1033
0
  if (!ZCG(accelerator_enabled)) {
1034
0
    RETURN_FALSE;
1035
0
  }
1036
1037
0
  RETURN_BOOL(filename_is_in_cache(script_name));
1038
0
}
1039
1040
/* {{{ Return true if the script is cached in OPCache file cache, false if it is not cached or if OPCache is not running. */
1041
ZEND_FUNCTION(opcache_is_script_cached_in_file_cache)
1042
0
{
1043
0
  zend_string *script_name;
1044
1045
0
  ZEND_PARSE_PARAMETERS_START(1, 1)
1046
0
    Z_PARAM_STR(script_name)
1047
0
  ZEND_PARSE_PARAMETERS_END();
1048
1049
0
  if (!validate_api_restriction()) {
1050
0
    RETURN_FALSE;
1051
0
  }
1052
1053
0
  if (!(ZCG(accelerator_enabled) || ZCG(accel_directives).file_cache_only)) {
1054
0
    RETURN_FALSE;
1055
0
  }
1056
1057
0
  if (!ZCG(accel_directives).file_cache) {
1058
0
    RETURN_FALSE;
1059
0
  }
1060
1061
0
  RETURN_BOOL(filename_is_in_file_cache(script_name));
1062
0
}