Coverage Report

Created: 2025-11-16 06:23

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