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