Coverage Report

Created: 2025-09-27 06:26

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