Coverage Report

Created: 2026-06-02 06:40

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