xref: /php-src/ext/opcache/ZendAccelerator.c (revision da81b5c8)
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 "main/php.h"
23 #include "main/php_globals.h"
24 #include "zend.h"
25 #include "zend_extensions.h"
26 #include "zend_compile.h"
27 #include "ZendAccelerator.h"
28 #include "zend_persist.h"
29 #include "zend_shared_alloc.h"
30 #include "zend_accelerator_module.h"
31 #include "zend_accelerator_blacklist.h"
32 #include "zend_list.h"
33 #include "zend_execute.h"
34 #include "zend_vm.h"
35 #include "zend_inheritance.h"
36 #include "zend_exceptions.h"
37 #include "zend_mmap.h"
38 #include "zend_observer.h"
39 #include "main/php_main.h"
40 #include "main/SAPI.h"
41 #include "main/php_streams.h"
42 #include "main/php_open_temporary_file.h"
43 #include "zend_API.h"
44 #include "zend_ini.h"
45 #include "zend_virtual_cwd.h"
46 #include "zend_accelerator_util_funcs.h"
47 #include "zend_accelerator_hash.h"
48 #include "zend_file_cache.h"
49 #include "ext/pcre/php_pcre.h"
50 #include "ext/standard/basic_functions.h"
51 
52 #ifdef ZEND_WIN32
53 # include "ext/hash/php_hash.h"
54 # include "ext/standard/md5.h"
55 #endif
56 
57 #ifdef HAVE_JIT
58 # include "jit/zend_jit.h"
59 #endif
60 
61 #ifndef ZEND_WIN32
62 #include  <netdb.h>
63 #endif
64 
65 #ifdef ZEND_WIN32
66 typedef int uid_t;
67 typedef int gid_t;
68 #include <io.h>
69 #include <lmcons.h>
70 #endif
71 
72 #ifndef ZEND_WIN32
73 # include <sys/time.h>
74 #else
75 # include <process.h>
76 #endif
77 
78 #ifdef HAVE_UNISTD_H
79 # include <unistd.h>
80 #endif
81 #include <fcntl.h>
82 #include <signal.h>
83 #include <time.h>
84 
85 #ifndef ZEND_WIN32
86 # include <sys/types.h>
87 # include <sys/wait.h>
88 # include <sys/ipc.h>
89 # include <pwd.h>
90 # include <grp.h>
91 #endif
92 
93 #include <sys/stat.h>
94 #include <errno.h>
95 
96 #ifdef __AVX__
97 #include <immintrin.h>
98 #endif
99 
100 ZEND_EXTENSION();
101 
102 #ifndef ZTS
103 zend_accel_globals accel_globals;
104 #else
105 int accel_globals_id;
106 #if defined(COMPILE_DL_OPCACHE)
107 ZEND_TSRMLS_CACHE_DEFINE()
108 #endif
109 #endif
110 
111 /* Points to the structure shared across all PHP processes */
112 zend_accel_shared_globals *accel_shared_globals = NULL;
113 
114 /* true globals, no need for thread safety */
115 #ifdef ZEND_WIN32
116 char accel_uname_id[32];
117 #endif
118 bool accel_startup_ok = false;
119 static const char *zps_failure_reason = NULL;
120 const char *zps_api_failure_reason = NULL;
121 bool file_cache_only = false;  /* process uses file cache only */
122 #if ENABLE_FILE_CACHE_FALLBACK
123 bool fallback_process = false; /* process uses file cache fallback */
124 #endif
125 
126 static zend_op_array *(*accelerator_orig_compile_file)(zend_file_handle *file_handle, int type);
127 static zend_class_entry* (*accelerator_orig_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces);
128 static zend_class_entry* (*accelerator_orig_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies);
129 static zend_result (*accelerator_orig_zend_stream_open_function)(zend_file_handle *handle );
130 static zend_string *(*accelerator_orig_zend_resolve_path)(zend_string *filename);
131 static zif_handler orig_chdir = NULL;
132 static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL;
133 static zend_result (*orig_post_startup_cb)(void);
134 
135 static zend_result accel_post_startup(void);
136 static zend_result accel_finish_startup(void);
137 
138 static void preload_shutdown(void);
139 static void preload_activate(void);
140 static void preload_restart(void);
141 
142 #ifdef ZEND_WIN32
143 # define INCREMENT(v) InterlockedIncrement64(&ZCSG(v))
144 # define DECREMENT(v) InterlockedDecrement64(&ZCSG(v))
145 # define LOCKVAL(v)   (ZCSG(v))
146 #endif
147 
148 /**
149  * Clear AVX/SSE2-aligned memory.
150  */
bzero_aligned(void * mem,size_t size)151 static void bzero_aligned(void *mem, size_t size)
152 {
153 #if defined(__x86_64__)
154 	memset(mem, 0, size);
155 #elif defined(__AVX__)
156 	char *p = (char*)mem;
157 	char *end = p + size;
158 	__m256i ymm0 = _mm256_setzero_si256();
159 
160 	while (p < end) {
161 		_mm256_store_si256((__m256i*)p, ymm0);
162 		_mm256_store_si256((__m256i*)(p+32), ymm0);
163 		p += 64;
164 	}
165 #elif defined(__SSE2__)
166 	char *p = (char*)mem;
167 	char *end = p + size;
168 	__m128i xmm0 = _mm_setzero_si128();
169 
170 	while (p < end) {
171 		_mm_store_si128((__m128i*)p, xmm0);
172 		_mm_store_si128((__m128i*)(p+16), xmm0);
173 		_mm_store_si128((__m128i*)(p+32), xmm0);
174 		_mm_store_si128((__m128i*)(p+48), xmm0);
175 		p += 64;
176 	}
177 #else
178 	memset(mem, 0, size);
179 #endif
180 }
181 
182 #ifdef ZEND_WIN32
zend_accel_get_time(void)183 static time_t zend_accel_get_time(void)
184 {
185 	FILETIME now;
186 	GetSystemTimeAsFileTime(&now);
187 
188 	return (time_t) ((((((__int64)now.dwHighDateTime) << 32)|now.dwLowDateTime) - 116444736000000000L)/10000000);
189 }
190 #else
191 # define zend_accel_get_time() time(NULL)
192 #endif
193 
is_cacheable_stream_path(const char * filename)194 static inline bool is_cacheable_stream_path(const char *filename)
195 {
196 	return memcmp(filename, "file://", sizeof("file://") - 1) == 0 ||
197 	       memcmp(filename, "phar://", sizeof("phar://") - 1) == 0;
198 }
199 
200 /* O+ overrides PHP chdir() function and remembers the current working directory
201  * in ZCG(cwd) and ZCG(cwd_len). Later accel_getcwd() can use stored value and
202  * avoid getcwd() call.
203  */
ZEND_FUNCTION(accel_chdir)204 static ZEND_FUNCTION(accel_chdir)
205 {
206 	char cwd[MAXPATHLEN];
207 
208 	orig_chdir(INTERNAL_FUNCTION_PARAM_PASSTHRU);
209 	if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
210 		if (ZCG(cwd)) {
211 			zend_string_release_ex(ZCG(cwd), 0);
212 		}
213 		ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
214 	} else {
215 		if (ZCG(cwd)) {
216 			zend_string_release_ex(ZCG(cwd), 0);
217 			ZCG(cwd) = NULL;
218 		}
219 	}
220 	ZCG(cwd_key_len) = 0;
221 	ZCG(cwd_check) = true;
222 }
223 
accel_getcwd(void)224 static inline zend_string* accel_getcwd(void)
225 {
226 	if (ZCG(cwd)) {
227 		return ZCG(cwd);
228 	} else {
229 		char cwd[MAXPATHLEN + 1];
230 
231 		if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
232 			return NULL;
233 		}
234 		ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
235 		ZCG(cwd_key_len) = 0;
236 		ZCG(cwd_check) = true;
237 		return ZCG(cwd);
238 	}
239 }
240 
zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason)241 void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason)
242 {
243 	if ((((double) ZSMMG(wasted_shared_memory)) / ZCG(accel_directives).memory_consumption) >= ZCG(accel_directives).max_wasted_percentage) {
244 		zend_accel_schedule_restart(reason);
245 	}
246 }
247 
248 /* O+ tracks changes of "include_path" directive. It stores all the requested
249  * values in ZCG(include_paths) shared hash table, current value in
250  * ZCG(include_path)/ZCG(include_path_len) and one letter "path key" in
251  * ZCG(include_path_key).
252  */
ZEND_INI_MH(accel_include_path_on_modify)253 static ZEND_INI_MH(accel_include_path_on_modify)
254 {
255 	int ret = orig_include_path_on_modify(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
256 
257 	if (ret == SUCCESS) {
258 		ZCG(include_path) = new_value;
259 		ZCG(include_path_key_len) = 0;
260 		ZCG(include_path_check) = true;
261 	}
262 	return ret;
263 }
264 
accel_restart_enter(void)265 static inline void accel_restart_enter(void)
266 {
267 #ifdef ZEND_WIN32
268 	INCREMENT(restart_in);
269 #else
270 	struct flock restart_in_progress;
271 
272 	restart_in_progress.l_type = F_WRLCK;
273 	restart_in_progress.l_whence = SEEK_SET;
274 	restart_in_progress.l_start = 2;
275 	restart_in_progress.l_len = 1;
276 
277 	if (fcntl(lock_file, F_SETLK, &restart_in_progress) == -1) {
278 		zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(+1):  %s (%d)", strerror(errno), errno);
279 	}
280 #endif
281 	ZCSG(restart_in_progress) = true;
282 }
283 
accel_restart_leave(void)284 static inline void accel_restart_leave(void)
285 {
286 #ifdef ZEND_WIN32
287 	ZCSG(restart_in_progress) = false;
288 	DECREMENT(restart_in);
289 #else
290 	struct flock restart_finished;
291 
292 	restart_finished.l_type = F_UNLCK;
293 	restart_finished.l_whence = SEEK_SET;
294 	restart_finished.l_start = 2;
295 	restart_finished.l_len = 1;
296 
297 	ZCSG(restart_in_progress) = false;
298 	if (fcntl(lock_file, F_SETLK, &restart_finished) == -1) {
299 		zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(-1):  %s (%d)", strerror(errno), errno);
300 	}
301 #endif
302 }
303 
accel_restart_is_active(void)304 static inline int accel_restart_is_active(void)
305 {
306 	if (ZCSG(restart_in_progress)) {
307 #ifndef ZEND_WIN32
308 		struct flock restart_check;
309 
310 		restart_check.l_type = F_WRLCK;
311 		restart_check.l_whence = SEEK_SET;
312 		restart_check.l_start = 2;
313 		restart_check.l_len = 1;
314 
315 		if (fcntl(lock_file, F_GETLK, &restart_check) == -1) {
316 			zend_accel_error(ACCEL_LOG_DEBUG, "RestartC:  %s (%d)", strerror(errno), errno);
317 			return FAILURE;
318 		}
319 		if (restart_check.l_type == F_UNLCK) {
320 			ZCSG(restart_in_progress) = false;
321 			return 0;
322 		} else {
323 			return 1;
324 		}
325 #else
326 		return LOCKVAL(restart_in) != 0;
327 #endif
328 	}
329 	return 0;
330 }
331 
332 /* Creates a read lock for SHM access */
accel_activate_add(void)333 static inline zend_result accel_activate_add(void)
334 {
335 #ifdef ZEND_WIN32
336 	SHM_UNPROTECT();
337 	INCREMENT(mem_usage);
338 	SHM_PROTECT();
339 #else
340 	struct flock mem_usage_lock;
341 
342 	mem_usage_lock.l_type = F_RDLCK;
343 	mem_usage_lock.l_whence = SEEK_SET;
344 	mem_usage_lock.l_start = 1;
345 	mem_usage_lock.l_len = 1;
346 
347 	if (fcntl(lock_file, F_SETLK, &mem_usage_lock) == -1) {
348 		zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(+1):  %s (%d)", strerror(errno), errno);
349 		return FAILURE;
350 	}
351 #endif
352 	return SUCCESS;
353 }
354 
355 /* Releases a lock for SHM access */
accel_deactivate_sub(void)356 static inline void accel_deactivate_sub(void)
357 {
358 #ifdef ZEND_WIN32
359 	if (ZCG(counted)) {
360 		SHM_UNPROTECT();
361 		DECREMENT(mem_usage);
362 		ZCG(counted) = false;
363 		SHM_PROTECT();
364 	}
365 #else
366 	struct flock mem_usage_unlock;
367 
368 	mem_usage_unlock.l_type = F_UNLCK;
369 	mem_usage_unlock.l_whence = SEEK_SET;
370 	mem_usage_unlock.l_start = 1;
371 	mem_usage_unlock.l_len = 1;
372 
373 	if (fcntl(lock_file, F_SETLK, &mem_usage_unlock) == -1) {
374 		zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(-1):  %s (%d)", strerror(errno), errno);
375 	}
376 #endif
377 }
378 
accel_unlock_all(void)379 static inline void accel_unlock_all(void)
380 {
381 #ifdef ZEND_WIN32
382 	accel_deactivate_sub();
383 #else
384 	if (lock_file == -1) {
385 		return;
386 	}
387 
388 	struct flock mem_usage_unlock_all;
389 
390 	mem_usage_unlock_all.l_type = F_UNLCK;
391 	mem_usage_unlock_all.l_whence = SEEK_SET;
392 	mem_usage_unlock_all.l_start = 0;
393 	mem_usage_unlock_all.l_len = 0;
394 
395 	if (fcntl(lock_file, F_SETLK, &mem_usage_unlock_all) == -1) {
396 		zend_accel_error(ACCEL_LOG_DEBUG, "UnlockAll:  %s (%d)", strerror(errno), errno);
397 	}
398 #endif
399 }
400 
401 /* Interned strings support */
402 
403 /* O+ disables creation of interned strings by regular PHP compiler, instead,
404  * it creates interned strings in shared memory when saves a script.
405  * Such interned strings are shared across all PHP processes
406  */
407 
408 #define STRTAB_INVALID_POS 0
409 
410 #define STRTAB_HASH_TO_SLOT(tab, h) \
411 	((zend_string_table_pos_t*)((char*)(tab) + sizeof(*(tab)) + ((h) & (tab)->nTableMask)))
412 #define STRTAB_STR_TO_POS(tab, s) \
413 	((zend_string_table_pos_t)(((char*)s - (char*)(tab)) / ZEND_STRING_TABLE_POS_ALIGNMENT))
414 #define STRTAB_POS_TO_STR(tab, pos) \
415 	((zend_string*)((char*)(tab) + ((uintptr_t)(pos) * ZEND_STRING_TABLE_POS_ALIGNMENT)))
416 #define STRTAB_COLLISION(s) \
417 	(*((zend_string_table_pos_t*)((char*)s - sizeof(zend_string_table_pos_t))))
418 #define STRTAB_STR_SIZE(s) \
419 	ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(ZSTR_LEN(s)) + sizeof(zend_string_table_pos_t), ZEND_STRING_TABLE_POS_ALIGNMENT)
420 #define STRTAB_NEXT(s) \
421 	((zend_string*)((char*)(s) + STRTAB_STR_SIZE(s)))
422 
accel_interned_strings_restore_state(void)423 static void accel_interned_strings_restore_state(void)
424 {
425 	zend_string *s, *top;
426 	zend_string_table_pos_t *hash_slot, n;
427 
428 	/* clear removed content */
429 	memset(ZCSG(interned_strings).saved_top,
430 			0, (char*)ZCSG(interned_strings).top - (char*)ZCSG(interned_strings).saved_top);
431 
432 	/* Reset "top" */
433 	ZCSG(interned_strings).top = ZCSG(interned_strings).saved_top;
434 
435 	/* rehash */
436 	memset((char*)&ZCSG(interned_strings) + sizeof(zend_string_table),
437 		STRTAB_INVALID_POS,
438 		(char*)ZCSG(interned_strings).start -
439 			((char*)&ZCSG(interned_strings) + sizeof(zend_string_table)));
440 	s = ZCSG(interned_strings).start;
441 	top = ZCSG(interned_strings).top;
442 	n = 0;
443 	if (EXPECTED(s < top)) {
444 		do {
445 			if (ZSTR_HAS_CE_CACHE(s)) {
446 				/* Discard non-global CE_CACHE slots on reset. */
447 				uintptr_t idx = (GC_REFCOUNT(s) - 1) / sizeof(void *);
448 				if (idx >= ZCSG(map_ptr_last)) {
449 					GC_SET_REFCOUNT(s, 2);
450 					GC_DEL_FLAGS(s, IS_STR_CLASS_NAME_MAP_PTR);
451 				}
452 			}
453 
454 			hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), ZSTR_H(s));
455 			STRTAB_COLLISION(s) = *hash_slot;
456 			*hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s);
457 			s = STRTAB_NEXT(s);
458 			n++;
459 		} while (s < top);
460 	}
461 	ZCSG(interned_strings).nNumOfElements = n;
462 }
463 
accel_interned_strings_save_state(void)464 static void accel_interned_strings_save_state(void)
465 {
466 	ZCSG(interned_strings).saved_top = ZCSG(interned_strings).top;
467 }
468 
accel_find_interned_string(zend_string * str)469 static zend_always_inline zend_string *accel_find_interned_string(zend_string *str)
470 {
471 	zend_ulong   h;
472 	zend_string_table_pos_t pos;
473 	zend_string *s;
474 
475 	if (IS_ACCEL_INTERNED(str)) {
476 		/* this is already an interned string */
477 		return str;
478 	}
479 
480 	if (!ZCG(counted)) {
481 		if (!ZCG(accelerator_enabled) || accel_activate_add() == FAILURE) {
482 			return NULL;
483 		}
484 		ZCG(counted) = true;
485 	}
486 
487 	h = zend_string_hash_val(str);
488 
489 	/* check for existing interned string */
490 	pos = *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
491 	if (EXPECTED(pos != STRTAB_INVALID_POS)) {
492 		do {
493 			s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
494 			if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
495 				return s;
496 			}
497 			pos = STRTAB_COLLISION(s);
498 		} while (pos != STRTAB_INVALID_POS);
499 	}
500 
501 	return NULL;
502 }
503 
accel_new_interned_string(zend_string * str)504 zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str)
505 {
506 	zend_ulong   h;
507 	zend_string_table_pos_t pos, *hash_slot;
508 	zend_string *s;
509 
510 	if (UNEXPECTED(file_cache_only)) {
511 		return str;
512 	}
513 
514 	if (IS_ACCEL_INTERNED(str)) {
515 		/* this is already an interned string */
516 		return str;
517 	}
518 
519 	h = zend_string_hash_val(str);
520 
521 	/* check for existing interned string */
522 	hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
523 	pos = *hash_slot;
524 	if (EXPECTED(pos != STRTAB_INVALID_POS)) {
525 		do {
526 			s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
527 			if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
528 				goto finish;
529 			}
530 			pos = STRTAB_COLLISION(s);
531 		} while (pos != STRTAB_INVALID_POS);
532 	}
533 
534 	if (UNEXPECTED((char*)ZCSG(interned_strings).end - (char*)ZCSG(interned_strings).top < STRTAB_STR_SIZE(str))) {
535 	    /* no memory, return the same non-interned string */
536 		zend_accel_error(ACCEL_LOG_WARNING, "Interned string buffer overflow");
537 		return str;
538 	}
539 
540 	/* create new interning string in shared interned strings buffer */
541 	ZCSG(interned_strings).nNumOfElements++;
542 	s = ZCSG(interned_strings).top;
543 	hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
544 	STRTAB_COLLISION(s) = *hash_slot;
545 	*hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s);
546 	GC_SET_REFCOUNT(s, 2);
547 	GC_TYPE_INFO(s) = GC_STRING | ((IS_STR_INTERNED | IS_STR_PERMANENT) << GC_FLAGS_SHIFT)| (ZSTR_IS_VALID_UTF8(str) ? IS_STR_VALID_UTF8 : 0);
548 	ZSTR_H(s) = h;
549 	ZSTR_LEN(s) = ZSTR_LEN(str);
550 	memcpy(ZSTR_VAL(s), ZSTR_VAL(str), ZSTR_LEN(s) + 1);
551 	ZCSG(interned_strings).top = STRTAB_NEXT(s);
552 
553 finish:
554 	/* Transfer CE_CACHE map ptr slot to new interned string.
555 	 * Should only happen for permanent interned strings with permanent map_ptr slot. */
556 	if (ZSTR_HAS_CE_CACHE(str) && !ZSTR_HAS_CE_CACHE(s)) {
557 		ZEND_ASSERT(GC_FLAGS(str) & IS_STR_PERMANENT);
558 		GC_SET_REFCOUNT(s, GC_REFCOUNT(str));
559 		GC_ADD_FLAGS(s, IS_STR_CLASS_NAME_MAP_PTR);
560 	}
561 
562 	zend_string_release(str);
563 	return s;
564 }
565 
accel_new_interned_string_for_php(zend_string * str)566 static zend_string* ZEND_FASTCALL accel_new_interned_string_for_php(zend_string *str)
567 {
568 	zend_string_hash_val(str);
569 	if (ZCG(counted)) {
570 		zend_string *ret = accel_find_interned_string(str);
571 
572 		if (ret) {
573 			zend_string_release(str);
574 			return ret;
575 		}
576 	}
577 	return str;
578 }
579 
accel_find_interned_string_ex(zend_ulong h,const char * str,size_t size)580 static zend_always_inline zend_string *accel_find_interned_string_ex(zend_ulong h, const char *str, size_t size)
581 {
582 	zend_string_table_pos_t pos;
583 	zend_string *s;
584 
585 	/* check for existing interned string */
586 	pos = *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
587 	if (EXPECTED(pos != STRTAB_INVALID_POS)) {
588 		do {
589 			s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
590 			if (EXPECTED(ZSTR_H(s) == h) && zend_string_equals_cstr(s, str, size)) {
591 				return s;
592 			}
593 			pos = STRTAB_COLLISION(s);
594 		} while (pos != STRTAB_INVALID_POS);
595 	}
596 	return NULL;
597 }
598 
accel_init_interned_string_for_php(const char * str,size_t size,bool permanent)599 static zend_string* ZEND_FASTCALL accel_init_interned_string_for_php(const char *str, size_t size, bool permanent)
600 {
601 	if (ZCG(counted)) {
602 	    zend_ulong h = zend_inline_hash_func(str, size);
603 		zend_string *ret = accel_find_interned_string_ex(h, str, size);
604 
605 		if (!ret) {
606 			ret = zend_string_init(str, size, permanent);
607 			ZSTR_H(ret) = h;
608 		}
609 
610 		return ret;
611 	}
612 
613 	return zend_string_init(str, size, permanent);
614 }
615 
accel_copy_permanent_list_types(zend_new_interned_string_func_t new_interned_string,zend_type type)616 static inline void accel_copy_permanent_list_types(
617 	zend_new_interned_string_func_t new_interned_string, zend_type type)
618 {
619 	zend_type *single_type;
620 	ZEND_TYPE_FOREACH(type, single_type) {
621 		if (ZEND_TYPE_HAS_LIST(*single_type)) {
622 			ZEND_ASSERT(ZEND_TYPE_IS_INTERSECTION(*single_type));
623 			accel_copy_permanent_list_types(new_interned_string, *single_type);
624 		}
625 		if (ZEND_TYPE_HAS_NAME(*single_type)) {
626 			ZEND_TYPE_SET_PTR(*single_type, new_interned_string(ZEND_TYPE_NAME(*single_type)));
627 		}
628 	} ZEND_TYPE_FOREACH_END();
629 }
630 
631 /* Copy PHP interned strings from PHP process memory into the shared memory */
accel_copy_permanent_strings(zend_new_interned_string_func_t new_interned_string)632 static void accel_copy_permanent_strings(zend_new_interned_string_func_t new_interned_string)
633 {
634 	uint32_t j;
635 	Bucket *p, *q;
636 	HashTable *ht;
637 
638 	/* empty string */
639 	zend_empty_string = new_interned_string(zend_empty_string);
640 	for (j = 0; j < 256; j++) {
641 		zend_one_char_string[j] = new_interned_string(ZSTR_CHAR(j));
642 	}
643 	for (j = 0; j < ZEND_STR_LAST_KNOWN; j++) {
644 		zend_known_strings[j] = new_interned_string(zend_known_strings[j]);
645 	}
646 
647 	/* function table hash keys */
648 	ZEND_HASH_MAP_FOREACH_BUCKET(CG(function_table), p) {
649 		if (p->key) {
650 			p->key = new_interned_string(p->key);
651 		}
652 		if (Z_FUNC(p->val)->common.function_name) {
653 			Z_FUNC(p->val)->common.function_name = new_interned_string(Z_FUNC(p->val)->common.function_name);
654 		}
655 		if (Z_FUNC(p->val)->common.arg_info &&
656 		    (Z_FUNC(p->val)->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) {
657 			uint32_t i;
658 			uint32_t num_args = Z_FUNC(p->val)->common.num_args + 1;
659 			zend_arg_info *arg_info = Z_FUNC(p->val)->common.arg_info - 1;
660 
661 			if (Z_FUNC(p->val)->common.fn_flags & ZEND_ACC_VARIADIC) {
662 				num_args++;
663 			}
664 			for (i = 0 ; i < num_args; i++) {
665 				accel_copy_permanent_list_types(new_interned_string, arg_info[i].type);
666 			}
667 		}
668 	} ZEND_HASH_FOREACH_END();
669 
670 	/* class table hash keys, class names, properties, methods, constants, etc */
671 	ZEND_HASH_MAP_FOREACH_BUCKET(CG(class_table), p) {
672 		zend_class_entry *ce;
673 
674 		ce = (zend_class_entry*)Z_PTR(p->val);
675 
676 		if (p->key) {
677 			p->key = new_interned_string(p->key);
678 		}
679 
680 		if (ce->name) {
681 			ce->name = new_interned_string(ce->name);
682 			ZEND_ASSERT(ZSTR_HAS_CE_CACHE(ce->name));
683 		}
684 
685 		ZEND_HASH_MAP_FOREACH_BUCKET(&ce->properties_info, q) {
686 			zend_property_info *info;
687 
688 			info = (zend_property_info*)Z_PTR(q->val);
689 
690 			if (q->key) {
691 				q->key = new_interned_string(q->key);
692 			}
693 
694 			if (info->name) {
695 				info->name = new_interned_string(info->name);
696 			}
697 		} ZEND_HASH_FOREACH_END();
698 
699 		ZEND_HASH_MAP_FOREACH_BUCKET(&ce->function_table, q) {
700 			if (q->key) {
701 				q->key = new_interned_string(q->key);
702 			}
703 			if (Z_FUNC(q->val)->common.function_name) {
704 				Z_FUNC(q->val)->common.function_name = new_interned_string(Z_FUNC(q->val)->common.function_name);
705 			}
706 		} ZEND_HASH_FOREACH_END();
707 
708 		ZEND_HASH_MAP_FOREACH_BUCKET(&ce->constants_table, q) {
709 			zend_class_constant* c;
710 
711 			if (q->key) {
712 				q->key = new_interned_string(q->key);
713 			}
714 			c = (zend_class_constant*)Z_PTR(q->val);
715 			if (Z_TYPE(c->value) == IS_STRING) {
716 				ZVAL_STR(&c->value, new_interned_string(Z_STR(c->value)));
717 			}
718 		} ZEND_HASH_FOREACH_END();
719 	} ZEND_HASH_FOREACH_END();
720 
721 	/* constant hash keys */
722 	ZEND_HASH_MAP_FOREACH_BUCKET(EG(zend_constants), p) {
723 		zend_constant *c;
724 
725 		if (p->key) {
726 			p->key = new_interned_string(p->key);
727 		}
728 		c = (zend_constant*)Z_PTR(p->val);
729 		if (c->name) {
730 			c->name = new_interned_string(c->name);
731 		}
732 		if (Z_TYPE(c->value) == IS_STRING) {
733 			ZVAL_STR(&c->value, new_interned_string(Z_STR(c->value)));
734 		}
735 	} ZEND_HASH_FOREACH_END();
736 
737 	/* auto globals hash keys and names */
738 	ZEND_HASH_MAP_FOREACH_BUCKET(CG(auto_globals), p) {
739 		zend_auto_global *auto_global;
740 
741 		auto_global = (zend_auto_global*)Z_PTR(p->val);
742 
743 		zend_string_addref(auto_global->name);
744 		auto_global->name = new_interned_string(auto_global->name);
745 		if (p->key) {
746 			p->key = new_interned_string(p->key);
747 		}
748 	} ZEND_HASH_FOREACH_END();
749 
750 	ZEND_HASH_MAP_FOREACH_BUCKET(&module_registry, p) {
751 		if (p->key) {
752 			p->key = new_interned_string(p->key);
753 		}
754 	} ZEND_HASH_FOREACH_END();
755 
756 	ZEND_HASH_MAP_FOREACH_BUCKET(EG(ini_directives), p) {
757 		zend_ini_entry *entry = (zend_ini_entry*)Z_PTR(p->val);
758 
759 		if (p->key) {
760 			p->key = new_interned_string(p->key);
761 		}
762 		if (entry->name) {
763 			entry->name = new_interned_string(entry->name);
764 		}
765 		if (entry->value) {
766 			entry->value = new_interned_string(entry->value);
767 		}
768 		if (entry->orig_value) {
769 			entry->orig_value = new_interned_string(entry->orig_value);
770 		}
771 	} ZEND_HASH_FOREACH_END();
772 
773 	ht = php_get_stream_filters_hash_global();
774 	ZEND_HASH_MAP_FOREACH_BUCKET(ht, p) {
775 		if (p->key) {
776 			p->key = new_interned_string(p->key);
777 		}
778 	} ZEND_HASH_FOREACH_END();
779 
780 	ht = php_stream_get_url_stream_wrappers_hash_global();
781 	ZEND_HASH_MAP_FOREACH_BUCKET(ht, p) {
782 		if (p->key) {
783 			p->key = new_interned_string(p->key);
784 		}
785 	} ZEND_HASH_FOREACH_END();
786 
787 	ht = php_stream_xport_get_hash();
788 	ZEND_HASH_MAP_FOREACH_BUCKET(ht, p) {
789 		if (p->key) {
790 			p->key = new_interned_string(p->key);
791 		}
792 	} ZEND_HASH_FOREACH_END();
793 }
794 
accel_replace_string_by_shm_permanent(zend_string * str)795 static zend_string* ZEND_FASTCALL accel_replace_string_by_shm_permanent(zend_string *str)
796 {
797 	zend_string *ret = accel_find_interned_string(str);
798 
799 	if (ret) {
800 		zend_string_release(str);
801 		return ret;
802 	}
803 	return str;
804 }
805 
accel_use_shm_interned_strings(void)806 static void accel_use_shm_interned_strings(void)
807 {
808 	HANDLE_BLOCK_INTERRUPTIONS();
809 	SHM_UNPROTECT();
810 	zend_shared_alloc_lock();
811 
812 	if (ZCSG(interned_strings).saved_top == NULL) {
813 		accel_copy_permanent_strings(accel_new_interned_string);
814 	} else {
815 		ZCG(counted) = true;
816 		accel_copy_permanent_strings(accel_replace_string_by_shm_permanent);
817 		ZCG(counted) = false;
818 	}
819 	accel_interned_strings_save_state();
820 
821 	zend_shared_alloc_unlock();
822 	SHM_PROTECT();
823 	HANDLE_UNBLOCK_INTERRUPTIONS();
824 }
825 
826 #ifndef ZEND_WIN32
kill_all_lockers(struct flock * mem_usage_check)827 static inline void kill_all_lockers(struct flock *mem_usage_check)
828 {
829 	int tries;
830 	/* so that other process won't try to force while we are busy cleaning up */
831 	ZCSG(force_restart_time) = 0;
832 	while (mem_usage_check->l_pid > 0) {
833 		/* Try SIGTERM first, switch to SIGKILL if not successful. */
834 		int signal = SIGTERM;
835 		errno = 0;
836 		bool success = false;
837 		tries = 10;
838 
839 		while (tries--) {
840 			zend_accel_error(ACCEL_LOG_WARNING, "Attempting to kill locker %d", mem_usage_check->l_pid);
841 			if (kill(mem_usage_check->l_pid, signal)) {
842 				if (errno == ESRCH) {
843 					/* Process died before the signal was sent */
844 					success = true;
845 					zend_accel_error(ACCEL_LOG_WARNING, "Process %d died before SIGKILL was sent", mem_usage_check->l_pid);
846 				} else if (errno != 0) {
847 					zend_accel_error(ACCEL_LOG_WARNING, "Failed to send SIGKILL to locker %d: %s", mem_usage_check->l_pid, strerror(errno));
848 				}
849 				break;
850 			}
851 			/* give it a chance to die */
852 			usleep(20000);
853 			if (kill(mem_usage_check->l_pid, 0)) {
854 				if (errno == ESRCH) {
855 					/* successfully killed locker, process no longer exists  */
856 					success = true;
857 					zend_accel_error(ACCEL_LOG_WARNING, "Killed locker %d", mem_usage_check->l_pid);
858 				} else if (errno != 0) {
859 					zend_accel_error(ACCEL_LOG_WARNING, "Failed to check locker %d: %s", mem_usage_check->l_pid, strerror(errno));
860 				}
861 				break;
862 			}
863 			usleep(10000);
864 			/* If SIGTERM was not sufficient, use SIGKILL. */
865 			signal = SIGKILL;
866 		}
867 		if (!success) {
868 			/* errno is not ESRCH or we ran out of tries to kill the locker */
869 			ZCSG(force_restart_time) = time(NULL); /* restore forced restart request */
870 			/* cannot kill the locker, bail out with error */
871 			zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Cannot kill process %d!", mem_usage_check->l_pid);
872 		}
873 
874 		mem_usage_check->l_type = F_WRLCK;
875 		mem_usage_check->l_whence = SEEK_SET;
876 		mem_usage_check->l_start = 1;
877 		mem_usage_check->l_len = 1;
878 		mem_usage_check->l_pid = -1;
879 		if (fcntl(lock_file, F_GETLK, mem_usage_check) == -1) {
880 			zend_accel_error(ACCEL_LOG_DEBUG, "KLockers:  %s (%d)", strerror(errno), errno);
881 			break;
882 		}
883 
884 		if (mem_usage_check->l_type == F_UNLCK || mem_usage_check->l_pid <= 0) {
885 			break;
886 		}
887 	}
888 }
889 #endif
890 
accel_is_inactive(void)891 static inline bool accel_is_inactive(void)
892 {
893 #ifdef ZEND_WIN32
894 	/* on Windows, we don't need kill_all_lockers() because SAPIs
895 	   that work on Windows don't manage child processes (and we
896 	   can't do anything about hanging threads anyway); therefore
897 	   on Windows, we can simply manage this counter with atomics
898 	   instead of flocks (atomics are much faster but they don't
899 	   provide us with the PID of locker processes) */
900 
901 	if (LOCKVAL(mem_usage) == 0) {
902 		return true;
903 	}
904 #else
905 	struct flock mem_usage_check;
906 
907 	mem_usage_check.l_type = F_WRLCK;
908 	mem_usage_check.l_whence = SEEK_SET;
909 	mem_usage_check.l_start = 1;
910 	mem_usage_check.l_len = 1;
911 	mem_usage_check.l_pid = -1;
912 	if (fcntl(lock_file, F_GETLK, &mem_usage_check) == -1) {
913 		zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC:  %s (%d)", strerror(errno), errno);
914 		return false;
915 	}
916 	if (mem_usage_check.l_type == F_UNLCK) {
917 		return true;
918 	}
919 
920 	if (ZCG(accel_directives).force_restart_timeout
921 		&& ZCSG(force_restart_time)
922 		&& time(NULL) >= ZCSG(force_restart_time)) {
923 		zend_accel_error(ACCEL_LOG_WARNING, "Forced restart at %ld (after " ZEND_LONG_FMT " seconds), locked by %d", (long)time(NULL), ZCG(accel_directives).force_restart_timeout, mem_usage_check.l_pid);
924 		kill_all_lockers(&mem_usage_check);
925 
926 		return false; /* next request should be able to restart it */
927 	}
928 #endif
929 
930 	return false;
931 }
932 
zend_get_stream_timestamp(const char * filename,zend_stat_t * statbuf)933 static int zend_get_stream_timestamp(const char *filename, zend_stat_t *statbuf)
934 {
935 	php_stream_wrapper *wrapper;
936 	php_stream_statbuf stream_statbuf;
937 	int ret, er;
938 
939 	if (!filename) {
940 		return FAILURE;
941 	}
942 
943 	wrapper = php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY);
944 	if (!wrapper) {
945 		return FAILURE;
946 	}
947 	if (!wrapper->wops || !wrapper->wops->url_stat) {
948 		statbuf->st_mtime = 1;
949 		return SUCCESS; /* anything other than 0 is considered to be a valid timestamp */
950 	}
951 
952 	er = EG(error_reporting);
953 	EG(error_reporting) = 0;
954 	zend_try {
955 		ret = wrapper->wops->url_stat(wrapper, (char*)filename, PHP_STREAM_URL_STAT_QUIET, &stream_statbuf, NULL);
956 	} zend_catch {
957 		ret = -1;
958 	} zend_end_try();
959 	EG(error_reporting) = er;
960 
961 	if (ret != 0) {
962 		return FAILURE;
963 	}
964 
965 	*statbuf = stream_statbuf.sb;
966 	return SUCCESS;
967 }
968 
969 #ifdef ZEND_WIN32
zend_get_file_handle_timestamp_win(zend_file_handle * file_handle,size_t * size)970 static accel_time_t zend_get_file_handle_timestamp_win(zend_file_handle *file_handle, size_t *size)
971 {
972 	static unsigned __int64 utc_base = 0;
973 	static FILETIME utc_base_ft;
974 	WIN32_FILE_ATTRIBUTE_DATA fdata;
975 
976 	if (!file_handle->opened_path) {
977 		return 0;
978 	}
979 
980 	if (!utc_base) {
981 		SYSTEMTIME st;
982 
983 		st.wYear = 1970;
984 		st.wMonth = 1;
985 		st.wDay = 1;
986 		st.wHour = 0;
987 		st.wMinute = 0;
988 		st.wSecond = 0;
989 		st.wMilliseconds = 0;
990 
991 		SystemTimeToFileTime (&st, &utc_base_ft);
992 		utc_base = (((unsigned __int64)utc_base_ft.dwHighDateTime) << 32) + utc_base_ft.dwLowDateTime;
993 	}
994 
995 	if (file_handle->opened_path && GetFileAttributesEx(file_handle->opened_path->val, GetFileExInfoStandard, &fdata) != 0) {
996 		unsigned __int64 ftime;
997 
998 		if (CompareFileTime (&fdata.ftLastWriteTime, &utc_base_ft) < 0) {
999 			return 0;
1000 		}
1001 
1002 		ftime = (((unsigned __int64)fdata.ftLastWriteTime.dwHighDateTime) << 32) + fdata.ftLastWriteTime.dwLowDateTime - utc_base;
1003 		ftime /= 10000000L;
1004 
1005 		if (size) {
1006 			*size = (size_t)((((unsigned __int64)fdata.nFileSizeHigh) << 32) + (unsigned __int64)fdata.nFileSizeLow);
1007 		}
1008 		return (accel_time_t)ftime;
1009 	}
1010 	return 0;
1011 }
1012 #endif
1013 
zend_get_file_handle_timestamp(zend_file_handle * file_handle,size_t * size)1014 accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size)
1015 {
1016 	zend_stat_t statbuf = {0};
1017 #ifdef ZEND_WIN32
1018 	accel_time_t res;
1019 #endif
1020 
1021 	if (sapi_module.get_stat &&
1022 	    !EG(current_execute_data) &&
1023 	    file_handle->primary_script) {
1024 
1025 		zend_stat_t *tmpbuf = sapi_module.get_stat();
1026 
1027 		if (tmpbuf) {
1028 			if (size) {
1029 				*size = tmpbuf->st_size;
1030 			}
1031 			return tmpbuf->st_mtime;
1032 		}
1033 	}
1034 
1035 #ifdef ZEND_WIN32
1036 	res = zend_get_file_handle_timestamp_win(file_handle, size);
1037 	if (res) {
1038 		return res;
1039 	}
1040 #endif
1041 
1042 	switch (file_handle->type) {
1043 		case ZEND_HANDLE_FP:
1044 			if (zend_fstat(fileno(file_handle->handle.fp), &statbuf) == -1) {
1045 				if (zend_get_stream_timestamp(ZSTR_VAL(file_handle->filename), &statbuf) != SUCCESS) {
1046 					return 0;
1047 				}
1048 			}
1049 			break;
1050 		case ZEND_HANDLE_FILENAME:
1051 			if (file_handle->opened_path) {
1052 				char *file_path = ZSTR_VAL(file_handle->opened_path);
1053 
1054 				if (php_is_stream_path(file_path)) {
1055 					if (zend_get_stream_timestamp(file_path, &statbuf) == SUCCESS) {
1056 						break;
1057 					}
1058 				}
1059 				if (VCWD_STAT(file_path, &statbuf) != -1) {
1060 					break;
1061 				}
1062 			}
1063 
1064 			if (zend_get_stream_timestamp(ZSTR_VAL(file_handle->filename), &statbuf) != SUCCESS) {
1065 				return 0;
1066 			}
1067 			break;
1068 		case ZEND_HANDLE_STREAM:
1069 			{
1070 				php_stream *stream = (php_stream *)file_handle->handle.stream.handle;
1071 				php_stream_statbuf sb;
1072 				int ret, er;
1073 
1074 				if (!stream ||
1075 				    !stream->ops ||
1076 				    !stream->ops->stat) {
1077 					return 0;
1078 				}
1079 
1080 				er = EG(error_reporting);
1081 				EG(error_reporting) = 0;
1082 				zend_try {
1083 					ret = stream->ops->stat(stream, &sb);
1084 				} zend_catch {
1085 					ret = -1;
1086 				} zend_end_try();
1087 				EG(error_reporting) = er;
1088 				if (ret != 0) {
1089 					return 0;
1090 				}
1091 
1092 				statbuf = sb.sb;
1093 			}
1094 			break;
1095 
1096 		default:
1097 			return 0;
1098 	}
1099 
1100 	if (size) {
1101 		*size = statbuf.st_size;
1102 	}
1103 	return statbuf.st_mtime;
1104 }
1105 
do_validate_timestamps(zend_persistent_script * persistent_script,zend_file_handle * file_handle)1106 static inline int do_validate_timestamps(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
1107 {
1108 	zend_file_handle ps_handle;
1109 	zend_string *full_path_ptr = NULL;
1110 	int ret;
1111 
1112 	/** check that the persistent script is indeed the same file we cached
1113 	 * (if part of the path is a symlink than it possible that the user will change it)
1114 	 * See bug #15140
1115 	 */
1116 	if (file_handle->opened_path) {
1117 		if (persistent_script->script.filename != file_handle->opened_path &&
1118 		    !zend_string_equal_content(persistent_script->script.filename, file_handle->opened_path)) {
1119 			return FAILURE;
1120 		}
1121 	} else {
1122 		full_path_ptr = accelerator_orig_zend_resolve_path(file_handle->filename);
1123 		if (full_path_ptr &&
1124 		    persistent_script->script.filename != full_path_ptr &&
1125 		    !zend_string_equal_content(persistent_script->script.filename, full_path_ptr)) {
1126 			zend_string_release_ex(full_path_ptr, 0);
1127 			return FAILURE;
1128 		}
1129 		file_handle->opened_path = full_path_ptr;
1130 	}
1131 
1132 	if (persistent_script->timestamp == 0) {
1133 		if (full_path_ptr) {
1134 			zend_string_release_ex(full_path_ptr, 0);
1135 			file_handle->opened_path = NULL;
1136 		}
1137 		return FAILURE;
1138 	}
1139 
1140 	if (zend_get_file_handle_timestamp(file_handle, NULL) == persistent_script->timestamp) {
1141 		if (full_path_ptr) {
1142 			zend_string_release_ex(full_path_ptr, 0);
1143 			file_handle->opened_path = NULL;
1144 		}
1145 		return SUCCESS;
1146 	}
1147 	if (full_path_ptr) {
1148 		zend_string_release_ex(full_path_ptr, 0);
1149 		file_handle->opened_path = NULL;
1150 	}
1151 
1152 	zend_stream_init_filename_ex(&ps_handle, persistent_script->script.filename);
1153 	ps_handle.opened_path = persistent_script->script.filename;
1154 
1155 	ret = zend_get_file_handle_timestamp(&ps_handle, NULL) == persistent_script->timestamp
1156 		? SUCCESS : FAILURE;
1157 
1158 	zend_destroy_file_handle(&ps_handle);
1159 
1160 	return ret;
1161 }
1162 
validate_timestamp_and_record(zend_persistent_script * persistent_script,zend_file_handle * file_handle)1163 zend_result validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
1164 {
1165 	if (persistent_script->timestamp == 0) {
1166 		return SUCCESS; /* Don't check timestamps of preloaded scripts */
1167 	} else if (ZCG(accel_directives).revalidate_freq &&
1168 	    persistent_script->dynamic_members.revalidate >= ZCG(request_time)) {
1169 		return SUCCESS;
1170 	} else if (do_validate_timestamps(persistent_script, file_handle) == FAILURE) {
1171 		return FAILURE;
1172 	} else {
1173 		persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
1174 		return SUCCESS;
1175 	}
1176 }
1177 
validate_timestamp_and_record_ex(zend_persistent_script * persistent_script,zend_file_handle * file_handle)1178 zend_result validate_timestamp_and_record_ex(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
1179 {
1180 	SHM_UNPROTECT();
1181 	const zend_result ret = validate_timestamp_and_record(persistent_script, file_handle);
1182 	SHM_PROTECT();
1183 
1184 	return ret;
1185 }
1186 
1187 /* Instead of resolving full real path name each time we need to identify file,
1188  * we create a key that consist from requested file name, current working
1189  * directory, current include_path, etc */
accel_make_persistent_key(zend_string * str)1190 zend_string *accel_make_persistent_key(zend_string *str)
1191 {
1192 	const char *path = ZSTR_VAL(str);
1193 	size_t path_length = ZSTR_LEN(str);
1194 	char *key;
1195 	int key_length;
1196 
1197 	ZSTR_LEN(&ZCG(key)) = 0;
1198 
1199 	/* CWD and include_path don't matter for absolute file names and streams */
1200 	if (IS_ABSOLUTE_PATH(path, path_length)) {
1201 		/* pass */
1202 	} else if (UNEXPECTED(php_is_stream_path(path))) {
1203 		if (!is_cacheable_stream_path(path)) {
1204 			return NULL;
1205 		}
1206 		/* pass */
1207 	} else if (UNEXPECTED(!ZCG(accel_directives).use_cwd)) {
1208 		/* pass */
1209 	} else {
1210 		const char *include_path = NULL, *cwd = NULL;
1211 		int include_path_len = 0, cwd_len = 0;
1212 		zend_string *parent_script = NULL;
1213 		size_t parent_script_len = 0;
1214 
1215 		if (EXPECTED(ZCG(cwd_key_len))) {
1216 			cwd = ZCG(cwd_key);
1217 			cwd_len = ZCG(cwd_key_len);
1218 		} else {
1219 			zend_string *cwd_str = accel_getcwd();
1220 
1221 			if (UNEXPECTED(!cwd_str)) {
1222 				/* we don't handle this well for now. */
1223 				zend_accel_error(ACCEL_LOG_INFO, "getcwd() failed for '%s' (%d), please try to set opcache.use_cwd to 0 in ini file", path, errno);
1224 				return NULL;
1225 			}
1226 			cwd = ZSTR_VAL(cwd_str);
1227 			cwd_len = ZSTR_LEN(cwd_str);
1228 			if (ZCG(cwd_check)) {
1229 				ZCG(cwd_check) = false;
1230 				if (ZCG(accelerator_enabled)) {
1231 
1232 					zend_string *str = accel_find_interned_string(cwd_str);
1233 					if (!str) {
1234 						HANDLE_BLOCK_INTERRUPTIONS();
1235 						SHM_UNPROTECT();
1236 						zend_shared_alloc_lock();
1237 						str = accel_new_interned_string(zend_string_copy(cwd_str));
1238 						if (str == cwd_str) {
1239 							zend_string_release_ex(str, 0);
1240 							str = NULL;
1241 						}
1242 						zend_shared_alloc_unlock();
1243 						SHM_PROTECT();
1244 						HANDLE_UNBLOCK_INTERRUPTIONS();
1245 					}
1246 					if (str) {
1247 						char buf[32];
1248 						char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, STRTAB_STR_TO_POS(&ZCSG(interned_strings), str));
1249 
1250 						cwd_len = ZCG(cwd_key_len) = buf + sizeof(buf) - 1 - res;
1251 						cwd = ZCG(cwd_key);
1252 						memcpy(ZCG(cwd_key), res, cwd_len + 1);
1253 					} else {
1254 						return NULL;
1255 					}
1256 				} else {
1257 					return NULL;
1258 				}
1259 			}
1260 		}
1261 
1262 		if (EXPECTED(ZCG(include_path_key_len))) {
1263 			include_path = ZCG(include_path_key);
1264 			include_path_len = ZCG(include_path_key_len);
1265 		} else if (!ZCG(include_path) || ZSTR_LEN(ZCG(include_path)) == 0) {
1266 			include_path = "";
1267 			include_path_len = 0;
1268 		} else {
1269 			include_path = ZSTR_VAL(ZCG(include_path));
1270 			include_path_len = ZSTR_LEN(ZCG(include_path));
1271 
1272 			if (ZCG(include_path_check)) {
1273 				ZCG(include_path_check) = false;
1274 				if (ZCG(accelerator_enabled)) {
1275 
1276 					zend_string *str = accel_find_interned_string(ZCG(include_path));
1277 					if (!str) {
1278 						HANDLE_BLOCK_INTERRUPTIONS();
1279 						SHM_UNPROTECT();
1280 						zend_shared_alloc_lock();
1281 						str = accel_new_interned_string(zend_string_copy(ZCG(include_path)));
1282 						if (str == ZCG(include_path)) {
1283 							zend_string_release(str);
1284 							str = NULL;
1285 						}
1286 						zend_shared_alloc_unlock();
1287 						SHM_PROTECT();
1288 						HANDLE_UNBLOCK_INTERRUPTIONS();
1289 					}
1290 					if (str) {
1291 						char buf[32];
1292 						char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, STRTAB_STR_TO_POS(&ZCSG(interned_strings), str));
1293 
1294 						include_path_len = ZCG(include_path_key_len) = buf + sizeof(buf) - 1 - res;
1295 						include_path = ZCG(include_path_key);
1296 						memcpy(ZCG(include_path_key), res, include_path_len + 1);
1297 					} else {
1298 						return NULL;
1299 					}
1300 				} else {
1301 					return NULL;
1302 				}
1303 			}
1304 		}
1305 
1306 		/* Calculate key length */
1307 		if (UNEXPECTED((size_t)(cwd_len + path_length + include_path_len + 2) >= sizeof(ZCG(_key)))) {
1308 			return NULL;
1309 		}
1310 
1311 		/* Generate key
1312 		 * Note - the include_path must be the last element in the key,
1313 		 * since in itself, it may include colons (which we use to separate
1314 		 * different components of the key)
1315 		 */
1316 		key = ZSTR_VAL(&ZCG(key));
1317 		memcpy(key, path, path_length);
1318 		key[path_length] = ':';
1319 		key_length = path_length + 1;
1320 		memcpy(key + key_length, cwd, cwd_len);
1321 		key_length += cwd_len;
1322 
1323 		if (include_path_len) {
1324 			key[key_length] = ':';
1325 			key_length += 1;
1326 			memcpy(key + key_length, include_path, include_path_len);
1327 			key_length += include_path_len;
1328 		}
1329 
1330 		/* Here we add to the key the parent script directory,
1331 		 * since fopen_wrappers from version 4.0.7 use current script's path
1332 		 * in include path too.
1333 		 */
1334 		if (EXPECTED(EG(current_execute_data)) &&
1335 		    EXPECTED((parent_script = zend_get_executed_filename_ex()) != NULL)) {
1336 
1337 			parent_script_len = ZSTR_LEN(parent_script);
1338 			while ((--parent_script_len > 0) && !IS_SLASH(ZSTR_VAL(parent_script)[parent_script_len]));
1339 
1340 			if (UNEXPECTED((size_t)(key_length + parent_script_len + 1) >= sizeof(ZCG(_key)))) {
1341 				return NULL;
1342 			}
1343 			key[key_length] = ':';
1344 			key_length += 1;
1345 			memcpy(key + key_length, ZSTR_VAL(parent_script), parent_script_len);
1346 			key_length += parent_script_len;
1347 		}
1348 		key[key_length] = '\0';
1349 		GC_SET_REFCOUNT(&ZCG(key), 1);
1350 		GC_TYPE_INFO(&ZCG(key)) = GC_STRING;
1351 		ZSTR_H(&ZCG(key)) = 0;
1352 		ZSTR_LEN(&ZCG(key)) = key_length;
1353 		return &ZCG(key);
1354 	}
1355 
1356 	/* not use_cwd */
1357 	return str;
1358 }
1359 
1360 /**
1361  * Discard a #zend_persistent_script currently stored in shared
1362  * memory.
1363  *
1364  * Caller must lock shared memory via zend_shared_alloc_lock().
1365  */
zend_accel_discard_script(zend_persistent_script * persistent_script)1366 static void zend_accel_discard_script(zend_persistent_script *persistent_script)
1367 {
1368 	if (persistent_script->corrupted) {
1369 		/* already discarded */
1370 		return;
1371 	}
1372 
1373 	persistent_script->corrupted = true;
1374 	persistent_script->timestamp = 0;
1375 	ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1376 	if (ZSMMG(memory_exhausted)) {
1377 		zend_accel_restart_reason reason =
1378 			zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
1379 		zend_accel_schedule_restart_if_necessary(reason);
1380 	}
1381 }
1382 
1383 /**
1384  * Wrapper for zend_accel_discard_script() which locks shared memory
1385  * via zend_shared_alloc_lock().
1386  */
zend_accel_lock_discard_script(zend_persistent_script * persistent_script)1387 static void zend_accel_lock_discard_script(zend_persistent_script *persistent_script)
1388 {
1389 	zend_shared_alloc_lock();
1390 	zend_accel_discard_script(persistent_script);
1391 	zend_shared_alloc_unlock();
1392 }
1393 
zend_accel_invalidate(zend_string * filename,bool force)1394 zend_result zend_accel_invalidate(zend_string *filename, bool force)
1395 {
1396 	zend_string *realpath;
1397 	zend_persistent_script *persistent_script;
1398 	zend_bool file_found = true;
1399 
1400 	if (!ZCG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) {
1401 		return FAILURE;
1402 	}
1403 
1404 	realpath = accelerator_orig_zend_resolve_path(filename);
1405 
1406 	if (!realpath) {
1407 		//file could have been deleted, but we still need to invalidate it.
1408 		//so instead of failing, just use the provided filename for the lookup
1409 		realpath = zend_string_copy(filename);
1410 		file_found = false;
1411 	}
1412 
1413 	if (ZCG(accel_directives).file_cache) {
1414 		zend_file_cache_invalidate(realpath);
1415 	}
1416 
1417 	persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath);
1418 	if (persistent_script && !persistent_script->corrupted) {
1419 		zend_file_handle file_handle;
1420 		zend_stream_init_filename_ex(&file_handle, realpath);
1421 		file_handle.opened_path = realpath;
1422 
1423 		if (force ||
1424 			!ZCG(accel_directives).validate_timestamps ||
1425 			do_validate_timestamps(persistent_script, &file_handle) == FAILURE) {
1426 			HANDLE_BLOCK_INTERRUPTIONS();
1427 			SHM_UNPROTECT();
1428 			zend_accel_lock_discard_script(persistent_script);
1429 			SHM_PROTECT();
1430 			HANDLE_UNBLOCK_INTERRUPTIONS();
1431 		}
1432 
1433 		file_handle.opened_path = NULL;
1434 		zend_destroy_file_handle(&file_handle);
1435 		file_found = true;
1436 	}
1437 
1438 	accelerator_shm_read_unlock();
1439 	zend_string_release_ex(realpath, 0);
1440 
1441 	return file_found ? SUCCESS : FAILURE;
1442 }
1443 
accel_new_interned_key(zend_string * key)1444 static zend_string* accel_new_interned_key(zend_string *key)
1445 {
1446 	zend_string *new_key;
1447 
1448 	if (zend_accel_in_shm(key)) {
1449 		return key;
1450 	}
1451 	GC_ADDREF(key);
1452 	new_key = accel_new_interned_string(key);
1453 	if (UNEXPECTED(new_key == key)) {
1454 		GC_DELREF(key);
1455 		new_key = zend_shared_alloc(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(ZSTR_LEN(key)), 8));
1456 		if (EXPECTED(new_key)) {
1457 			GC_SET_REFCOUNT(new_key, 2);
1458 			GC_TYPE_INFO(new_key) = GC_STRING | (IS_STR_INTERNED << GC_FLAGS_SHIFT);
1459 			ZSTR_H(new_key) = ZSTR_H(key);
1460 			ZSTR_LEN(new_key) = ZSTR_LEN(key);
1461 			memcpy(ZSTR_VAL(new_key), ZSTR_VAL(key), ZSTR_LEN(new_key) + 1);
1462 		}
1463 	}
1464 	return new_key;
1465 }
1466 
1467 /* Adds another key for existing cached script */
zend_accel_add_key(zend_string * key,zend_accel_hash_entry * bucket)1468 static void zend_accel_add_key(zend_string *key, zend_accel_hash_entry *bucket)
1469 {
1470 	if (!zend_accel_hash_find(&ZCSG(hash), key)) {
1471 		if (zend_accel_hash_is_full(&ZCSG(hash))) {
1472 			zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1473 			ZSMMG(memory_exhausted) = true;
1474 			zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
1475 		} else {
1476 			zend_string *new_key = accel_new_interned_key(key);
1477 			if (new_key) {
1478 				if (zend_accel_hash_update(&ZCSG(hash), new_key, 1, bucket)) {
1479 					zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", ZSTR_VAL(new_key));
1480 				}
1481 			} else {
1482 				zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
1483 			}
1484 		}
1485 	}
1486 }
1487 
is_phar_file(zend_string * filename)1488 static zend_always_inline bool is_phar_file(zend_string *filename)
1489 {
1490 	return filename && ZSTR_LEN(filename) >= sizeof(".phar") &&
1491 		!memcmp(ZSTR_VAL(filename) + ZSTR_LEN(filename) - (sizeof(".phar")-1), ".phar", sizeof(".phar")-1) &&
1492 		!strstr(ZSTR_VAL(filename), "://");
1493 }
1494 
store_script_in_file_cache(zend_persistent_script * new_persistent_script)1495 static zend_persistent_script *store_script_in_file_cache(zend_persistent_script *new_persistent_script)
1496 {
1497 	uint32_t memory_used;
1498 
1499 	zend_shared_alloc_init_xlat_table();
1500 
1501 	/* Calculate the required memory size */
1502 	memory_used = zend_accel_script_persist_calc(new_persistent_script, 0);
1503 
1504 	/* Allocate memory block */
1505 #if defined(__AVX__) || defined(__SSE2__)
1506 	/* Align to 64-byte boundary */
1507 	ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used + 64);
1508 	ZCG(mem) = (void*)(((uintptr_t)ZCG(mem) + 63L) & ~63L);
1509 #elif ZEND_MM_NEED_EIGHT_BYTE_REALIGNMENT
1510 	/* Align to 8-byte boundary */
1511 	ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used + 8);
1512 	ZCG(mem) = (void*)(((uintptr_t)ZCG(mem) + 7L) & ~7L);
1513 #else
1514 	ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used);
1515 #endif
1516 
1517 	zend_shared_alloc_clear_xlat_table();
1518 
1519 	/* Copy into memory block */
1520 	new_persistent_script = zend_accel_script_persist(new_persistent_script, 0);
1521 
1522 	zend_shared_alloc_destroy_xlat_table();
1523 
1524 	new_persistent_script->is_phar = is_phar_file(new_persistent_script->script.filename);
1525 
1526 	/* Consistency check */
1527 	if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
1528 		zend_accel_error(
1529 			((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
1530 			"Internal error: wrong size calculation: %s start=" ZEND_ADDR_FMT ", end=" ZEND_ADDR_FMT ", real=" ZEND_ADDR_FMT "\n",
1531 			ZSTR_VAL(new_persistent_script->script.filename),
1532 			(size_t)new_persistent_script->mem,
1533 			(size_t)((char *)new_persistent_script->mem + new_persistent_script->size),
1534 			(size_t)ZCG(mem));
1535 	}
1536 
1537 	zend_file_cache_script_store(new_persistent_script, /* is_shm */ false);
1538 
1539 	return new_persistent_script;
1540 }
1541 
cache_script_in_file_cache(zend_persistent_script * new_persistent_script,bool * from_shared_memory)1542 static zend_persistent_script *cache_script_in_file_cache(zend_persistent_script *new_persistent_script, bool *from_shared_memory)
1543 {
1544 	uint32_t orig_compiler_options;
1545 
1546 	orig_compiler_options = CG(compiler_options);
1547 	CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
1548 	zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level);
1549 	zend_accel_finalize_delayed_early_binding_list(new_persistent_script);
1550 	CG(compiler_options) = orig_compiler_options;
1551 
1552 	*from_shared_memory = true;
1553 	return store_script_in_file_cache(new_persistent_script);
1554 }
1555 
cache_script_in_shared_memory(zend_persistent_script * new_persistent_script,zend_string * key,bool * from_shared_memory)1556 static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_script *new_persistent_script, zend_string *key, bool *from_shared_memory)
1557 {
1558 	zend_accel_hash_entry *bucket;
1559 	uint32_t memory_used;
1560 	uint32_t orig_compiler_options;
1561 
1562 	orig_compiler_options = CG(compiler_options);
1563 	if (ZCG(accel_directives).file_cache) {
1564 		CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
1565 	}
1566 	zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level);
1567 	zend_accel_finalize_delayed_early_binding_list(new_persistent_script);
1568 	CG(compiler_options) = orig_compiler_options;
1569 
1570 	/* exclusive lock */
1571 	zend_shared_alloc_lock();
1572 
1573 	/* Check if we still need to put the file into the cache (may be it was
1574 	 * already stored by another process. This final check is done under
1575 	 * exclusive lock) */
1576 	bucket = zend_accel_hash_find_entry(&ZCSG(hash), new_persistent_script->script.filename);
1577 	if (bucket) {
1578 		zend_persistent_script *existing_persistent_script = (zend_persistent_script *)bucket->data;
1579 
1580 		if (!existing_persistent_script->corrupted) {
1581 			if (key &&
1582 			    (!ZCG(accel_directives).validate_timestamps ||
1583 			     (new_persistent_script->timestamp == existing_persistent_script->timestamp))) {
1584 				zend_accel_add_key(key, bucket);
1585 			}
1586 			zend_shared_alloc_unlock();
1587 #if 1
1588 			/* prefer the script already stored in SHM */
1589 			free_persistent_script(new_persistent_script, 1);
1590 			*from_shared_memory = true;
1591 			return existing_persistent_script;
1592 #else
1593 			return new_persistent_script;
1594 #endif
1595 		}
1596 	}
1597 
1598 	if (zend_accel_hash_is_full(&ZCSG(hash))) {
1599 		zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1600 		ZSMMG(memory_exhausted) = true;
1601 		zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
1602 		zend_shared_alloc_unlock();
1603 		if (ZCG(accel_directives).file_cache) {
1604 			new_persistent_script = store_script_in_file_cache(new_persistent_script);
1605 			*from_shared_memory = true;
1606 		}
1607 		return new_persistent_script;
1608 	}
1609 
1610 	zend_shared_alloc_init_xlat_table();
1611 
1612 	/* Calculate the required memory size */
1613 	memory_used = zend_accel_script_persist_calc(new_persistent_script, 1);
1614 
1615 	/* Allocate shared memory */
1616 	ZCG(mem) = zend_shared_alloc_aligned(memory_used);
1617 	if (!ZCG(mem)) {
1618 		zend_shared_alloc_destroy_xlat_table();
1619 		zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
1620 		zend_shared_alloc_unlock();
1621 		if (ZCG(accel_directives).file_cache) {
1622 			new_persistent_script = store_script_in_file_cache(new_persistent_script);
1623 			*from_shared_memory = true;
1624 		}
1625 		return new_persistent_script;
1626 	}
1627 
1628 	bzero_aligned(ZCG(mem), memory_used);
1629 
1630 	zend_shared_alloc_clear_xlat_table();
1631 
1632 	/* Copy into shared memory */
1633 	new_persistent_script = zend_accel_script_persist(new_persistent_script, 1);
1634 
1635 	zend_shared_alloc_destroy_xlat_table();
1636 
1637 	new_persistent_script->is_phar = is_phar_file(new_persistent_script->script.filename);
1638 
1639 	/* Consistency check */
1640 	if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
1641 		zend_accel_error(
1642 			((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
1643 			"Internal error: wrong size calculation: %s start=" ZEND_ADDR_FMT ", end=" ZEND_ADDR_FMT ", real=" ZEND_ADDR_FMT "\n",
1644 			ZSTR_VAL(new_persistent_script->script.filename),
1645 			(size_t)new_persistent_script->mem,
1646 			(size_t)((char *)new_persistent_script->mem + new_persistent_script->size),
1647 			(size_t)ZCG(mem));
1648 	}
1649 
1650 	/* store script structure in the hash table */
1651 	bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->script.filename, 0, new_persistent_script);
1652 	if (bucket) {
1653 		zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", ZSTR_VAL(new_persistent_script->script.filename));
1654 		if (key &&
1655 		    /* key may contain non-persistent PHAR aliases (see issues #115 and #149) */
1656 		    !zend_string_starts_with_literal(key, "phar://") &&
1657 		    !zend_string_equals(new_persistent_script->script.filename, key)) {
1658 			/* link key to the same persistent script in hash table */
1659 			zend_string *new_key = accel_new_interned_key(key);
1660 
1661 			if (new_key) {
1662 				if (zend_accel_hash_update(&ZCSG(hash), new_key, 1, bucket)) {
1663 					zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", ZSTR_VAL(key));
1664 				} else {
1665 					zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1666 					ZSMMG(memory_exhausted) = true;
1667 					zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
1668 				}
1669 			} else {
1670 				zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
1671 			}
1672 		}
1673 	}
1674 
1675 	new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
1676 
1677 	zend_shared_alloc_unlock();
1678 
1679 	if (ZCG(accel_directives).file_cache) {
1680 		SHM_PROTECT();
1681 		zend_file_cache_script_store(new_persistent_script, /* is_shm */ true);
1682 		SHM_UNPROTECT();
1683 	}
1684 
1685 	*from_shared_memory = true;
1686 	return new_persistent_script;
1687 }
1688 
1689 #define ZEND_AUTOGLOBAL_MASK_SERVER  (1 << 0)
1690 #define ZEND_AUTOGLOBAL_MASK_ENV     (1 << 1)
1691 #define ZEND_AUTOGLOBAL_MASK_REQUEST (1 << 2)
1692 
zend_accel_get_auto_globals(void)1693 static int zend_accel_get_auto_globals(void)
1694 {
1695 	int mask = 0;
1696 	if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER))) {
1697 		mask |= ZEND_AUTOGLOBAL_MASK_SERVER;
1698 	}
1699 	if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_ENV))) {
1700 		mask |= ZEND_AUTOGLOBAL_MASK_ENV;
1701 	}
1702 	if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_REQUEST))) {
1703 		mask |= ZEND_AUTOGLOBAL_MASK_REQUEST;
1704 	}
1705 	return mask;
1706 }
1707 
zend_accel_set_auto_globals(int mask)1708 static void zend_accel_set_auto_globals(int mask)
1709 {
1710 	if (mask & ZEND_AUTOGLOBAL_MASK_SERVER) {
1711 		zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER));
1712 	}
1713 	if (mask & ZEND_AUTOGLOBAL_MASK_ENV) {
1714 		zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_ENV));
1715 	}
1716 	if (mask & ZEND_AUTOGLOBAL_MASK_REQUEST) {
1717 		zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_REQUEST));
1718 	}
1719 	ZCG(auto_globals_mask) |= mask;
1720 }
1721 
replay_warnings(uint32_t num_warnings,zend_error_info ** warnings)1722 static void replay_warnings(uint32_t num_warnings, zend_error_info **warnings) {
1723 	for (uint32_t i = 0; i < num_warnings; i++) {
1724 		zend_error_info *warning = warnings[i];
1725 		zend_error_zstr_at(warning->type, warning->filename, warning->lineno, warning->message);
1726 	}
1727 }
1728 
opcache_compile_file(zend_file_handle * file_handle,int type,zend_op_array ** op_array_p)1729 static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handle, int type, zend_op_array **op_array_p)
1730 {
1731 	zend_persistent_script *new_persistent_script;
1732 	uint32_t orig_functions_count, orig_class_count;
1733 	zend_op_array *orig_active_op_array;
1734 	zval orig_user_error_handler;
1735 	zend_op_array *op_array;
1736 	bool do_bailout = false;
1737 	accel_time_t timestamp = 0;
1738 	uint32_t orig_compiler_options = 0;
1739 
1740 	/* Try to open file */
1741 	if (file_handle->type == ZEND_HANDLE_FILENAME) {
1742 		if (accelerator_orig_zend_stream_open_function(file_handle) != SUCCESS) {
1743 			*op_array_p = NULL;
1744 			if (!EG(exception)) {
1745 				if (type == ZEND_REQUIRE) {
1746 					zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
1747 				} else {
1748 					zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
1749 				}
1750 			}
1751 			return NULL;
1752 		}
1753 	}
1754 
1755 	/* check blacklist right after ensuring that file was opened */
1756 	if (file_handle->opened_path && zend_accel_blacklist_is_blacklisted(&accel_blacklist, ZSTR_VAL(file_handle->opened_path), ZSTR_LEN(file_handle->opened_path))) {
1757 		SHM_UNPROTECT();
1758 		ZCSG(blacklist_misses)++;
1759 		SHM_PROTECT();
1760 		*op_array_p = accelerator_orig_compile_file(file_handle, type);
1761 		return NULL;
1762 	}
1763 
1764 	if (ZCG(accel_directives).validate_timestamps ||
1765 	    ZCG(accel_directives).file_update_protection ||
1766 	    ZCG(accel_directives).max_file_size > 0) {
1767 		size_t size = 0;
1768 
1769 		/* Obtain the file timestamps, *before* actually compiling them,
1770 		 * otherwise we have a race-condition.
1771 		 */
1772 		timestamp = zend_get_file_handle_timestamp(file_handle, ZCG(accel_directives).max_file_size > 0 ? &size : NULL);
1773 
1774 		/* If we can't obtain a timestamp (that means file is possibly socket)
1775 		 *  we won't cache it
1776 		 */
1777 		if (timestamp == 0) {
1778 			*op_array_p = accelerator_orig_compile_file(file_handle, type);
1779 			return NULL;
1780 		}
1781 
1782 		/* check if file is too new (may be it's not written completely yet) */
1783 		if (ZCG(accel_directives).file_update_protection &&
1784 		    ((accel_time_t)(ZCG(request_time) - ZCG(accel_directives).file_update_protection) < timestamp)) {
1785 			*op_array_p = accelerator_orig_compile_file(file_handle, type);
1786 			return NULL;
1787 		}
1788 
1789 		if (ZCG(accel_directives).max_file_size > 0 && size > (size_t)ZCG(accel_directives).max_file_size) {
1790 			SHM_UNPROTECT();
1791 			ZCSG(blacklist_misses)++;
1792 			SHM_PROTECT();
1793 			*op_array_p = accelerator_orig_compile_file(file_handle, type);
1794 			return NULL;
1795 		}
1796 	}
1797 
1798 	/* Save the original values for the op_array, function table and class table */
1799 	orig_active_op_array = CG(active_op_array);
1800 	orig_functions_count = EG(function_table)->nNumUsed;
1801 	orig_class_count = EG(class_table)->nNumUsed;
1802 	ZVAL_COPY_VALUE(&orig_user_error_handler, &EG(user_error_handler));
1803 
1804 	/* Override them with ours */
1805 	ZVAL_UNDEF(&EG(user_error_handler));
1806 	if (ZCG(accel_directives).record_warnings) {
1807 		zend_begin_record_errors();
1808 	}
1809 
1810 	zend_try {
1811 		orig_compiler_options = CG(compiler_options);
1812 		CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
1813 		CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
1814 		CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
1815 		CG(compiler_options) |= ZEND_COMPILE_IGNORE_OTHER_FILES;
1816 		CG(compiler_options) |= ZEND_COMPILE_IGNORE_OBSERVER;
1817 #ifdef ZEND_WIN32
1818 		/* On Windows, don't compile with internal classes. Shm may be attached from different
1819 		 * processes with internal classes living in different addresses. */
1820 		CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES;
1821 #endif
1822 		if (ZCG(accel_directives).file_cache) {
1823 			CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
1824 			/* Don't compile with internal classes for file cache, in case some extension is removed
1825 			 * later on. We cannot assume it is there in the future. */
1826 			CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES;
1827 		}
1828 		op_array = *op_array_p = accelerator_orig_compile_file(file_handle, type);
1829 		CG(compiler_options) = orig_compiler_options;
1830 	} zend_catch {
1831 		op_array = NULL;
1832 		do_bailout = true;
1833 		CG(compiler_options) = orig_compiler_options;
1834 	} zend_end_try();
1835 
1836 	/* Restore originals */
1837 	CG(active_op_array) = orig_active_op_array;
1838 	EG(user_error_handler) = orig_user_error_handler;
1839 	EG(record_errors) = 0;
1840 
1841 	if (!op_array) {
1842 		/* compilation failed */
1843 		zend_free_recorded_errors();
1844 		if (do_bailout) {
1845 			zend_bailout();
1846 		}
1847 		return NULL;
1848 	}
1849 
1850 	/* Build the persistent_script structure.
1851 	   Here we aren't sure we would store it, but we will need it
1852 	   further anyway.
1853 	*/
1854 	new_persistent_script = create_persistent_script();
1855 	new_persistent_script->script.main_op_array = *op_array;
1856 	zend_accel_move_user_functions(CG(function_table), CG(function_table)->nNumUsed - orig_functions_count, &new_persistent_script->script);
1857 	zend_accel_move_user_classes(CG(class_table), CG(class_table)->nNumUsed - orig_class_count, &new_persistent_script->script);
1858 	zend_accel_build_delayed_early_binding_list(new_persistent_script);
1859 	new_persistent_script->num_warnings = EG(num_errors);
1860 	new_persistent_script->warnings = EG(errors);
1861 	EG(num_errors) = 0;
1862 	EG(errors) = NULL;
1863 
1864 	efree(op_array); /* we have valid persistent_script, so it's safe to free op_array */
1865 
1866 	/* Fill in the ping_auto_globals_mask for the new script. If jit for auto globals is enabled we
1867 	   will have to ping the used auto global variables before execution */
1868 	if (PG(auto_globals_jit)) {
1869 		new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals();
1870 	}
1871 
1872 	if (ZCG(accel_directives).validate_timestamps) {
1873 		/* Obtain the file timestamps, *before* actually compiling them,
1874 		 * otherwise we have a race-condition.
1875 		 */
1876 		new_persistent_script->timestamp = timestamp;
1877 		new_persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
1878 	}
1879 
1880 	if (file_handle->opened_path) {
1881 		new_persistent_script->script.filename = zend_string_copy(file_handle->opened_path);
1882 	} else {
1883 		new_persistent_script->script.filename = zend_string_copy(file_handle->filename);
1884 	}
1885 	zend_string_hash_val(new_persistent_script->script.filename);
1886 
1887 	/* Now persistent_script structure is ready in process memory */
1888 	return new_persistent_script;
1889 }
1890 
file_cache_compile_file(zend_file_handle * file_handle,int type)1891 static zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type)
1892 {
1893 	zend_persistent_script *persistent_script;
1894 	zend_op_array *op_array = NULL;
1895 	bool from_memory; /* if the script we've got is stored in SHM */
1896 
1897 	if (php_is_stream_path(ZSTR_VAL(file_handle->filename)) &&
1898 	    !is_cacheable_stream_path(ZSTR_VAL(file_handle->filename))) {
1899 		return accelerator_orig_compile_file(file_handle, type);
1900 	}
1901 
1902 	if (!file_handle->opened_path) {
1903 		if (file_handle->type == ZEND_HANDLE_FILENAME &&
1904 		    accelerator_orig_zend_stream_open_function(file_handle) == FAILURE) {
1905 			if (!EG(exception)) {
1906 				if (type == ZEND_REQUIRE) {
1907 					zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
1908 				} else {
1909 					zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
1910 				}
1911 			}
1912 			return NULL;
1913 	    }
1914 	}
1915 
1916 	HANDLE_BLOCK_INTERRUPTIONS();
1917 	SHM_UNPROTECT();
1918 	persistent_script = zend_file_cache_script_load(file_handle);
1919 	SHM_PROTECT();
1920 	HANDLE_UNBLOCK_INTERRUPTIONS();
1921 	if (persistent_script) {
1922 		/* see bug #15471 (old BTS) */
1923 		if (persistent_script->script.filename) {
1924 			if (!EG(current_execute_data) || !EG(current_execute_data)->opline ||
1925 			    !EG(current_execute_data)->func ||
1926 			    !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
1927 			    EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
1928 			    (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
1929 			     EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
1930 				if (zend_hash_add_empty_element(&EG(included_files), persistent_script->script.filename) != NULL) {
1931 					/* ext/phar has to load phar's metadata into memory */
1932 					if (persistent_script->is_phar) {
1933 						php_stream_statbuf ssb;
1934 						char *fname = emalloc(sizeof("phar://") + ZSTR_LEN(persistent_script->script.filename));
1935 
1936 						memcpy(fname, "phar://", sizeof("phar://") - 1);
1937 						memcpy(fname + sizeof("phar://") - 1, ZSTR_VAL(persistent_script->script.filename), ZSTR_LEN(persistent_script->script.filename) + 1);
1938 						php_stream_stat_path(fname, &ssb);
1939 						efree(fname);
1940 					}
1941 				}
1942 			}
1943 		}
1944 		replay_warnings(persistent_script->num_warnings, persistent_script->warnings);
1945 
1946 	    if (persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask)) {
1947 			zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask));
1948 		}
1949 
1950 		return zend_accel_load_script(persistent_script, 1);
1951 	}
1952 
1953 	persistent_script = opcache_compile_file(file_handle, type, &op_array);
1954 
1955 	if (persistent_script) {
1956 		from_memory = false;
1957 		persistent_script = cache_script_in_file_cache(persistent_script, &from_memory);
1958 		return zend_accel_load_script(persistent_script, from_memory);
1959 	}
1960 
1961 	return op_array;
1962 }
1963 
check_persistent_script_access(zend_persistent_script * persistent_script)1964 static int check_persistent_script_access(zend_persistent_script *persistent_script)
1965 {
1966 	char *phar_path, *ptr;
1967 	if ((ZSTR_LEN(persistent_script->script.filename)<sizeof("phar://.phar")) ||
1968 	    memcmp(ZSTR_VAL(persistent_script->script.filename), "phar://", sizeof("phar://")-1)) {
1969 
1970 		return access(ZSTR_VAL(persistent_script->script.filename), R_OK) != 0;
1971 
1972 	} else {
1973 		/* we got a cached file from .phar, so we have to strip prefix and path inside .phar to check access() */
1974 		phar_path = estrdup(ZSTR_VAL(persistent_script->script.filename)+sizeof("phar://")-1);
1975 		if ((ptr = strstr(phar_path, ".phar/")) != NULL)
1976 		{
1977 			*(ptr+sizeof(".phar/")-2) = 0; /* strip path inside .phar file */
1978 		}
1979 		bool ret = access(phar_path, R_OK) != 0;
1980 		efree(phar_path);
1981 		return ret;
1982 	}
1983 }
1984 
1985 /* zend_compile() replacement */
persistent_compile_file(zend_file_handle * file_handle,int type)1986 zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
1987 {
1988 	zend_persistent_script *persistent_script = NULL;
1989 	zend_string *key = NULL;
1990 	bool from_shared_memory; /* if the script we've got is stored in SHM */
1991 
1992 	if (!file_handle->filename || !ZCG(accelerator_enabled)) {
1993 		/* The Accelerator is disabled, act as if without the Accelerator */
1994 		ZCG(cache_opline) = NULL;
1995 		ZCG(cache_persistent_script) = NULL;
1996 		if (file_handle->filename
1997 		 && ZCG(accel_directives).file_cache
1998 		 && ZCG(enabled) && accel_startup_ok) {
1999 			return file_cache_compile_file(file_handle, type);
2000 		}
2001 		return accelerator_orig_compile_file(file_handle, type);
2002 	} else if (file_cache_only) {
2003 		ZCG(cache_opline) = NULL;
2004 		ZCG(cache_persistent_script) = NULL;
2005 		return file_cache_compile_file(file_handle, type);
2006 	} else if ((ZCSG(restart_in_progress) && accel_restart_is_active())) {
2007 		if (ZCG(accel_directives).file_cache) {
2008 			return file_cache_compile_file(file_handle, type);
2009 		}
2010 		ZCG(cache_opline) = NULL;
2011 		ZCG(cache_persistent_script) = NULL;
2012 		return accelerator_orig_compile_file(file_handle, type);
2013 	}
2014 
2015 	/* In case this callback is called from include_once, require_once or it's
2016 	 * a main FastCGI request, the key must be already calculated, and cached
2017 	 * persistent script already found */
2018 	if (ZCG(cache_persistent_script) &&
2019 	    ((!EG(current_execute_data) &&
2020 	      file_handle->primary_script &&
2021 	      ZCG(cache_opline) == NULL) ||
2022 	     (EG(current_execute_data) &&
2023 	      EG(current_execute_data)->func &&
2024 	      ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
2025 	      ZCG(cache_opline) == EG(current_execute_data)->opline))) {
2026 
2027 		persistent_script = ZCG(cache_persistent_script);
2028 		if (ZSTR_LEN(&ZCG(key))) {
2029 			key = &ZCG(key);
2030 		}
2031 
2032 	} else {
2033 		if (!ZCG(accel_directives).revalidate_path) {
2034 			/* try to find cached script by key */
2035 			key = accel_make_persistent_key(file_handle->filename);
2036 			if (!key) {
2037 				ZCG(cache_opline) = NULL;
2038 				ZCG(cache_persistent_script) = NULL;
2039 				return accelerator_orig_compile_file(file_handle, type);
2040 			}
2041 			persistent_script = zend_accel_hash_find(&ZCSG(hash), key);
2042 		} else if (UNEXPECTED(php_is_stream_path(ZSTR_VAL(file_handle->filename)) && !is_cacheable_stream_path(ZSTR_VAL(file_handle->filename)))) {
2043 			ZCG(cache_opline) = NULL;
2044 			ZCG(cache_persistent_script) = NULL;
2045 			return accelerator_orig_compile_file(file_handle, type);
2046 		}
2047 
2048 		if (!persistent_script) {
2049 			/* try to find cached script by full real path */
2050 			zend_accel_hash_entry *bucket;
2051 
2052 			/* open file to resolve the path */
2053 		    if (file_handle->type == ZEND_HANDLE_FILENAME
2054 		     && accelerator_orig_zend_stream_open_function(file_handle) == FAILURE) {
2055 				if (!EG(exception)) {
2056 					if (type == ZEND_REQUIRE) {
2057 						zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
2058 					} else {
2059 						zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
2060 					}
2061 				}
2062 				return NULL;
2063 		    }
2064 
2065 			if (file_handle->opened_path) {
2066 				bucket = zend_accel_hash_find_entry(&ZCSG(hash), file_handle->opened_path);
2067 
2068 				if (bucket) {
2069 					persistent_script = (zend_persistent_script *)bucket->data;
2070 
2071 					if (key && !persistent_script->corrupted) {
2072 						HANDLE_BLOCK_INTERRUPTIONS();
2073 						SHM_UNPROTECT();
2074 						zend_shared_alloc_lock();
2075 						zend_accel_add_key(key, bucket);
2076 						zend_shared_alloc_unlock();
2077 						SHM_PROTECT();
2078 						HANDLE_UNBLOCK_INTERRUPTIONS();
2079 					}
2080 				}
2081 			}
2082 		}
2083 	}
2084 
2085 	/* clear cache */
2086 	ZCG(cache_opline) = NULL;
2087 	ZCG(cache_persistent_script) = NULL;
2088 
2089 	if (persistent_script && persistent_script->corrupted) {
2090 		persistent_script = NULL;
2091 	}
2092 
2093 	/* Make sure we only increase the currently running processes semaphore
2094      * once each execution (this function can be called more than once on
2095      * each execution)
2096      */
2097 	if (!ZCG(counted)) {
2098 		if (accel_activate_add() == FAILURE) {
2099 			if (ZCG(accel_directives).file_cache) {
2100 				return file_cache_compile_file(file_handle, type);
2101 			}
2102 			return accelerator_orig_compile_file(file_handle, type);
2103 		}
2104 		ZCG(counted) = true;
2105 	}
2106 
2107 	/* Revalidate accessibility of cached file */
2108 	if (EXPECTED(persistent_script != NULL) &&
2109 	    UNEXPECTED(ZCG(accel_directives).validate_permission) &&
2110 	    file_handle->type == ZEND_HANDLE_FILENAME &&
2111 	    UNEXPECTED(check_persistent_script_access(persistent_script))) {
2112 		if (!EG(exception)) {
2113 			if (type == ZEND_REQUIRE) {
2114 				zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
2115 			} else {
2116 				zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
2117 			}
2118 		}
2119 		return NULL;
2120 	}
2121 
2122 	HANDLE_BLOCK_INTERRUPTIONS();
2123 	SHM_UNPROTECT();
2124 
2125 	/* If script is found then validate_timestamps if option is enabled */
2126 	if (persistent_script && ZCG(accel_directives).validate_timestamps) {
2127 		if (validate_timestamp_and_record(persistent_script, file_handle) == FAILURE) {
2128 			zend_accel_lock_discard_script(persistent_script);
2129 			persistent_script = NULL;
2130 		}
2131 	}
2132 
2133 	/* Check the second level cache */
2134 	if (!persistent_script && ZCG(accel_directives).file_cache) {
2135 		persistent_script = zend_file_cache_script_load(file_handle);
2136 	}
2137 
2138 	/* If script was not found or invalidated by validate_timestamps */
2139 	if (!persistent_script) {
2140 		uint32_t old_const_num = zend_hash_next_free_element(EG(zend_constants));
2141 		zend_op_array *op_array;
2142 
2143 		/* Cache miss.. */
2144 		ZCSG(misses)++;
2145 
2146 		/* No memory left. Behave like without the Accelerator */
2147 		if (ZSMMG(memory_exhausted) || ZCSG(restart_pending)) {
2148 			SHM_PROTECT();
2149 			HANDLE_UNBLOCK_INTERRUPTIONS();
2150 			if (ZCG(accel_directives).file_cache) {
2151 				return file_cache_compile_file(file_handle, type);
2152 			}
2153 			return accelerator_orig_compile_file(file_handle, type);
2154 		}
2155 
2156 		SHM_PROTECT();
2157 		HANDLE_UNBLOCK_INTERRUPTIONS();
2158 		persistent_script = opcache_compile_file(file_handle, type, &op_array);
2159 		HANDLE_BLOCK_INTERRUPTIONS();
2160 		SHM_UNPROTECT();
2161 
2162 		/* Try and cache the script and assume that it is returned from_shared_memory.
2163 		 * If it isn't compile_and_cache_file() changes the flag to 0
2164 		 */
2165 		from_shared_memory = false;
2166 		if (persistent_script) {
2167 			persistent_script = cache_script_in_shared_memory(persistent_script, key, &from_shared_memory);
2168 		}
2169 
2170 		/* Caching is disabled, returning op_array;
2171 		 * or something went wrong during compilation, returning NULL
2172 		 */
2173 		if (!persistent_script) {
2174 			SHM_PROTECT();
2175 			HANDLE_UNBLOCK_INTERRUPTIONS();
2176 			return op_array;
2177 		}
2178 		if (from_shared_memory) {
2179 			/* Delete immutable arrays moved into SHM */
2180 			uint32_t new_const_num = zend_hash_next_free_element(EG(zend_constants));
2181 			while (new_const_num > old_const_num) {
2182 				new_const_num--;
2183 				zend_hash_index_del(EG(zend_constants), new_const_num);
2184 			}
2185 		}
2186 		persistent_script->dynamic_members.last_used = ZCG(request_time);
2187 		SHM_PROTECT();
2188 		HANDLE_UNBLOCK_INTERRUPTIONS();
2189 	} else {
2190 
2191 #ifndef ZEND_WIN32
2192 		ZCSG(hits)++; /* TBFixed: may lose one hit */
2193 		persistent_script->dynamic_members.hits++; /* see above */
2194 #else
2195 #ifdef ZEND_ENABLE_ZVAL_LONG64
2196 		InterlockedIncrement64(&ZCSG(hits));
2197 		InterlockedIncrement64(&persistent_script->dynamic_members.hits);
2198 #else
2199 		InterlockedIncrement(&ZCSG(hits));
2200 		InterlockedIncrement(&persistent_script->dynamic_members.hits);
2201 #endif
2202 #endif
2203 
2204 		/* see bug #15471 (old BTS) */
2205 		if (persistent_script->script.filename) {
2206 			if (!EG(current_execute_data) ||
2207 			    !EG(current_execute_data)->func ||
2208 			    !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
2209 			    !EG(current_execute_data)->opline ||
2210 			    EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
2211 			    (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
2212 			     EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
2213 				if (zend_hash_add_empty_element(&EG(included_files), persistent_script->script.filename) != NULL) {
2214 					/* ext/phar has to load phar's metadata into memory */
2215 					if (persistent_script->is_phar) {
2216 						php_stream_statbuf ssb;
2217 						char *fname = emalloc(sizeof("phar://") + ZSTR_LEN(persistent_script->script.filename));
2218 
2219 						memcpy(fname, "phar://", sizeof("phar://") - 1);
2220 						memcpy(fname + sizeof("phar://") - 1, ZSTR_VAL(persistent_script->script.filename), ZSTR_LEN(persistent_script->script.filename) + 1);
2221 						php_stream_stat_path(fname, &ssb);
2222 						efree(fname);
2223 					}
2224 				}
2225 			}
2226 		}
2227 		persistent_script->dynamic_members.last_used = ZCG(request_time);
2228 		SHM_PROTECT();
2229 		HANDLE_UNBLOCK_INTERRUPTIONS();
2230 
2231 		replay_warnings(persistent_script->num_warnings, persistent_script->warnings);
2232 		from_shared_memory = true;
2233 	}
2234 
2235 	/* Fetch jit auto globals used in the script before execution */
2236 	if (persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask)) {
2237 		zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask));
2238 	}
2239 
2240 	return zend_accel_load_script(persistent_script, from_shared_memory);
2241 }
2242 
zend_accel_inheritance_cache_find(zend_inheritance_cache_entry * entry,zend_class_entry * ce,zend_class_entry * parent,zend_class_entry ** traits_and_interfaces,bool * needs_autoload_ptr)2243 static zend_always_inline zend_inheritance_cache_entry* zend_accel_inheritance_cache_find(zend_inheritance_cache_entry *entry, zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, bool *needs_autoload_ptr)
2244 {
2245 	uint32_t i;
2246 
2247 	ZEND_ASSERT(ce->ce_flags & ZEND_ACC_IMMUTABLE);
2248 	ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
2249 
2250 	while (entry) {
2251 		bool found = true;
2252 		bool needs_autoload = false;
2253 
2254 		if (entry->parent != parent) {
2255 			found = false;
2256 		} else {
2257 			for (i = 0; i < ce->num_traits + ce->num_interfaces; i++) {
2258 				if (entry->traits_and_interfaces[i] != traits_and_interfaces[i]) {
2259 					found = false;
2260 					break;
2261 				}
2262 			}
2263 			if (found && entry->dependencies) {
2264 				for (i = 0; i < entry->dependencies_count; i++) {
2265 					zend_class_entry *ce = zend_lookup_class_ex(entry->dependencies[i].name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
2266 
2267 					if (ce != entry->dependencies[i].ce) {
2268 						if (!ce) {
2269 							needs_autoload = true;
2270 						} else {
2271 							found = false;
2272 							break;
2273 						}
2274 					}
2275 				}
2276 			}
2277 		}
2278 		if (found) {
2279 			*needs_autoload_ptr = needs_autoload;
2280 			return entry;
2281 		}
2282 		entry = entry->next;
2283 	}
2284 
2285 	return NULL;
2286 }
2287 
zend_accel_inheritance_cache_get(zend_class_entry * ce,zend_class_entry * parent,zend_class_entry ** traits_and_interfaces)2288 static zend_class_entry* zend_accel_inheritance_cache_get(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces)
2289 {
2290 	uint32_t i;
2291 	bool needs_autoload;
2292 	zend_inheritance_cache_entry *entry = ce->inheritance_cache;
2293 
2294 	while (entry) {
2295 		entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload);
2296 		if (entry) {
2297 			if (!needs_autoload) {
2298 				replay_warnings(entry->num_warnings, entry->warnings);
2299 				if (ZCSG(map_ptr_last) > CG(map_ptr_last)) {
2300 					zend_map_ptr_extend(ZCSG(map_ptr_last));
2301 				}
2302 				ce = entry->ce;
2303 				if (ZSTR_HAS_CE_CACHE(ce->name)) {
2304 					ZSTR_SET_CE_CACHE_EX(ce->name, ce, 0);
2305 				}
2306 				return ce;
2307 			}
2308 
2309 			for (i = 0; i < entry->dependencies_count; i++) {
2310 				zend_class_entry *ce = zend_lookup_class_ex(entry->dependencies[i].name, NULL, 0);
2311 
2312 				if (ce == NULL) {
2313 					return NULL;
2314 				}
2315 			}
2316 		}
2317 	}
2318 
2319 	return NULL;
2320 }
2321 
zend_accel_inheritance_cache_add(zend_class_entry * ce,zend_class_entry * proto,zend_class_entry * parent,zend_class_entry ** traits_and_interfaces,HashTable * dependencies)2322 static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies)
2323 {
2324 	zend_persistent_script dummy;
2325 	size_t size;
2326 	uint32_t i;
2327 	bool needs_autoload;
2328 	zend_class_entry *new_ce;
2329 	zend_inheritance_cache_entry *entry;
2330 
2331 	ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_IMMUTABLE));
2332 	ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
2333 
2334 	if (!ZCG(accelerator_enabled) ||
2335 	    (ZCSG(restart_in_progress) && accel_restart_is_active())) {
2336 		return NULL;
2337 	}
2338 
2339 	if (traits_and_interfaces && dependencies) {
2340 		for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
2341 			if (traits_and_interfaces[i]) {
2342 				zend_hash_del(dependencies, traits_and_interfaces[i]->name);
2343 			}
2344 		}
2345 	}
2346 
2347 	SHM_UNPROTECT();
2348 	zend_shared_alloc_lock();
2349 
2350 	entry = proto->inheritance_cache;
2351 	while (entry) {
2352 		entry = zend_accel_inheritance_cache_find(entry, proto, parent, traits_and_interfaces, &needs_autoload);
2353 		if (entry) {
2354 			zend_shared_alloc_unlock();
2355 			SHM_PROTECT();
2356 			if (!needs_autoload) {
2357 				zend_map_ptr_extend(ZCSG(map_ptr_last));
2358 				return entry->ce;
2359 			} else {
2360 				return NULL;
2361 			}
2362 		}
2363 	}
2364 
2365 	zend_shared_alloc_init_xlat_table();
2366 
2367 	memset(&dummy, 0, sizeof(dummy));
2368 	dummy.size = ZEND_ALIGNED_SIZE(
2369 		sizeof(zend_inheritance_cache_entry) -
2370 		sizeof(void*) +
2371 		(sizeof(void*) * (proto->num_traits + proto->num_interfaces)));
2372 	if (dependencies) {
2373 		dummy.size += ZEND_ALIGNED_SIZE(zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency));
2374 	}
2375 	ZCG(current_persistent_script) = &dummy;
2376 	zend_persist_class_entry_calc(ce);
2377 	zend_persist_warnings_calc(EG(num_errors), EG(errors));
2378 	size = dummy.size;
2379 
2380 	zend_shared_alloc_clear_xlat_table();
2381 
2382 #if ZEND_MM_NEED_EIGHT_BYTE_REALIGNMENT
2383 	/* Align to 8-byte boundary */
2384 	ZCG(mem) = zend_shared_alloc(size + 8);
2385 #else
2386 	ZCG(mem) = zend_shared_alloc(size);
2387 #endif
2388 
2389 	if (!ZCG(mem)) {
2390 		zend_shared_alloc_destroy_xlat_table();
2391 		zend_shared_alloc_unlock();
2392 		SHM_PROTECT();
2393 		return NULL;
2394 	}
2395 
2396 	zend_map_ptr_extend(ZCSG(map_ptr_last));
2397 
2398 #if ZEND_MM_NEED_EIGHT_BYTE_REALIGNMENT
2399 	/* Align to 8-byte boundary */
2400 	ZCG(mem) = (void*)(((uintptr_t)ZCG(mem) + 7L) & ~7L);
2401 #endif
2402 
2403 	memset(ZCG(mem), 0, size);
2404 	entry = (zend_inheritance_cache_entry*)ZCG(mem);
2405 	ZCG(mem) = (char*)ZCG(mem) +
2406 		ZEND_ALIGNED_SIZE(
2407 			(sizeof(zend_inheritance_cache_entry) -
2408 			 sizeof(void*) +
2409 			 (sizeof(void*) * (proto->num_traits + proto->num_interfaces))));
2410 	entry->parent = parent;
2411 	for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
2412 		entry->traits_and_interfaces[i] = traits_and_interfaces[i];
2413 	}
2414 	if (dependencies && zend_hash_num_elements(dependencies)) {
2415 		zend_string *dep_name;
2416 		zend_class_entry *dep_ce;
2417 
2418 		i = 0;
2419 		entry->dependencies_count = zend_hash_num_elements(dependencies);
2420 		entry->dependencies = (zend_class_dependency*)ZCG(mem);
2421 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(dependencies, dep_name, dep_ce) {
2422 #if ZEND_DEBUG
2423 			ZEND_ASSERT(zend_accel_in_shm(dep_name));
2424 #endif
2425 			entry->dependencies[i].name = dep_name;
2426 			entry->dependencies[i].ce = dep_ce;
2427 			i++;
2428 		} ZEND_HASH_FOREACH_END();
2429 		ZCG(mem) = (char*)ZCG(mem) + zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency);
2430 	}
2431 
2432 	/* See GH-15657: `zend_persist_class_entry` can JIT property hook code via
2433 	 * `zend_persist_property_info`, but the inheritance cache should not
2434 	 * JIT those at this point in time. */
2435 #ifdef HAVE_JIT
2436 	bool jit_on_old = JIT_G(on);
2437 	JIT_G(on) = false;
2438 #endif
2439 
2440 	entry->ce = new_ce = zend_persist_class_entry(ce);
2441 	zend_update_parent_ce(new_ce);
2442 
2443 #ifdef HAVE_JIT
2444 	JIT_G(on) = jit_on_old;
2445 #endif
2446 
2447 	entry->num_warnings = EG(num_errors);
2448 	entry->warnings = zend_persist_warnings(EG(num_errors), EG(errors));
2449 	entry->next = proto->inheritance_cache;
2450 	proto->inheritance_cache = entry;
2451 
2452 	EG(num_errors) = 0;
2453 	EG(errors) = NULL;
2454 
2455 	ZCSG(map_ptr_last) = CG(map_ptr_last);
2456 
2457 	zend_shared_alloc_destroy_xlat_table();
2458 
2459 	zend_shared_alloc_unlock();
2460 	SHM_PROTECT();
2461 
2462 	/* Consistency check */
2463 	if ((char*)entry + size != (char*)ZCG(mem)) {
2464 		zend_accel_error(
2465 			((char*)entry + size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
2466 			"Internal error: wrong class size calculation: %s start=" ZEND_ADDR_FMT ", end=" ZEND_ADDR_FMT ", real=" ZEND_ADDR_FMT "\n",
2467 			ZSTR_VAL(ce->name),
2468 			(size_t)entry,
2469 			(size_t)((char *)entry + size),
2470 			(size_t)ZCG(mem));
2471 	}
2472 
2473 	zend_map_ptr_extend(ZCSG(map_ptr_last));
2474 
2475 	return new_ce;
2476 }
2477 
2478 #ifdef ZEND_WIN32
accel_gen_uname_id(void)2479 static zend_result accel_gen_uname_id(void)
2480 {
2481 	PHP_MD5_CTX ctx;
2482 	unsigned char digest[16];
2483 	wchar_t uname[UNLEN + 1];
2484 	DWORD unsize = UNLEN;
2485 
2486 	if (!GetUserNameW(uname, &unsize)) {
2487 		return FAILURE;
2488 	}
2489 	PHP_MD5Init(&ctx);
2490 	PHP_MD5Update(&ctx, (void *) uname, (unsize - 1) * sizeof(wchar_t));
2491 	PHP_MD5Update(&ctx, ZCG(accel_directives).cache_id, strlen(ZCG(accel_directives).cache_id));
2492 	PHP_MD5Final(digest, &ctx);
2493 	php_hash_bin2hex(accel_uname_id, digest, sizeof digest);
2494 	return SUCCESS;
2495 }
2496 #endif
2497 
2498 /* zend_stream_open_function() replacement for PHP 5.3 and above */
persistent_stream_open_function(zend_file_handle * handle)2499 static zend_result persistent_stream_open_function(zend_file_handle *handle)
2500 {
2501 	if (ZCG(cache_persistent_script)) {
2502 		/* check if callback is called from include_once or it's a main request */
2503 		if ((!EG(current_execute_data) &&
2504 		     handle->primary_script &&
2505 		     ZCG(cache_opline) == NULL) ||
2506 		    (EG(current_execute_data) &&
2507 		     EG(current_execute_data)->func &&
2508 		     ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
2509 		     ZCG(cache_opline) == EG(current_execute_data)->opline)) {
2510 
2511 			/* we are in include_once or FastCGI request */
2512 			handle->opened_path = zend_string_copy(ZCG(cache_persistent_script)->script.filename);
2513 			return SUCCESS;
2514 		}
2515 		ZCG(cache_opline) = NULL;
2516 		ZCG(cache_persistent_script) = NULL;
2517 	}
2518 	return accelerator_orig_zend_stream_open_function(handle);
2519 }
2520 
2521 /* zend_resolve_path() replacement for PHP 5.3 and above */
persistent_zend_resolve_path(zend_string * filename)2522 static zend_string* persistent_zend_resolve_path(zend_string *filename)
2523 {
2524 	if (!file_cache_only &&
2525 	    ZCG(accelerator_enabled)) {
2526 
2527 		/* check if callback is called from include_once or it's a main request */
2528 		if ((!EG(current_execute_data)) ||
2529 		    (EG(current_execute_data) &&
2530 		     EG(current_execute_data)->func &&
2531 		     ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
2532 		     EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
2533 		     (EG(current_execute_data)->opline->extended_value == ZEND_INCLUDE_ONCE ||
2534 		      EG(current_execute_data)->opline->extended_value == ZEND_REQUIRE_ONCE))) {
2535 
2536 			/* we are in include_once or FastCGI request */
2537 			zend_string *resolved_path;
2538 			zend_string *key = NULL;
2539 
2540 			if (!ZCG(accel_directives).revalidate_path) {
2541 				/* lookup by "not-real" path */
2542 				key = accel_make_persistent_key(filename);
2543 				if (key) {
2544 					zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), key);
2545 					if (bucket != NULL) {
2546 						zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
2547 						if (!persistent_script->corrupted) {
2548 							ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
2549 							ZCG(cache_persistent_script) = persistent_script;
2550 							return zend_string_copy(persistent_script->script.filename);
2551 						}
2552 					}
2553 				} else {
2554 					ZCG(cache_opline) = NULL;
2555 					ZCG(cache_persistent_script) = NULL;
2556 					return accelerator_orig_zend_resolve_path(filename);
2557 				}
2558 			}
2559 
2560 			/* find the full real path */
2561 			resolved_path = accelerator_orig_zend_resolve_path(filename);
2562 
2563 			if (resolved_path) {
2564 				/* lookup by real path */
2565 				zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path);
2566 				if (bucket) {
2567 					zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
2568 					if (!persistent_script->corrupted) {
2569 						if (key) {
2570 							/* add another "key" for the same bucket */
2571 							HANDLE_BLOCK_INTERRUPTIONS();
2572 							SHM_UNPROTECT();
2573 							zend_shared_alloc_lock();
2574 							zend_accel_add_key(key, bucket);
2575 							zend_shared_alloc_unlock();
2576 							SHM_PROTECT();
2577 							HANDLE_UNBLOCK_INTERRUPTIONS();
2578 						} else {
2579 							ZSTR_LEN(&ZCG(key)) = 0;
2580 						}
2581 						ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
2582 						ZCG(cache_persistent_script) = persistent_script;
2583 						return resolved_path;
2584 					}
2585 				}
2586 			}
2587 
2588 			ZCG(cache_opline) = NULL;
2589 			ZCG(cache_persistent_script) = NULL;
2590 			return resolved_path;
2591 		}
2592 	}
2593 	ZCG(cache_opline) = NULL;
2594 	ZCG(cache_persistent_script) = NULL;
2595 	return accelerator_orig_zend_resolve_path(filename);
2596 }
2597 
zend_reset_cache_vars(void)2598 static void zend_reset_cache_vars(void)
2599 {
2600 	ZSMMG(memory_exhausted) = false;
2601 	ZCSG(hits) = 0;
2602 	ZCSG(misses) = 0;
2603 	ZCSG(blacklist_misses) = 0;
2604 	ZSMMG(wasted_shared_memory) = 0;
2605 	ZCSG(restart_pending) = false;
2606 	ZCSG(force_restart_time) = 0;
2607 	ZCSG(map_ptr_last) = CG(map_ptr_last);
2608 }
2609 
accel_reset_pcre_cache(void)2610 static void accel_reset_pcre_cache(void)
2611 {
2612 	Bucket *p;
2613 
2614 	ZEND_HASH_MAP_FOREACH_BUCKET(&PCRE_G(pcre_cache), p) {
2615 		/* Remove PCRE cache entries with inconsistent keys */
2616 		if (zend_accel_in_shm(p->key)) {
2617 			p->key = NULL;
2618 			zend_hash_del_bucket(&PCRE_G(pcre_cache), p);
2619 		}
2620 	} ZEND_HASH_FOREACH_END();
2621 }
2622 
accel_activate(INIT_FUNC_ARGS)2623 zend_result accel_activate(INIT_FUNC_ARGS)
2624 {
2625 	if (!ZCG(enabled) || !accel_startup_ok) {
2626 		ZCG(accelerator_enabled) = false;
2627 		return SUCCESS;
2628 	}
2629 
2630 	/* PHP-5.4 and above return "double", but we use 1 sec precision */
2631 	ZCG(auto_globals_mask) = 0;
2632 	ZCG(request_time) = (time_t)sapi_get_request_time();
2633 	ZCG(cache_opline) = NULL;
2634 	ZCG(cache_persistent_script) = NULL;
2635 	ZCG(include_path_key_len) = 0;
2636 	ZCG(include_path_check) = true;
2637 
2638 	ZCG(cwd) = NULL;
2639 	ZCG(cwd_key_len) = 0;
2640 	ZCG(cwd_check) = true;
2641 
2642 	if (file_cache_only) {
2643 		ZCG(accelerator_enabled) = false;
2644 		return SUCCESS;
2645 	}
2646 
2647 #ifndef ZEND_WIN32
2648 	if (ZCG(accel_directives).validate_root) {
2649 		struct stat buf;
2650 
2651 		if (stat("/", &buf) != 0) {
2652 			ZCG(root_hash) = 0;
2653 		} else {
2654 			ZCG(root_hash) = buf.st_ino;
2655 			if (sizeof(buf.st_ino) > sizeof(ZCG(root_hash))) {
2656 				if (ZCG(root_hash) != buf.st_ino) {
2657 					zend_string *key = ZSTR_INIT_LITERAL("opcache.enable", 0);
2658 					zend_alter_ini_entry_chars(key, "0", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_RUNTIME);
2659 					zend_string_release_ex(key, 0);
2660 					zend_accel_error(ACCEL_LOG_WARNING, "Can't cache files in chroot() directory with too big inode");
2661 					return SUCCESS;
2662 				}
2663 			}
2664 		}
2665 	} else {
2666 		ZCG(root_hash) = 0;
2667 	}
2668 #endif
2669 
2670 	HANDLE_BLOCK_INTERRUPTIONS();
2671 	SHM_UNPROTECT();
2672 
2673 	if (ZCG(counted)) {
2674 #ifdef ZTS
2675 		zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for thread id %lu", (unsigned long) tsrm_thread_id());
2676 #else
2677 		zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for pid %d", getpid());
2678 #endif
2679 		accel_unlock_all();
2680 		ZCG(counted) = false;
2681 	}
2682 
2683 	if (ZCSG(restart_pending)) {
2684 		zend_shared_alloc_lock();
2685 		if (ZCSG(restart_pending)) { /* check again, to ensure that the cache wasn't already cleaned by another process */
2686 			if (accel_is_inactive()) {
2687 				zend_accel_error(ACCEL_LOG_DEBUG, "Restarting!");
2688 				ZCSG(restart_pending) = false;
2689 				switch ZCSG(restart_reason) {
2690 					case ACCEL_RESTART_OOM:
2691 						ZCSG(oom_restarts)++;
2692 						break;
2693 					case ACCEL_RESTART_HASH:
2694 						ZCSG(hash_restarts)++;
2695 						break;
2696 					case ACCEL_RESTART_USER:
2697 						ZCSG(manual_restarts)++;
2698 						break;
2699 				}
2700 				accel_restart_enter();
2701 
2702 				zend_map_ptr_reset();
2703 				zend_reset_cache_vars();
2704 				zend_accel_hash_clean(&ZCSG(hash));
2705 
2706 				if (ZCG(accel_directives).interned_strings_buffer) {
2707 					accel_interned_strings_restore_state();
2708 				}
2709 
2710 				zend_shared_alloc_restore_state();
2711 				if (ZCSG(preload_script)) {
2712 					preload_restart();
2713 				}
2714 
2715 #ifdef HAVE_JIT
2716 				zend_jit_restart();
2717 #endif
2718 
2719 				ZCSG(accelerator_enabled) = ZCSG(cache_status_before_restart);
2720 				if (ZCSG(last_restart_time) < ZCG(request_time)) {
2721 					ZCSG(last_restart_time) = ZCG(request_time);
2722 				} else {
2723 					ZCSG(last_restart_time)++;
2724 				}
2725 				accel_restart_leave();
2726 			}
2727 		}
2728 		zend_shared_alloc_unlock();
2729 	}
2730 
2731 	ZCG(accelerator_enabled) = ZCSG(accelerator_enabled);
2732 
2733 	SHM_PROTECT();
2734 	HANDLE_UNBLOCK_INTERRUPTIONS();
2735 
2736 	if (ZCG(accelerator_enabled) && ZCSG(last_restart_time) != ZCG(last_restart_time)) {
2737 		/* SHM was reinitialized. */
2738 		ZCG(last_restart_time) = ZCSG(last_restart_time);
2739 
2740 		/* Reset in-process realpath cache */
2741 		realpath_cache_clean();
2742 
2743 		accel_reset_pcre_cache();
2744 		ZCG(pcre_reseted) = false;
2745 	} else if (!ZCG(accelerator_enabled) && !ZCG(pcre_reseted)) {
2746 		accel_reset_pcre_cache();
2747 		ZCG(pcre_reseted) = true;
2748 	}
2749 
2750 
2751 #ifdef HAVE_JIT
2752 	zend_jit_activate();
2753 #endif
2754 
2755 	if (ZCSG(preload_script)) {
2756 		preload_activate();
2757 	}
2758 
2759 	return SUCCESS;
2760 }
2761 
2762 #ifdef HAVE_JIT
accel_deactivate(void)2763 void accel_deactivate(void)
2764 {
2765 	zend_jit_deactivate();
2766 }
2767 #endif
2768 
accel_post_deactivate(void)2769 zend_result accel_post_deactivate(void)
2770 {
2771 	if (ZCG(cwd)) {
2772 		zend_string_release_ex(ZCG(cwd), 0);
2773 		ZCG(cwd) = NULL;
2774 	}
2775 
2776 	if (!ZCG(enabled) || !accel_startup_ok) {
2777 		return SUCCESS;
2778 	}
2779 
2780 	zend_shared_alloc_safe_unlock(); /* be sure we didn't leave cache locked */
2781 	accel_unlock_all();
2782 	ZCG(counted) = false;
2783 
2784 	return SUCCESS;
2785 }
2786 
accelerator_remove_cb(zend_extension * element1,zend_extension * element2)2787 static int accelerator_remove_cb(zend_extension *element1, zend_extension *element2)
2788 {
2789 	(void)element2; /* keep the compiler happy */
2790 
2791 	if (!strcmp(element1->name, ACCELERATOR_PRODUCT_NAME )) {
2792 		element1->startup = NULL;
2793 #if 0
2794 		/* We have to call shutdown callback it to free TS resources */
2795 		element1->shutdown = NULL;
2796 #endif
2797 		element1->activate = NULL;
2798 		element1->deactivate = NULL;
2799 		element1->op_array_handler = NULL;
2800 
2801 #ifdef __DEBUG_MESSAGES__
2802 		fprintf(stderr, ACCELERATOR_PRODUCT_NAME " is disabled: %s\n", (zps_failure_reason ? zps_failure_reason : "unknown error"));
2803 		fflush(stderr);
2804 #endif
2805 	}
2806 
2807 	return 0;
2808 }
2809 
zps_startup_failure(const char * reason,const char * api_reason,int (* cb)(zend_extension *,zend_extension *))2810 static void zps_startup_failure(const char *reason, const char *api_reason, int (*cb)(zend_extension *, zend_extension *))
2811 {
2812 	accel_startup_ok = false;
2813 	zps_failure_reason = reason;
2814 	zps_api_failure_reason = api_reason?api_reason:reason;
2815 	zend_llist_del_element(&zend_extensions, NULL, (int (*)(void *, void *))cb);
2816 }
2817 
accel_find_sapi(void)2818 static inline zend_result accel_find_sapi(void)
2819 {
2820 	static const char *supported_sapis[] = {
2821 		"apache",
2822 		"fastcgi",
2823 		"cli-server",
2824 		"cgi-fcgi",
2825 		"fpm-fcgi",
2826 		"fpmi-fcgi",
2827 		"apache2handler",
2828 		"litespeed",
2829 		"uwsgi",
2830 		"fuzzer",
2831 		"frankenphp",
2832 		"ngx-php",
2833 		NULL
2834 	};
2835 	const char **sapi_name;
2836 
2837 	if (sapi_module.name) {
2838 		for (sapi_name = supported_sapis; *sapi_name; sapi_name++) {
2839 			if (strcmp(sapi_module.name, *sapi_name) == 0) {
2840 				return SUCCESS;
2841 			}
2842 		}
2843 		if (ZCG(accel_directives).enable_cli && (
2844 		    strcmp(sapi_module.name, "cli") == 0
2845 		  || strcmp(sapi_module.name, "phpdbg") == 0)) {
2846 			return SUCCESS;
2847 		}
2848 	}
2849 
2850 	return FAILURE;
2851 }
2852 
zend_accel_init_shm(void)2853 static zend_result zend_accel_init_shm(void)
2854 {
2855 	int i;
2856 	size_t accel_shared_globals_size;
2857 
2858 	zend_shared_alloc_lock();
2859 
2860 	if (ZCG(accel_directives).interned_strings_buffer) {
2861 		accel_shared_globals_size = sizeof(zend_accel_shared_globals) + ZCG(accel_directives).interned_strings_buffer * 1024 * 1024;
2862 	} else {
2863 		/* Make sure there is always at least one interned string hash slot,
2864 		 * so the table can be queried unconditionally. */
2865 		accel_shared_globals_size = sizeof(zend_accel_shared_globals) + sizeof(zend_string_table_pos_t);
2866 	}
2867 
2868 	accel_shared_globals = zend_shared_alloc(accel_shared_globals_size);
2869 	if (!accel_shared_globals) {
2870 		zend_shared_alloc_unlock();
2871 		zend_accel_error_noreturn(ACCEL_LOG_FATAL,
2872 				"Insufficient shared memory for interned strings buffer! (tried to allocate %zu bytes)",
2873 				accel_shared_globals_size);
2874 		return FAILURE;
2875 	}
2876 	memset(accel_shared_globals, 0, sizeof(zend_accel_shared_globals));
2877 	ZSMMG(app_shared_globals) = accel_shared_globals;
2878 
2879 	zend_accel_hash_init(&ZCSG(hash), ZCG(accel_directives).max_accelerated_files);
2880 
2881 	if (ZCG(accel_directives).interned_strings_buffer) {
2882 		uint32_t hash_size;
2883 
2884 		/* must be a power of two */
2885 		hash_size = ZCG(accel_directives).interned_strings_buffer * (32 * 1024);
2886 		hash_size |= (hash_size >> 1);
2887 		hash_size |= (hash_size >> 2);
2888 		hash_size |= (hash_size >> 4);
2889 		hash_size |= (hash_size >> 8);
2890 		hash_size |= (hash_size >> 16);
2891 
2892 		ZCSG(interned_strings).nTableMask =
2893 			hash_size * sizeof(zend_string_table_pos_t);
2894 		ZCSG(interned_strings).nNumOfElements = 0;
2895 		ZCSG(interned_strings).start =
2896 			(zend_string*)((char*)&ZCSG(interned_strings) +
2897 				sizeof(zend_string_table) +
2898 				((hash_size + 1) * sizeof(zend_string_table_pos_t))) +
2899 				8;
2900 		ZEND_ASSERT(((uintptr_t)ZCSG(interned_strings).start & 0x7) == 0); /* should be 8 byte aligned */
2901 
2902 		ZCSG(interned_strings).top =
2903 			ZCSG(interned_strings).start;
2904 		ZCSG(interned_strings).end =
2905 			(zend_string*)((char*)(accel_shared_globals + 1) + /* table data is stored after accel_shared_globals */
2906 				ZCG(accel_directives).interned_strings_buffer * 1024 * 1024);
2907 		ZEND_ASSERT(((uintptr_t)ZCSG(interned_strings).end - (uintptr_t)&ZCSG(interned_strings)) / ZEND_STRING_TABLE_POS_ALIGNMENT < ZEND_STRING_TABLE_POS_MAX);
2908 		ZCSG(interned_strings).saved_top = NULL;
2909 
2910 		memset((char*)&ZCSG(interned_strings) + sizeof(zend_string_table),
2911 			STRTAB_INVALID_POS,
2912 			(char*)ZCSG(interned_strings).start -
2913 				((char*)&ZCSG(interned_strings) + sizeof(zend_string_table)));
2914 	} else {
2915 		*STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), 0) = STRTAB_INVALID_POS;
2916 	}
2917 
2918 	/* We can reuse init_interned_string_for_php for the "init_existing_interned" case,
2919 	 * because the function does not create new interned strings at runtime. */
2920 	zend_interned_strings_set_request_storage_handlers(
2921 		accel_new_interned_string_for_php,
2922 		accel_init_interned_string_for_php,
2923 		accel_init_interned_string_for_php);
2924 
2925 	zend_reset_cache_vars();
2926 
2927 	ZCSG(oom_restarts) = 0;
2928 	ZCSG(hash_restarts) = 0;
2929 	ZCSG(manual_restarts) = 0;
2930 
2931 	ZCSG(accelerator_enabled) = true;
2932 	ZCSG(start_time) = zend_accel_get_time();
2933 	ZCSG(last_restart_time) = 0;
2934 	ZCSG(restart_in_progress) = false;
2935 
2936 	for (i = 0; i < -HT_MIN_MASK; i++) {
2937 		ZCSG(uninitialized_bucket)[i] = HT_INVALID_IDX;
2938 	}
2939 
2940 	zend_shared_alloc_unlock();
2941 
2942 	return SUCCESS;
2943 }
2944 
accel_globals_ctor(zend_accel_globals * accel_globals)2945 static void accel_globals_ctor(zend_accel_globals *accel_globals)
2946 {
2947 #if defined(COMPILE_DL_OPCACHE) && defined(ZTS)
2948 	ZEND_TSRMLS_CACHE_UPDATE();
2949 #endif
2950 	memset(accel_globals, 0, sizeof(zend_accel_globals));
2951 }
2952 
2953 #ifdef HAVE_HUGE_CODE_PAGES
2954 # ifndef _WIN32
2955 #  include <sys/mman.h>
2956 #  ifndef MAP_ANON
2957 #   ifdef MAP_ANONYMOUS
2958 #    define MAP_ANON MAP_ANONYMOUS
2959 #   endif
2960 #  endif
2961 #  ifndef MAP_FAILED
2962 #   define MAP_FAILED ((void*)-1)
2963 #  endif
2964 #  ifdef MAP_ALIGNED_SUPER
2965 #   include <sys/types.h>
2966 #   include <sys/sysctl.h>
2967 #   include <sys/user.h>
2968 #   define MAP_HUGETLB MAP_ALIGNED_SUPER
2969 #  endif
2970 # endif
2971 
2972 # if defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE)
accel_remap_huge_pages(void * start,size_t size,size_t real_size,const char * name,size_t offset)2973 static zend_result accel_remap_huge_pages(void *start, size_t size, size_t real_size, const char *name, size_t offset)
2974 {
2975 	void *ret = MAP_FAILED;
2976 	void *mem;
2977 
2978 	mem = mmap(NULL, size,
2979 		PROT_READ | PROT_WRITE,
2980 		MAP_PRIVATE | MAP_ANONYMOUS,
2981 		-1, 0);
2982 	if (mem == MAP_FAILED) {
2983 		zend_error(E_WARNING,
2984 			ACCELERATOR_PRODUCT_NAME " huge_code_pages: mmap failed: %s (%d)",
2985 			strerror(errno), errno);
2986 		return FAILURE;
2987 	}
2988 	memcpy(mem, start, real_size);
2989 
2990 #  ifdef MAP_HUGETLB
2991 	ret = mmap(start, size,
2992 		PROT_READ | PROT_WRITE | PROT_EXEC,
2993 		MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_HUGETLB,
2994 		-1, 0);
2995 #  endif
2996 	if (ret == MAP_FAILED) {
2997 		ret = mmap(start, size,
2998 			PROT_READ | PROT_WRITE | PROT_EXEC,
2999 			MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
3000 			-1, 0);
3001 		/* this should never happen? */
3002 		ZEND_ASSERT(ret != MAP_FAILED);
3003 #  ifdef MADV_HUGEPAGE
3004 		if (-1 == madvise(start, size, MADV_HUGEPAGE)) {
3005 			memcpy(start, mem, real_size);
3006 			mprotect(start, size, PROT_READ | PROT_EXEC);
3007 			munmap(mem, size);
3008 			zend_error(E_WARNING,
3009 				ACCELERATOR_PRODUCT_NAME " huge_code_pages: madvise(HUGEPAGE) failed: %s (%d)",
3010 				strerror(errno), errno);
3011 			return FAILURE;
3012 		}
3013 #  else
3014 		memcpy(start, mem, real_size);
3015 		mprotect(start, size, PROT_READ | PROT_EXEC);
3016 		munmap(mem, size);
3017 		zend_error(E_WARNING,
3018 			ACCELERATOR_PRODUCT_NAME " huge_code_pages: mmap(HUGETLB) failed: %s (%d)",
3019 			strerror(errno), errno);
3020 		return FAILURE;
3021 #  endif
3022 	}
3023 
3024 	// Given the MAP_FIXED flag the address can never diverge
3025 	ZEND_ASSERT(ret == start);
3026 	zend_mmap_set_name(start, size, "zend_huge_code_pages");
3027 	memcpy(start, mem, real_size);
3028 	mprotect(start, size, PROT_READ | PROT_EXEC);
3029 
3030 	munmap(mem, size);
3031 
3032 	return SUCCESS;
3033 }
3034 
accel_move_code_to_huge_pages(void)3035 static void accel_move_code_to_huge_pages(void)
3036 {
3037 #if defined(__linux__)
3038 	FILE *f;
3039 	long unsigned int huge_page_size = 2 * 1024 * 1024;
3040 
3041 	f = fopen("/proc/self/maps", "r");
3042 	if (f) {
3043 		long unsigned int  start, end, offset, inode;
3044 		char perm[5], dev[10], name[MAXPATHLEN];
3045 		int ret;
3046 		extern char *__progname;
3047 		char buffer[MAXPATHLEN];
3048 
3049 		while (fgets(buffer, MAXPATHLEN, f)) {
3050 			ret = sscanf(buffer, "%lx-%lx %4s %lx %9s %lu %s\n", &start, &end, perm, &offset, dev, &inode, name);
3051 			if (ret >= 6) {
3052 				/* try to find the php text segment and map it into huge pages
3053 				   Lines without 'name' are going to be skipped */
3054 				if (ret > 6 && perm[0] == 'r' && perm[1] == '-' && perm[2] == 'x' && name[0] == '/' \
3055 					&& strstr(name, __progname)) {
3056 					long unsigned int  seg_start = ZEND_MM_ALIGNED_SIZE_EX(start, huge_page_size);
3057 					long unsigned int  seg_end = (end & ~(huge_page_size-1L));
3058 					long unsigned int  real_end;
3059 
3060 					ret = fscanf(f, "%lx-", &start);
3061 					if (ret == 1 && start == seg_end + huge_page_size) {
3062 						real_end = end;
3063 						seg_end = start;
3064 					} else {
3065 						real_end = seg_end;
3066 					}
3067 
3068 					if (seg_end > seg_start) {
3069 						zend_accel_error(ACCEL_LOG_DEBUG, "remap to huge page %lx-%lx %s \n", seg_start, seg_end, name);
3070 						accel_remap_huge_pages((void*)seg_start, seg_end - seg_start, real_end - seg_start, name, offset + seg_start - start);
3071 					}
3072 					break;
3073 				}
3074 			}
3075 		}
3076 		fclose(f);
3077 	}
3078 #elif defined(__FreeBSD__)
3079 	size_t s = 0;
3080 	int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
3081 	long unsigned int huge_page_size = 2 * 1024 * 1024;
3082 	if (sysctl(mib, 4, NULL, &s, NULL, 0) == 0) {
3083 		s = s * 4 / 3;
3084 		void *addr = mmap(NULL, s, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
3085 		if (addr != MAP_FAILED) {
3086 			if (sysctl(mib, 4, addr, &s, NULL, 0) == 0) {
3087 				uintptr_t start = (uintptr_t)addr;
3088 				uintptr_t end = start + s;
3089 				while (start < end) {
3090 					struct kinfo_vmentry *entry = (struct kinfo_vmentry *)start;
3091 					size_t sz = entry->kve_structsize;
3092 					if (sz == 0) {
3093 						break;
3094 					}
3095 					int permflags = entry->kve_protection;
3096 					if ((permflags & KVME_PROT_READ) && !(permflags & KVME_PROT_WRITE) &&
3097 					    (permflags & KVME_PROT_EXEC) && entry->kve_path[0] != '\0') {
3098 						long unsigned int seg_start = ZEND_MM_ALIGNED_SIZE_EX(start, huge_page_size);
3099 						long unsigned int seg_end = (end & ~(huge_page_size-1L));
3100 						if (seg_end > seg_start) {
3101 							zend_accel_error(ACCEL_LOG_DEBUG, "remap to huge page %lx-%lx %s \n", seg_start, seg_end, entry->kve_path);
3102 							accel_remap_huge_pages((void*)seg_start, seg_end - seg_start, seg_end - seg_start, entry->kve_path, entry->kve_offset + seg_start - start);
3103 							// First relevant segment found is our binary
3104 							break;
3105 						}
3106 					}
3107 					start += sz;
3108 				}
3109 			}
3110 			munmap(addr, s);
3111 		}
3112 	}
3113 #endif
3114 }
3115 # else
accel_move_code_to_huge_pages(void)3116 static void accel_move_code_to_huge_pages(void)
3117 {
3118 	zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages has no affect as huge page is not supported");
3119 	return;
3120 }
3121 # endif /* defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE) */
3122 #endif /* HAVE_HUGE_CODE_PAGES */
3123 
accel_startup(zend_extension * extension)3124 static int accel_startup(zend_extension *extension)
3125 {
3126 #ifdef ZTS
3127 	accel_globals_id = ts_allocate_id(&accel_globals_id, sizeof(zend_accel_globals), (ts_allocate_ctor) accel_globals_ctor, NULL);
3128 #else
3129 	accel_globals_ctor(&accel_globals);
3130 #endif
3131 
3132 #ifdef HAVE_JIT
3133 	zend_jit_init();
3134 #endif
3135 
3136 #ifdef ZEND_WIN32
3137 # if !defined(__has_feature) || !__has_feature(address_sanitizer)
3138 	_setmaxstdio(2048); /* The default configuration is limited to 512 stdio files */
3139 # endif
3140 #endif
3141 
3142 	if (start_accel_module() == FAILURE) {
3143 		accel_startup_ok = false;
3144 		zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": module registration failed!");
3145 		return FAILURE;
3146 	}
3147 
3148 #ifdef ZEND_WIN32
3149 	if (UNEXPECTED(accel_gen_uname_id() == FAILURE)) {
3150 		zps_startup_failure("Unable to get user name", NULL, accelerator_remove_cb);
3151 		return SUCCESS;
3152 	}
3153 #endif
3154 
3155 #ifdef HAVE_HUGE_CODE_PAGES
3156 	if (ZCG(accel_directives).huge_code_pages &&
3157 	    (strcmp(sapi_module.name, "cli") == 0 ||
3158 	     strcmp(sapi_module.name, "cli-server") == 0 ||
3159 		 strcmp(sapi_module.name, "cgi-fcgi") == 0 ||
3160 		 strcmp(sapi_module.name, "fpm-fcgi") == 0)) {
3161 		accel_move_code_to_huge_pages();
3162 	}
3163 #endif
3164 
3165 	/* no supported SAPI found - disable acceleration and stop initialization */
3166 	if (accel_find_sapi() == FAILURE) {
3167 		accel_startup_ok = false;
3168 		if (!ZCG(accel_directives).enable_cli &&
3169 		    strcmp(sapi_module.name, "cli") == 0) {
3170 			zps_startup_failure("Opcode Caching is disabled for CLI", NULL, accelerator_remove_cb);
3171 		} else {
3172 			zps_startup_failure("Opcode Caching is only supported in Apache, FPM, FastCGI, FrankenPHP, LiteSpeed and uWSGI SAPIs", NULL, accelerator_remove_cb);
3173 		}
3174 		return SUCCESS;
3175 	}
3176 
3177 	if (ZCG(enabled) == 0) {
3178 		return SUCCESS ;
3179 	}
3180 
3181 	orig_post_startup_cb = zend_post_startup_cb;
3182 	zend_post_startup_cb = accel_post_startup;
3183 
3184 	/* Prevent unloading */
3185 	extension->handle = 0;
3186 
3187 	return SUCCESS;
3188 }
3189 
accel_post_startup(void)3190 static zend_result accel_post_startup(void)
3191 {
3192 	zend_function *func;
3193 	zend_ini_entry *ini_entry;
3194 
3195 	if (orig_post_startup_cb) {
3196 		zend_result (*cb)(void) = orig_post_startup_cb;
3197 
3198 		orig_post_startup_cb = NULL;
3199 		if (cb() != SUCCESS) {
3200 			return FAILURE;
3201 		}
3202 	}
3203 
3204 /********************************************/
3205 /* End of non-SHM dependent initializations */
3206 /********************************************/
3207 	file_cache_only = ZCG(accel_directives).file_cache_only;
3208 	if (!file_cache_only) {
3209 		size_t shm_size = ZCG(accel_directives).memory_consumption;
3210 #ifdef HAVE_JIT
3211 		size_t jit_size = 0;
3212 		bool reattached = false;
3213 
3214 		if (JIT_G(enabled) && JIT_G(buffer_size)
3215 		 && zend_jit_check_support() == SUCCESS) {
3216 			size_t page_size;
3217 
3218 			page_size = zend_get_page_size();
3219 			if (!page_size || (page_size & (page_size - 1))) {
3220 				zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can't get page size.");
3221 				abort();
3222 			}
3223 			jit_size = JIT_G(buffer_size);
3224 			jit_size = ZEND_MM_ALIGNED_SIZE_EX(jit_size, page_size);
3225 			shm_size += jit_size;
3226 		}
3227 
3228 		switch (zend_shared_alloc_startup(shm_size, jit_size)) {
3229 #else
3230 		switch (zend_shared_alloc_startup(shm_size, 0)) {
3231 #endif
3232 			case ALLOC_SUCCESS:
3233 				if (zend_accel_init_shm() == FAILURE) {
3234 					accel_startup_ok = false;
3235 					return FAILURE;
3236 				}
3237 				break;
3238 			case ALLOC_FAILURE:
3239 				accel_startup_ok = false;
3240 				zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
3241 				return SUCCESS;
3242 			case SUCCESSFULLY_REATTACHED:
3243 #ifdef HAVE_JIT
3244 				reattached = true;
3245 #endif
3246 				zend_shared_alloc_lock();
3247 				accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals);
3248 				zend_interned_strings_set_request_storage_handlers(
3249 					accel_new_interned_string_for_php,
3250 					accel_init_interned_string_for_php,
3251 					accel_init_interned_string_for_php);
3252 				zend_shared_alloc_unlock();
3253 				break;
3254 			case FAILED_REATTACHED:
3255 				accel_startup_ok = false;
3256 				zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - cannot reattach to exiting shared memory.");
3257 				return SUCCESS;
3258 				break;
3259 #if ENABLE_FILE_CACHE_FALLBACK
3260 			case ALLOC_FALLBACK:
3261 				zend_shared_alloc_lock();
3262 				file_cache_only = true;
3263 				fallback_process = true;
3264 				zend_shared_alloc_unlock();
3265 				goto file_cache_fallback;
3266 				break;
3267 #endif
3268 		}
3269 
3270 		/* from this point further, shared memory is supposed to be OK */
3271 
3272 		/* remember the last restart time in the process memory */
3273 		ZCG(last_restart_time) = ZCSG(last_restart_time);
3274 
3275 		zend_shared_alloc_lock();
3276 #ifdef HAVE_JIT
3277 		if (JIT_G(enabled)) {
3278 			if (JIT_G(buffer_size) == 0) {
3279 				JIT_G(enabled) = false;
3280 				JIT_G(on) = false;
3281 			} else if (!ZSMMG(reserved)) {
3282 				zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not use reserved buffer!");
3283 			} else {
3284 				zend_jit_startup(ZSMMG(reserved), jit_size, reattached);
3285 				zend_jit_startup_ok = true;
3286 			}
3287 		}
3288 #endif
3289 		zend_shared_alloc_save_state();
3290 		zend_shared_alloc_unlock();
3291 
3292 		SHM_PROTECT();
3293 	} else if (!ZCG(accel_directives).file_cache) {
3294 		accel_startup_ok = false;
3295 		zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache_only is set without a proper setting of opcache.file_cache");
3296 		return SUCCESS;
3297 	} else {
3298 #ifdef HAVE_JIT
3299 		JIT_G(enabled) = false;
3300 		JIT_G(on) = false;
3301 #endif
3302 		accel_shared_globals = calloc(1, sizeof(zend_accel_shared_globals));
3303 	}
3304 #if ENABLE_FILE_CACHE_FALLBACK
3305 file_cache_fallback:
3306 #endif
3307 
3308 	/* Override compiler */
3309 	accelerator_orig_compile_file = zend_compile_file;
3310 	zend_compile_file = persistent_compile_file;
3311 
3312 	/* Override stream opener function (to eliminate open() call caused by
3313 	 * include/require statements ) */
3314 	accelerator_orig_zend_stream_open_function = zend_stream_open_function;
3315 	zend_stream_open_function = persistent_stream_open_function;
3316 
3317 	/* Override path resolver function (to eliminate stat() calls caused by
3318 	 * include_once/require_once statements */
3319 	accelerator_orig_zend_resolve_path = zend_resolve_path;
3320 	zend_resolve_path = persistent_zend_resolve_path;
3321 
3322 	/* Override chdir() function */
3323 	if ((func = zend_hash_str_find_ptr(CG(function_table), "chdir", sizeof("chdir")-1)) != NULL &&
3324 	    func->type == ZEND_INTERNAL_FUNCTION) {
3325 		orig_chdir = func->internal_function.handler;
3326 		func->internal_function.handler = ZEND_FN(accel_chdir);
3327 	}
3328 	ZCG(cwd) = NULL;
3329 	ZCG(include_path) = NULL;
3330 
3331 	/* Override "include_path" modifier callback */
3332 	if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
3333 		ZCG(include_path) = ini_entry->value;
3334 		orig_include_path_on_modify = ini_entry->on_modify;
3335 		ini_entry->on_modify = accel_include_path_on_modify;
3336 	}
3337 
3338 	accel_startup_ok = true;
3339 
3340 	/* Override file_exists(), is_file() and is_readable() */
3341 	zend_accel_override_file_functions();
3342 
3343 	/* Load black list */
3344 	accel_blacklist.entries = NULL;
3345 	if (ZCG(enabled) && accel_startup_ok &&
3346 	    ZCG(accel_directives).user_blacklist_filename &&
3347 	    *ZCG(accel_directives.user_blacklist_filename)) {
3348 		zend_accel_blacklist_init(&accel_blacklist);
3349 		zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename));
3350 	}
3351 
3352 	if (!file_cache_only && ZCG(accel_directives).interned_strings_buffer) {
3353 		accel_use_shm_interned_strings();
3354 	}
3355 
3356 	if (accel_finish_startup() != SUCCESS) {
3357 		return FAILURE;
3358 	}
3359 
3360 	if (ZCG(enabled) && accel_startup_ok) {
3361 		/* Override inheritance cache callbaks */
3362 		accelerator_orig_inheritance_cache_get = zend_inheritance_cache_get;
3363 		accelerator_orig_inheritance_cache_add = zend_inheritance_cache_add;
3364 		zend_inheritance_cache_get = zend_accel_inheritance_cache_get;
3365 		zend_inheritance_cache_add = zend_accel_inheritance_cache_add;
3366 	}
3367 
3368 	return SUCCESS;
3369 }
3370 
3371 static void (*orig_post_shutdown_cb)(void);
3372 
3373 static void accel_post_shutdown(void)
3374 {
3375 	zend_shared_alloc_shutdown();
3376 }
3377 
3378 void accel_shutdown(void)
3379 {
3380 	zend_ini_entry *ini_entry;
3381 	bool _file_cache_only = false;
3382 
3383 #ifdef HAVE_JIT
3384 	zend_jit_shutdown();
3385 #endif
3386 
3387 	zend_accel_blacklist_shutdown(&accel_blacklist);
3388 
3389 	if (!ZCG(enabled) || !accel_startup_ok) {
3390 #ifdef ZTS
3391 		ts_free_id(accel_globals_id);
3392 #endif
3393 		return;
3394 	}
3395 
3396 	if (ZCSG(preload_script)) {
3397 		preload_shutdown();
3398 	}
3399 
3400 	_file_cache_only = file_cache_only;
3401 
3402 	accel_reset_pcre_cache();
3403 
3404 #ifdef ZTS
3405 	ts_free_id(accel_globals_id);
3406 #endif
3407 
3408 	if (!_file_cache_only) {
3409 		/* Delay SHM detach */
3410 		orig_post_shutdown_cb = zend_post_shutdown_cb;
3411 		zend_post_shutdown_cb = accel_post_shutdown;
3412 	} else {
3413 		free(accel_shared_globals);
3414 	}
3415 
3416 	zend_compile_file = accelerator_orig_compile_file;
3417 	zend_inheritance_cache_get = accelerator_orig_inheritance_cache_get;
3418 	zend_inheritance_cache_add = accelerator_orig_inheritance_cache_add;
3419 
3420 	if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
3421 		ini_entry->on_modify = orig_include_path_on_modify;
3422 	}
3423 }
3424 
3425 void zend_accel_schedule_restart(zend_accel_restart_reason reason)
3426 {
3427 	const char *zend_accel_restart_reason_text[ACCEL_RESTART_USER + 1] = {
3428 		"out of memory",
3429 		"hash overflow",
3430 		"user",
3431 	};
3432 
3433 	if (ZCSG(restart_pending)) {
3434 		/* don't schedule twice */
3435 		return;
3436 	}
3437 
3438 	if (UNEXPECTED(zend_accel_schedule_restart_hook)) {
3439 		zend_accel_schedule_restart_hook(reason);
3440 	}
3441 
3442 	zend_accel_error(ACCEL_LOG_DEBUG, "Restart Scheduled! Reason: %s",
3443 			zend_accel_restart_reason_text[reason]);
3444 
3445 	HANDLE_BLOCK_INTERRUPTIONS();
3446 	SHM_UNPROTECT();
3447 	ZCSG(restart_pending) = true;
3448 	ZCSG(restart_reason) = reason;
3449 	ZCSG(cache_status_before_restart) = ZCSG(accelerator_enabled);
3450 	ZCSG(accelerator_enabled) = false;
3451 
3452 	if (ZCG(accel_directives).force_restart_timeout) {
3453 		ZCSG(force_restart_time) = zend_accel_get_time() + ZCG(accel_directives).force_restart_timeout;
3454 	} else {
3455 		ZCSG(force_restart_time) = 0;
3456 	}
3457 	SHM_PROTECT();
3458 	HANDLE_UNBLOCK_INTERRUPTIONS();
3459 }
3460 
3461 static void accel_deactivate_now(void)
3462 {
3463 	/* this is needed because on WIN32 lock is not decreased unless ZCG(counted) is set */
3464 #ifdef ZEND_WIN32
3465 	ZCG(counted) = true;
3466 #endif
3467 	accel_deactivate_sub();
3468 }
3469 
3470 /* ensures it is OK to read SHM
3471 	if it's not OK (restart in progress) returns FAILURE
3472 	if OK returns SUCCESS
3473 	MUST call accelerator_shm_read_unlock after done lock operations
3474 */
3475 zend_result accelerator_shm_read_lock(void)
3476 {
3477 	if (ZCG(counted)) {
3478 		/* counted means we are holding read lock for SHM, so that nothing bad can happen */
3479 		return SUCCESS;
3480 	} else {
3481 		/* here accelerator is active but we do not hold SHM lock. This means restart was scheduled
3482 			or is in progress now */
3483 		if (accel_activate_add() == FAILURE) { /* acquire usage lock */
3484 			return FAILURE;
3485 		}
3486 		/* Now if we weren't inside restart, restart would not begin until we remove usage lock */
3487 		if (ZCSG(restart_in_progress)) {
3488 			/* we already were inside restart this means it's not safe to touch shm */
3489 			accel_deactivate_now(); /* drop usage lock */
3490 			return FAILURE;
3491 		}
3492 		ZCG(counted) = true;
3493 	}
3494 	return SUCCESS;
3495 }
3496 
3497 /* must be called ONLY after SUCCESSFUL accelerator_shm_read_lock */
3498 void accelerator_shm_read_unlock(void)
3499 {
3500 	if (!ZCG(counted)) {
3501 		/* counted is false - meaning we had to readlock manually, release readlock now */
3502 		accel_deactivate_now();
3503 	}
3504 }
3505 
3506 /* Preloading */
3507 static HashTable *preload_scripts = NULL;
3508 static zend_op_array *(*preload_orig_compile_file)(zend_file_handle *file_handle, int type);
3509 
3510 static void preload_shutdown(void)
3511 {
3512 	zval *zv;
3513 
3514 #if 0
3515 	if (EG(zend_constants)) {
3516 		ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(zend_constants), zv) {
3517 			zend_constant *c = Z_PTR_P(zv);
3518 			if (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) {
3519 				break;
3520 			}
3521 		} ZEND_HASH_MAP_FOREACH_END_DEL();
3522 	}
3523 #endif
3524 
3525 	if (EG(function_table)) {
3526 		ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(function_table), zv) {
3527 			zend_function *func = Z_PTR_P(zv);
3528 			if (func->type == ZEND_INTERNAL_FUNCTION) {
3529 				break;
3530 			}
3531 		} ZEND_HASH_MAP_FOREACH_END_DEL();
3532 	}
3533 
3534 	if (EG(class_table)) {
3535 		ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(class_table), zv) {
3536 			zend_class_entry *ce = Z_PTR_P(zv);
3537 			if (ce->type == ZEND_INTERNAL_CLASS) {
3538 				break;
3539 			}
3540 		} ZEND_HASH_MAP_FOREACH_END_DEL();
3541 	}
3542 }
3543 
3544 static void preload_activate(void)
3545 {
3546 	if (ZCSG(preload_script)->ping_auto_globals_mask & ~ZCG(auto_globals_mask)) {
3547 		zend_accel_set_auto_globals(ZCSG(preload_script)->ping_auto_globals_mask & ~ZCG(auto_globals_mask));
3548 	}
3549 }
3550 
3551 static void preload_restart(void)
3552 {
3553 	zend_accel_hash_update(&ZCSG(hash), ZCSG(preload_script)->script.filename, 0, ZCSG(preload_script));
3554 	if (ZCSG(saved_scripts)) {
3555 		zend_persistent_script **p = ZCSG(saved_scripts);
3556 		while (*p) {
3557 			zend_accel_hash_update(&ZCSG(hash), (*p)->script.filename, 0, *p);
3558 			p++;
3559 		}
3560 	}
3561 }
3562 
3563 static size_t preload_try_strip_filename(zend_string *filename) {
3564 	/*FIXME: better way to handle eval()'d code? see COMPILED_STRING_DESCRIPTION_FORMAT */
3565 	if (ZSTR_LEN(filename) > sizeof(" eval()'d code")
3566 		&& *(ZSTR_VAL(filename) + ZSTR_LEN(filename) - sizeof(" eval()'d code")) == ':') {
3567 		const char *cfilename = ZSTR_VAL(filename);
3568 		size_t cfilenamelen = ZSTR_LEN(filename) - sizeof(" eval()'d code") - 1 /*:*/;
3569 		while (cfilenamelen && cfilename[--cfilenamelen] != '(');
3570 		return cfilenamelen;
3571 	}
3572 	return 0;
3573 }
3574 
3575 static void preload_move_user_functions(HashTable *src, HashTable *dst)
3576 {
3577 	Bucket *p;
3578 	dtor_func_t orig_dtor = src->pDestructor;
3579 	zend_string *filename = NULL;
3580 	bool copy = false;
3581 
3582 	src->pDestructor = NULL;
3583 	zend_hash_extend(dst, dst->nNumUsed + src->nNumUsed, 0);
3584 	ZEND_HASH_MAP_REVERSE_FOREACH_BUCKET(src, p) {
3585 		zend_function *function = Z_PTR(p->val);
3586 
3587 		if (EXPECTED(function->type == ZEND_USER_FUNCTION)) {
3588 			if (function->op_array.filename != filename) {
3589 				filename = function->op_array.filename;
3590 				if (filename) {
3591 					if (!(copy = zend_hash_exists(preload_scripts, filename))) {
3592 						size_t eval_len = preload_try_strip_filename(filename);
3593 						if (eval_len) {
3594 							copy = zend_hash_str_exists(preload_scripts, ZSTR_VAL(filename), eval_len);
3595 						}
3596 					}
3597 				} else {
3598 					copy = false;
3599 				}
3600 			}
3601 			if (copy) {
3602 				_zend_hash_append_ptr(dst, p->key, function);
3603 			} else {
3604 				orig_dtor(&p->val);
3605 			}
3606 			zend_hash_del_bucket(src, p);
3607 		} else {
3608 			break;
3609 		}
3610 	} ZEND_HASH_FOREACH_END();
3611 	src->pDestructor = orig_dtor;
3612 }
3613 
3614 static void preload_move_user_classes(HashTable *src, HashTable *dst)
3615 {
3616 	Bucket *p;
3617 	dtor_func_t orig_dtor = src->pDestructor;
3618 	zend_string *filename = NULL;
3619 	bool copy = false;
3620 
3621 	src->pDestructor = NULL;
3622 	zend_hash_extend(dst, dst->nNumUsed + src->nNumUsed, 0);
3623 	ZEND_HASH_MAP_FOREACH_BUCKET_FROM(src, p, EG(persistent_classes_count)) {
3624 		zend_class_entry *ce = Z_PTR(p->val);
3625 		ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
3626 		if (ce->info.user.filename != filename) {
3627 			filename = ce->info.user.filename;
3628 			if (filename) {
3629 				if (!(copy = zend_hash_exists(preload_scripts, filename))) {
3630 					size_t eval_len = preload_try_strip_filename(filename);
3631 					if (eval_len) {
3632 						copy = zend_hash_str_exists(preload_scripts, ZSTR_VAL(filename), eval_len);
3633 					}
3634 				}
3635 			} else {
3636 				copy = false;
3637 			}
3638 		}
3639 		if (copy) {
3640 			_zend_hash_append(dst, p->key, &p->val);
3641 		} else {
3642 			orig_dtor(&p->val);
3643 		}
3644 		zend_hash_del_bucket(src, p);
3645 	} ZEND_HASH_FOREACH_END();
3646 	src->pDestructor = orig_dtor;
3647 }
3648 
3649 static zend_op_array *preload_compile_file(zend_file_handle *file_handle, int type)
3650 {
3651 	zend_op_array *op_array = preload_orig_compile_file(file_handle, type);
3652 
3653 	if (op_array && op_array->refcount) {
3654 		zend_persistent_script *script;
3655 
3656 		script = create_persistent_script();
3657 		script->script.filename = zend_string_copy(op_array->filename);
3658 		zend_string_hash_val(script->script.filename);
3659 		script->script.main_op_array = *op_array;
3660 
3661 //???		efree(op_array->refcount);
3662 		op_array->refcount = NULL;
3663 
3664 		zend_hash_add_ptr(preload_scripts, script->script.filename, script);
3665 	}
3666 
3667 	return op_array;
3668 }
3669 
3670 static void preload_sort_classes(void *base, size_t count, size_t siz, compare_func_t compare, swap_func_t swp)
3671 {
3672 	Bucket *b1 = base;
3673 	Bucket *b2;
3674 	Bucket *end = b1 + count;
3675 	Bucket tmp;
3676 	zend_class_entry *ce, *p;
3677 
3678 	while (b1 < end) {
3679 try_again:
3680 		ce = (zend_class_entry*)Z_PTR(b1->val);
3681 		if (ce->parent && (ce->ce_flags & ZEND_ACC_LINKED)) {
3682 			p = ce->parent;
3683 			if (p->type == ZEND_USER_CLASS) {
3684 				b2 = b1 + 1;
3685 				while (b2 < end) {
3686 					if (p ==  Z_PTR(b2->val)) {
3687 						tmp = *b1;
3688 						*b1 = *b2;
3689 						*b2 = tmp;
3690 						goto try_again;
3691 					}
3692 					b2++;
3693 				}
3694 			}
3695 		}
3696 		if (ce->num_interfaces && (ce->ce_flags & ZEND_ACC_LINKED)) {
3697 			uint32_t i = 0;
3698 			for (i = 0; i < ce->num_interfaces; i++) {
3699 				p = ce->interfaces[i];
3700 				if (p->type == ZEND_USER_CLASS) {
3701 					b2 = b1 + 1;
3702 					while (b2 < end) {
3703 						if (p ==  Z_PTR(b2->val)) {
3704 							tmp = *b1;
3705 							*b1 = *b2;
3706 							*b2 = tmp;
3707 							goto try_again;
3708 						}
3709 						b2++;
3710 					}
3711 				}
3712 			}
3713 		}
3714 		b1++;
3715 	}
3716 }
3717 
3718 typedef struct {
3719 	const char *kind;
3720 	const char *name;
3721 } preload_error;
3722 
3723 static zend_result preload_resolve_deps(preload_error *error, const zend_class_entry *ce)
3724 {
3725 	memset(error, 0, sizeof(preload_error));
3726 
3727 	if (ce->parent_name) {
3728 		zend_string *key = zend_string_tolower(ce->parent_name);
3729 		zend_class_entry *parent = zend_hash_find_ptr(EG(class_table), key);
3730 		zend_string_release(key);
3731 		if (!parent) {
3732 			error->kind = "Unknown parent ";
3733 			error->name = ZSTR_VAL(ce->parent_name);
3734 			return FAILURE;
3735 		}
3736 	}
3737 
3738 	if (ce->num_interfaces) {
3739 		for (uint32_t i = 0; i < ce->num_interfaces; i++) {
3740 			zend_class_entry *interface =
3741 				zend_hash_find_ptr(EG(class_table), ce->interface_names[i].lc_name);
3742 			if (!interface) {
3743 				error->kind = "Unknown interface ";
3744 				error->name = ZSTR_VAL(ce->interface_names[i].name);
3745 				return FAILURE;
3746 			}
3747 		}
3748 	}
3749 
3750 	if (ce->num_traits) {
3751 		for (uint32_t i = 0; i < ce->num_traits; i++) {
3752 			zend_class_entry *trait =
3753 				zend_hash_find_ptr(EG(class_table), ce->trait_names[i].lc_name);
3754 			if (!trait) {
3755 				error->kind = "Unknown trait ";
3756 				error->name = ZSTR_VAL(ce->trait_names[i].name);
3757 				return FAILURE;
3758 			}
3759 		}
3760 	}
3761 
3762 	return SUCCESS;
3763 }
3764 
3765 static bool preload_try_resolve_constants(zend_class_entry *ce)
3766 {
3767 	bool ok, changed, was_changed = false;
3768 	zend_class_constant *c;
3769 	zval *val;
3770 	zend_string *key;
3771 
3772 	EG(exception) = (void*)(uintptr_t)-1; /* prevent error reporting */
3773 	do {
3774 		ok = true;
3775 		changed = false;
3776 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
3777 			val = &c->value;
3778 			if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
3779 				if (EXPECTED(zend_update_class_constant(c, key, c->ce) == SUCCESS)) {
3780 					was_changed = changed = true;
3781 				} else {
3782 					ok = false;
3783 				}
3784 			}
3785 		} ZEND_HASH_FOREACH_END();
3786 		if (ok) {
3787 			ce->ce_flags &= ~ZEND_ACC_HAS_AST_CONSTANTS;
3788 		}
3789 		if (ce->default_properties_count) {
3790 			uint32_t i;
3791 			bool resolved = true;
3792 
3793 			for (i = 0; i < ce->default_properties_count; i++) {
3794 				val = &ce->default_properties_table[i];
3795 				if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
3796 					zend_property_info *prop = ce->properties_info_table[i];
3797 					if (UNEXPECTED(zval_update_constant_ex(val, prop->ce) != SUCCESS)) {
3798 						resolved = ok = false;
3799 					}
3800 				}
3801 			}
3802 			if (resolved) {
3803 				ce->ce_flags &= ~ZEND_ACC_HAS_AST_PROPERTIES;
3804 			}
3805 		}
3806 		if (ce->default_static_members_count) {
3807 			uint32_t count = ce->parent ? ce->default_static_members_count - ce->parent->default_static_members_count : ce->default_static_members_count;
3808 			bool resolved = true;
3809 
3810 			val = ce->default_static_members_table + ce->default_static_members_count - 1;
3811 			while (count) {
3812 				if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
3813 					if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) {
3814 						resolved = ok = false;
3815 					}
3816 				}
3817 				val--;
3818 				count--;
3819 			}
3820 			if (resolved) {
3821 				ce->ce_flags &= ~ZEND_ACC_HAS_AST_STATICS;
3822 			}
3823 		}
3824 	} while (changed && !ok);
3825 	EG(exception) = NULL;
3826 	CG(in_compilation) = false;
3827 
3828 	if (ok) {
3829 		ce->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
3830 	}
3831 
3832 	return ok || was_changed;
3833 }
3834 
3835 static void (*orig_error_cb)(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message);
3836 
3837 static void preload_error_cb(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message)
3838 {
3839 	/* Suppress printing of the error, only bail out for fatal errors. */
3840 	if (type & E_FATAL_ERRORS) {
3841 		zend_bailout();
3842 	}
3843 }
3844 
3845 /* Remove DECLARE opcodes and dynamic defs. */
3846 static void preload_remove_declares(zend_op_array *op_array)
3847 {
3848 	zend_op *opline = op_array->opcodes;
3849 	zend_op *end = opline + op_array->last;
3850 	uint32_t skip_dynamic_func_count = 0;
3851 	zend_string *key;
3852 	zend_op_array *func;
3853 
3854 	while (opline != end) {
3855 		switch (opline->opcode) {
3856 			case ZEND_DECLARE_CLASS:
3857 			case ZEND_DECLARE_CLASS_DELAYED:
3858 				key = Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1);
3859 				if (!zend_hash_exists(CG(class_table), key)) {
3860 					MAKE_NOP(opline);
3861 				}
3862 				break;
3863 			case ZEND_DECLARE_FUNCTION:
3864 				opline->op2.num -= skip_dynamic_func_count;
3865 				key = Z_STR_P(RT_CONSTANT(opline, opline->op1));
3866 				func = zend_hash_find_ptr(EG(function_table), key);
3867 				if (func && func == op_array->dynamic_func_defs[opline->op2.num]) {
3868 					zend_op_array **dynamic_func_defs;
3869 
3870 					op_array->num_dynamic_func_defs--;
3871 					if (op_array->num_dynamic_func_defs == 0) {
3872 						dynamic_func_defs = NULL;
3873 					} else {
3874 						dynamic_func_defs = emalloc(sizeof(zend_op_array*) * op_array->num_dynamic_func_defs);
3875 						if (opline->op2.num > 0) {
3876 							memcpy(
3877 								dynamic_func_defs,
3878 								op_array->dynamic_func_defs,
3879 								sizeof(zend_op_array*) * opline->op2.num);
3880 						}
3881 						if (op_array->num_dynamic_func_defs - opline->op2.num > 0) {
3882 							memcpy(
3883 								dynamic_func_defs + opline->op2.num,
3884 								op_array->dynamic_func_defs + (opline->op2.num + 1),
3885 								sizeof(zend_op_array*) * (op_array->num_dynamic_func_defs - opline->op2.num));
3886 						}
3887 					}
3888 					efree(op_array->dynamic_func_defs);
3889 					op_array->dynamic_func_defs = dynamic_func_defs;
3890 					skip_dynamic_func_count++;
3891 					MAKE_NOP(opline);
3892 				}
3893 				break;
3894 			case ZEND_DECLARE_LAMBDA_FUNCTION:
3895 				opline->op2.num -= skip_dynamic_func_count;
3896 				break;
3897 		}
3898 		opline++;
3899 	}
3900 }
3901 
3902 static void preload_link(void)
3903 {
3904 	zval *zv;
3905 	zend_persistent_script *script;
3906 	zend_class_entry *ce;
3907 	zend_string *key;
3908 	bool changed;
3909 
3910 	HashTable errors;
3911 	zend_hash_init(&errors, 0, NULL, NULL, 0);
3912 
3913 	/* Resolve class dependencies */
3914 	do {
3915 		changed = false;
3916 
3917 		ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM(EG(class_table), key, zv, EG(persistent_classes_count)) {
3918 			ce = Z_PTR_P(zv);
3919 			ZEND_ASSERT(ce->type != ZEND_INTERNAL_CLASS);
3920 
3921 			if (!(ce->ce_flags & (ZEND_ACC_TOP_LEVEL|ZEND_ACC_ANON_CLASS))
3922 					|| (ce->ce_flags & ZEND_ACC_LINKED)) {
3923 				continue;
3924 			}
3925 
3926 			zend_string *lcname = zend_string_tolower(ce->name);
3927 			if (!(ce->ce_flags & ZEND_ACC_ANON_CLASS)) {
3928 				if (zend_hash_exists(EG(class_table), lcname)) {
3929 					zend_string_release(lcname);
3930 					continue;
3931 				}
3932 			}
3933 
3934 			preload_error error_info;
3935 			if (preload_resolve_deps(&error_info, ce) == FAILURE) {
3936 				zend_string_release(lcname);
3937 				continue;
3938 			}
3939 
3940 			zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, lcname);
3941 			ZEND_ASSERT(zv && "We already checked above that the class doesn't exist yet");
3942 
3943 			/* Set the FILE_CACHED flag to force a lazy load, and the CACHED flag to
3944 			 * prevent freeing of interface names. */
3945 			void *checkpoint = zend_arena_checkpoint(CG(arena));
3946 			zend_class_entry *orig_ce = ce;
3947 			uint32_t temporary_flags = ZEND_ACC_FILE_CACHED|ZEND_ACC_CACHED;
3948 			ce->ce_flags |= temporary_flags;
3949 			if (ce->parent_name) {
3950 				zend_string_addref(ce->parent_name);
3951 			}
3952 
3953 			/* Record and suppress errors during inheritance. */
3954 			orig_error_cb = zend_error_cb;
3955 			zend_error_cb = preload_error_cb;
3956 			zend_begin_record_errors();
3957 
3958 			/* Set filename & lineno information for inheritance errors */
3959 			CG(in_compilation) = true;
3960 			CG(compiled_filename) = ce->info.user.filename;
3961 			CG(zend_lineno) = ce->info.user.line_start;
3962 			zend_try {
3963 				ce = zend_do_link_class(ce, NULL, lcname);
3964 				if (!ce) {
3965 					ZEND_ASSERT(0 && "Class linking failed?");
3966 				}
3967 				ce->ce_flags &= ~temporary_flags;
3968 				changed = true;
3969 
3970 				/* Inheritance successful, print out any warnings. */
3971 				zend_error_cb = orig_error_cb;
3972 				zend_emit_recorded_errors();
3973 			} zend_catch {
3974 				/* Clear variance obligations that were left behind on bailout. */
3975 				if (CG(delayed_variance_obligations)) {
3976 					zend_hash_index_del(
3977 						CG(delayed_variance_obligations), (uintptr_t) Z_CE_P(zv));
3978 				}
3979 
3980 				/* Restore the original class. */
3981 				zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, key);
3982 				Z_CE_P(zv) = orig_ce;
3983 				orig_ce->ce_flags &= ~temporary_flags;
3984 				zend_arena_release(&CG(arena), checkpoint);
3985 
3986 				/* Remember the last error. */
3987 				zend_error_cb = orig_error_cb;
3988 				EG(record_errors) = false;
3989 				ZEND_ASSERT(EG(num_errors) > 0);
3990 				zend_hash_update_ptr(&errors, key, EG(errors)[EG(num_errors)-1]);
3991 				EG(num_errors)--;
3992 			} zend_end_try();
3993 			CG(in_compilation) = false;
3994 			CG(compiled_filename) = NULL;
3995 			zend_free_recorded_errors();
3996 			zend_string_release(lcname);
3997 		} ZEND_HASH_FOREACH_END();
3998 	} while (changed);
3999 
4000 	do {
4001 		changed = false;
4002 
4003 		ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(class_table), zv) {
4004 			ce = Z_PTR_P(zv);
4005 			if (ce->type == ZEND_INTERNAL_CLASS) {
4006 				break;
4007 			}
4008 			if ((ce->ce_flags & ZEND_ACC_LINKED) && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
4009 				if (!(ce->ce_flags & ZEND_ACC_TRAIT)) { /* don't update traits */
4010 					CG(in_compilation) = true; /* prevent autoloading */
4011 					if (preload_try_resolve_constants(ce)) {
4012 						changed = true;
4013 					}
4014 					CG(in_compilation) = false;
4015 				}
4016 			}
4017 		} ZEND_HASH_FOREACH_END();
4018 	} while (changed);
4019 
4020 	/* Warn for classes that could not be linked. */
4021 	ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_FROM(
4022 			EG(class_table), key, zv, EG(persistent_classes_count)) {
4023 		ce = Z_PTR_P(zv);
4024 		ZEND_ASSERT(ce->type != ZEND_INTERNAL_CLASS);
4025 		if ((ce->ce_flags & (ZEND_ACC_TOP_LEVEL|ZEND_ACC_ANON_CLASS))
4026 				&& !(ce->ce_flags & ZEND_ACC_LINKED)) {
4027 			zend_string *lcname = zend_string_tolower(ce->name);
4028 			preload_error error;
4029 			if (!(ce->ce_flags & ZEND_ACC_ANON_CLASS)
4030 			 && zend_hash_exists(EG(class_table), lcname)) {
4031 				zend_error_at(
4032 					E_WARNING, ce->info.user.filename, ce->info.user.line_start,
4033 					"Can't preload already declared class %s", ZSTR_VAL(ce->name));
4034 			} else if (preload_resolve_deps(&error, ce) == FAILURE) {
4035 				zend_error_at(
4036 					E_WARNING, ce->info.user.filename, ce->info.user.line_start,
4037 					"Can't preload unlinked class %s: %s%s",
4038 					ZSTR_VAL(ce->name), error.kind, error.name);
4039 			} else {
4040 				zend_error_info *error = zend_hash_find_ptr(&errors, key);
4041 				zend_error_at(
4042 					E_WARNING, error->filename, error->lineno,
4043 					"Can't preload unlinked class %s: %s",
4044 					ZSTR_VAL(ce->name), ZSTR_VAL(error->message));
4045 			}
4046 			zend_string_release(lcname);
4047 		}
4048 	} ZEND_HASH_FOREACH_END();
4049 
4050 	zend_hash_destroy(&errors);
4051 
4052 	ZEND_HASH_MAP_FOREACH_PTR(preload_scripts, script) {
4053 		zend_op_array *op_array = &script->script.main_op_array;
4054 		preload_remove_declares(op_array);
4055 
4056 		if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) {
4057 			zend_accel_free_delayed_early_binding_list(script);
4058 			zend_accel_build_delayed_early_binding_list(script);
4059 			if (!script->num_early_bindings) {
4060 				op_array->fn_flags &= ~ZEND_ACC_EARLY_BINDING;
4061 			}
4062 		}
4063 	} ZEND_HASH_FOREACH_END();
4064 
4065 	/* Dynamic defs inside functions and methods need to be removed as well. */
4066 	zend_op_array *op_array;
4067 	ZEND_HASH_MAP_FOREACH_PTR_FROM(EG(function_table), op_array, EG(persistent_functions_count)) {
4068 		ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
4069 		preload_remove_declares(op_array);
4070 	} ZEND_HASH_FOREACH_END();
4071 	ZEND_HASH_MAP_FOREACH_PTR_FROM(EG(class_table), ce, EG(persistent_classes_count)) {
4072 		ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
4073 			if (op_array->type == ZEND_USER_FUNCTION) {
4074 				preload_remove_declares(op_array);
4075 			}
4076 		} ZEND_HASH_FOREACH_END();
4077 	} ZEND_HASH_FOREACH_END();
4078 }
4079 
4080 static zend_string *preload_resolve_path(zend_string *filename)
4081 {
4082 	if (php_is_stream_path(ZSTR_VAL(filename))) {
4083 		return NULL;
4084 	}
4085 	return zend_resolve_path(filename);
4086 }
4087 
4088 static void preload_remove_empty_includes(void)
4089 {
4090 	zend_persistent_script *script;
4091 	bool changed;
4092 
4093 	/* mark all as empty */
4094 	ZEND_HASH_MAP_FOREACH_PTR(preload_scripts, script) {
4095 		script->empty = true;
4096 	} ZEND_HASH_FOREACH_END();
4097 
4098 	/* find non empty scripts */
4099 	do {
4100 		changed = false;
4101 		ZEND_HASH_MAP_FOREACH_PTR(preload_scripts, script) {
4102 			if (script->empty) {
4103 				bool empty = true;
4104 				zend_op *opline = script->script.main_op_array.opcodes;
4105 				zend_op *end = opline + script->script.main_op_array.last;
4106 
4107 				while (opline < end) {
4108 					if (opline->opcode == ZEND_INCLUDE_OR_EVAL &&
4109 					    opline->extended_value != ZEND_EVAL &&
4110 					    opline->op1_type == IS_CONST &&
4111 					    Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_STRING &&
4112 					    opline->result_type == IS_UNUSED) {
4113 
4114 						zend_string *resolved_path = preload_resolve_path(Z_STR_P(RT_CONSTANT(opline, opline->op1)));
4115 
4116 						if (resolved_path) {
4117 							zend_persistent_script *incl = zend_hash_find_ptr(preload_scripts, resolved_path);
4118 							zend_string_release(resolved_path);
4119 							if (!incl || !incl->empty) {
4120 								empty = false;
4121 								break;
4122 							}
4123 						} else {
4124 							empty = false;
4125 							break;
4126 						}
4127 					} else if (opline->opcode != ZEND_NOP &&
4128 					           opline->opcode != ZEND_RETURN &&
4129 					           opline->opcode != ZEND_HANDLE_EXCEPTION) {
4130 						empty = false;
4131 						break;
4132 					}
4133 					opline++;
4134 				}
4135 				if (!empty) {
4136 					script->empty = false;
4137 					changed = true;
4138 				}
4139 			}
4140 		} ZEND_HASH_FOREACH_END();
4141 	} while (changed);
4142 
4143 	/* remove empty includes */
4144 	ZEND_HASH_MAP_FOREACH_PTR(preload_scripts, script) {
4145 		zend_op *opline = script->script.main_op_array.opcodes;
4146 		zend_op *end = opline + script->script.main_op_array.last;
4147 
4148 		while (opline < end) {
4149 			if (opline->opcode == ZEND_INCLUDE_OR_EVAL &&
4150 			    opline->extended_value != ZEND_EVAL &&
4151 			    opline->op1_type == IS_CONST &&
4152 			    Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_STRING) {
4153 
4154 				zend_string *resolved_path = preload_resolve_path(Z_STR_P(RT_CONSTANT(opline, opline->op1)));
4155 
4156 				if (resolved_path) {
4157 					zend_persistent_script *incl = zend_hash_find_ptr(preload_scripts, resolved_path);
4158 					if (incl && incl->empty && opline->result_type == IS_UNUSED) {
4159 						MAKE_NOP(opline);
4160 					} else {
4161 						if (!IS_ABSOLUTE_PATH(Z_STRVAL_P(RT_CONSTANT(opline, opline->op1)), Z_STRLEN_P(RT_CONSTANT(opline, opline->op1)))) {
4162 							/* replace relative patch with absolute one */
4163 							zend_string_release(Z_STR_P(RT_CONSTANT(opline, opline->op1)));
4164 							ZVAL_STR_COPY(RT_CONSTANT(opline, opline->op1), resolved_path);
4165 						}
4166 					}
4167 					zend_string_release(resolved_path);
4168 				}
4169 			}
4170 			opline++;
4171 		}
4172 	} ZEND_HASH_FOREACH_END();
4173 }
4174 
4175 static void preload_register_trait_methods(zend_class_entry *ce) {
4176 	zend_op_array *op_array;
4177 	ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
4178 		if (!(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
4179 			ZEND_ASSERT(op_array->refcount && "Must have refcount pointer");
4180 			zend_shared_alloc_register_xlat_entry(op_array->refcount, op_array);
4181 		}
4182 	} ZEND_HASH_FOREACH_END();
4183 }
4184 
4185 static void preload_fix_trait_methods(zend_class_entry *ce)
4186 {
4187 	zend_op_array *op_array;
4188 
4189 	ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
4190 		if (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE) {
4191 			zend_op_array *orig_op_array = zend_shared_alloc_get_xlat_entry(op_array->refcount);
4192 			ZEND_ASSERT(orig_op_array && "Must be in xlat table");
4193 
4194 			zend_string *function_name = op_array->function_name;
4195 			zend_class_entry *scope = op_array->scope;
4196 			uint32_t fn_flags = op_array->fn_flags;
4197 			zend_function *prototype = op_array->prototype;
4198 			HashTable *ht = op_array->static_variables;
4199 			*op_array = *orig_op_array;
4200 			op_array->function_name = function_name;
4201 			op_array->scope = scope;
4202 			op_array->fn_flags = fn_flags;
4203 			op_array->prototype = prototype;
4204 			op_array->static_variables = ht;
4205 		}
4206 	} ZEND_HASH_FOREACH_END();
4207 }
4208 
4209 static void preload_optimize(zend_persistent_script *script)
4210 {
4211 	zend_class_entry *ce;
4212 	zend_persistent_script *tmp_script;
4213 
4214 	zend_shared_alloc_init_xlat_table();
4215 
4216 	ZEND_HASH_MAP_FOREACH_PTR(&script->script.class_table, ce) {
4217 		if (ce->ce_flags & ZEND_ACC_TRAIT) {
4218 			preload_register_trait_methods(ce);
4219 		}
4220 	} ZEND_HASH_FOREACH_END();
4221 
4222 	ZEND_HASH_MAP_FOREACH_PTR(preload_scripts, tmp_script) {
4223 		ZEND_HASH_MAP_FOREACH_PTR(&tmp_script->script.class_table, ce) {
4224 			if (ce->ce_flags & ZEND_ACC_TRAIT) {
4225 				preload_register_trait_methods(ce);
4226 			}
4227 		} ZEND_HASH_FOREACH_END();
4228 	} ZEND_HASH_FOREACH_END();
4229 
4230 	zend_optimize_script(&script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level);
4231 	zend_accel_finalize_delayed_early_binding_list(script);
4232 
4233 	ZEND_HASH_MAP_FOREACH_PTR(&script->script.class_table, ce) {
4234 		preload_fix_trait_methods(ce);
4235 	} ZEND_HASH_FOREACH_END();
4236 
4237 	ZEND_HASH_MAP_FOREACH_PTR(preload_scripts, script) {
4238 		ZEND_HASH_MAP_FOREACH_PTR(&script->script.class_table, ce) {
4239 			preload_fix_trait_methods(ce);
4240 		} ZEND_HASH_FOREACH_END();
4241 	} ZEND_HASH_FOREACH_END();
4242 
4243 	zend_shared_alloc_destroy_xlat_table();
4244 
4245 	ZEND_HASH_MAP_FOREACH_PTR(preload_scripts, script) {
4246 		zend_optimize_script(&script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level);
4247 		zend_accel_finalize_delayed_early_binding_list(script);
4248 	} ZEND_HASH_FOREACH_END();
4249 }
4250 
4251 static zend_persistent_script* preload_script_in_shared_memory(zend_persistent_script *new_persistent_script)
4252 {
4253 	zend_accel_hash_entry *bucket;
4254 	uint32_t memory_used;
4255 	uint32_t checkpoint;
4256 
4257 	if (zend_accel_hash_is_full(&ZCSG(hash))) {
4258 		zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Not enough entries in hash table for preloading. Consider increasing the value for the opcache.max_accelerated_files directive in php.ini.");
4259 		return NULL;
4260 	}
4261 
4262 	checkpoint = zend_shared_alloc_checkpoint_xlat_table();
4263 
4264 	/* Calculate the required memory size */
4265 	memory_used = zend_accel_script_persist_calc(new_persistent_script, 1);
4266 
4267 	/* Allocate shared memory */
4268 	ZCG(mem) = zend_shared_alloc_aligned(memory_used);
4269 	if (!ZCG(mem)) {
4270 		zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Not enough shared memory for preloading. Consider increasing the value for the opcache.memory_consumption directive in php.ini.");
4271 		return NULL;
4272 	}
4273 
4274 	bzero_aligned(ZCG(mem), memory_used);
4275 
4276 	zend_shared_alloc_restore_xlat_table(checkpoint);
4277 
4278 	/* Copy into shared memory */
4279 	new_persistent_script = zend_accel_script_persist(new_persistent_script, 1);
4280 
4281 	new_persistent_script->is_phar = is_phar_file(new_persistent_script->script.filename);
4282 
4283 	/* Consistency check */
4284 	if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
4285 		zend_accel_error(
4286 			((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
4287 			"Internal error: wrong size calculation: %s start=" ZEND_ADDR_FMT ", end=" ZEND_ADDR_FMT ", real=" ZEND_ADDR_FMT "\n",
4288 			ZSTR_VAL(new_persistent_script->script.filename),
4289 			(size_t)new_persistent_script->mem,
4290 			(size_t)((char *)new_persistent_script->mem + new_persistent_script->size),
4291 			(size_t)ZCG(mem));
4292 	}
4293 
4294 	/* store script structure in the hash table */
4295 	bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->script.filename, 0, new_persistent_script);
4296 	if (bucket) {
4297 		zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", ZSTR_VAL(new_persistent_script->script.filename));
4298 	}
4299 
4300 	new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
4301 
4302 	return new_persistent_script;
4303 }
4304 
4305 static void preload_load(void)
4306 {
4307 	/* Load into process tables */
4308 	zend_script *script = &ZCSG(preload_script)->script;
4309 	if (zend_hash_num_elements(&script->function_table)) {
4310 		Bucket *p = script->function_table.arData;
4311 		Bucket *end = p + script->function_table.nNumUsed;
4312 
4313 		zend_hash_extend(CG(function_table),
4314 			CG(function_table)->nNumUsed + script->function_table.nNumUsed, 0);
4315 		for (; p != end; p++) {
4316 			_zend_hash_append_ptr_ex(CG(function_table), p->key, Z_PTR(p->val), 1);
4317 		}
4318 	}
4319 
4320 	if (zend_hash_num_elements(&script->class_table)) {
4321 		Bucket *p = script->class_table.arData;
4322 		Bucket *end = p + script->class_table.nNumUsed;
4323 
4324 		zend_hash_extend(CG(class_table),
4325 			CG(class_table)->nNumUsed + script->class_table.nNumUsed, 0);
4326 		for (; p != end; p++) {
4327 			_zend_hash_append_ex(CG(class_table), p->key, &p->val, 1);
4328 		}
4329 	}
4330 
4331 	if (EG(zend_constants)) {
4332 		EG(persistent_constants_count) = EG(zend_constants)->nNumUsed;
4333 	}
4334 	if (EG(function_table)) {
4335 		EG(persistent_functions_count) = EG(function_table)->nNumUsed;
4336 	}
4337 	if (EG(class_table)) {
4338 		EG(persistent_classes_count)   = EG(class_table)->nNumUsed;
4339 	}
4340 	if (CG(map_ptr_last) != ZCSG(map_ptr_last)) {
4341 		size_t old_map_ptr_last = CG(map_ptr_last);
4342 		CG(map_ptr_last) = ZCSG(map_ptr_last);
4343 		CG(map_ptr_size) = ZEND_MM_ALIGNED_SIZE_EX(CG(map_ptr_last) + 1, 4096);
4344 		CG(map_ptr_real_base) = perealloc(CG(map_ptr_real_base), CG(map_ptr_size) * sizeof(void*), 1);
4345 		CG(map_ptr_base) = ZEND_MAP_PTR_BIASED_BASE(CG(map_ptr_real_base));
4346 		memset((void **) CG(map_ptr_real_base) + old_map_ptr_last, 0,
4347 			(CG(map_ptr_last) - old_map_ptr_last) * sizeof(void *));
4348 	}
4349 }
4350 
4351 static zend_result accel_preload(const char *config, bool in_child)
4352 {
4353 	zend_file_handle file_handle;
4354 	zend_result ret;
4355 	char *orig_open_basedir;
4356 	size_t orig_map_ptr_last;
4357 	uint32_t orig_compiler_options;
4358 
4359 	ZCG(enabled) = false;
4360 	ZCG(accelerator_enabled) = false;
4361 	orig_open_basedir = PG(open_basedir);
4362 	PG(open_basedir) = NULL;
4363 	preload_orig_compile_file = accelerator_orig_compile_file;
4364 	accelerator_orig_compile_file = preload_compile_file;
4365 
4366 	orig_map_ptr_last = CG(map_ptr_last);
4367 
4368 	/* Compile and execute preloading script */
4369 	zend_stream_init_filename(&file_handle, (char *) config);
4370 
4371 	preload_scripts = emalloc(sizeof(HashTable));
4372 	zend_hash_init(preload_scripts, 0, NULL, NULL, 0);
4373 
4374 	orig_compiler_options = CG(compiler_options);
4375 	if (in_child) {
4376 		CG(compiler_options) |= ZEND_COMPILE_PRELOAD_IN_CHILD;
4377 	}
4378 	CG(compiler_options) |= ZEND_COMPILE_PRELOAD;
4379 	CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
4380 	CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
4381 	CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
4382 	CG(compiler_options) |= ZEND_COMPILE_IGNORE_OTHER_FILES;
4383 	CG(skip_shebang) = true;
4384 
4385 	zend_try {
4386 		zend_op_array *op_array;
4387 
4388 		ret = SUCCESS;
4389 		op_array = zend_compile_file(&file_handle, ZEND_REQUIRE);
4390 		if (file_handle.opened_path) {
4391 			zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path);
4392 		}
4393 		zend_destroy_file_handle(&file_handle);
4394 		if (op_array) {
4395 			zend_execute(op_array, NULL);
4396 			zend_exception_restore();
4397 			if (UNEXPECTED(EG(exception))) {
4398 				if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
4399 					zend_user_exception_handler();
4400 				}
4401 				if (EG(exception)) {
4402 					ret = zend_exception_error(EG(exception), E_ERROR);
4403 					if (ret == FAILURE) {
4404 						CG(unclean_shutdown) = true;
4405 					}
4406 				}
4407 			}
4408 			destroy_op_array(op_array);
4409 			efree_size(op_array, sizeof(zend_op_array));
4410 		} else {
4411 			if (EG(exception)) {
4412 				zend_exception_error(EG(exception), E_ERROR);
4413 			}
4414 
4415 			CG(unclean_shutdown) = true;
4416 			ret = FAILURE;
4417 		}
4418 	} zend_catch {
4419 		ret = FAILURE;
4420 	} zend_end_try();
4421 
4422 	PG(open_basedir) = orig_open_basedir;
4423 	accelerator_orig_compile_file = preload_orig_compile_file;
4424 	ZCG(enabled) = true;
4425 
4426 	zend_destroy_file_handle(&file_handle);
4427 
4428 	if (ret == SUCCESS) {
4429 		zend_persistent_script *script;
4430 		int ping_auto_globals_mask;
4431 		int i;
4432 
4433 		if (PG(auto_globals_jit)) {
4434 			ping_auto_globals_mask = zend_accel_get_auto_globals();
4435 		} else {
4436 			ping_auto_globals_mask = 0;
4437 		}
4438 
4439 		if (EG(zend_constants)) {
4440 			/* Remember __COMPILER_HALT_OFFSET__(s). Do this early,
4441 			 * as zend_shutdown_executor_values() destroys constants. */
4442 			ZEND_HASH_MAP_FOREACH_PTR(preload_scripts, script) {
4443 				zend_execute_data *orig_execute_data = EG(current_execute_data);
4444 				zend_execute_data fake_execute_data;
4445 				zval *offset;
4446 
4447 				memset(&fake_execute_data, 0, sizeof(fake_execute_data));
4448 				fake_execute_data.func = (zend_function*)&script->script.main_op_array;
4449 				EG(current_execute_data) = &fake_execute_data;
4450 				if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
4451 					script->compiler_halt_offset = Z_LVAL_P(offset);
4452 				}
4453 				EG(current_execute_data) = orig_execute_data;
4454 			} ZEND_HASH_FOREACH_END();
4455 		}
4456 
4457 		/* Cleanup executor */
4458 		EG(flags) |= EG_FLAGS_IN_SHUTDOWN;
4459 
4460 		php_call_shutdown_functions();
4461 		zend_call_destructors();
4462 		php_output_end_all();
4463 		php_free_shutdown_functions();
4464 
4465 		/* Release stored values to avoid dangling pointers */
4466 		zend_shutdown_executor_values(/* fast_shutdown */ false);
4467 
4468 		/* On ZTS we execute `executor_globals_ctor` which reset the freelist and p5s pointers, while on NTS we don't.
4469 		 * We have to clean up the memory before the actual request takes place to avoid a memory leak. */
4470 #ifdef ZTS
4471 		zend_shutdown_strtod();
4472 #endif
4473 
4474 		/* We don't want to preload constants.
4475 		 * Check that  zend_shutdown_executor_values() also destroys constants. */
4476 		ZEND_ASSERT(zend_hash_num_elements(EG(zend_constants)) == EG(persistent_constants_count));
4477 
4478 		zend_hash_init(&EG(symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0);
4479 
4480 		CG(map_ptr_last) = orig_map_ptr_last;
4481 
4482 		if (EG(full_tables_cleanup)) {
4483 			zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading is not compatible with dl() function.");
4484 			ret = FAILURE;
4485 			goto finish;
4486 		}
4487 
4488 		/* Inheritance errors may be thrown during linking */
4489 		zend_try {
4490 			preload_link();
4491 		} zend_catch {
4492 			CG(map_ptr_last) = orig_map_ptr_last;
4493 			ret = FAILURE;
4494 			goto finish;
4495 		} zend_end_try();
4496 
4497 		preload_remove_empty_includes();
4498 
4499 		script = create_persistent_script();
4500 		script->ping_auto_globals_mask = ping_auto_globals_mask;
4501 
4502 		/* Store all functions and classes in a single pseudo-file */
4503 		CG(compiled_filename) = ZSTR_INIT_LITERAL("$PRELOAD$", 0);
4504 #if ZEND_USE_ABS_CONST_ADDR
4505 		init_op_array(&script->script.main_op_array, ZEND_USER_FUNCTION, 1);
4506 #else
4507 		init_op_array(&script->script.main_op_array, ZEND_USER_FUNCTION, 2);
4508 #endif
4509 		script->script.main_op_array.fn_flags |= ZEND_ACC_DONE_PASS_TWO;
4510 		script->script.main_op_array.last = 1;
4511 		script->script.main_op_array.last_literal = 1;
4512 		script->script.main_op_array.T = ZEND_OBSERVER_ENABLED;
4513 #if ZEND_USE_ABS_CONST_ADDR
4514 		script->script.main_op_array.literals = (zval*)emalloc(sizeof(zval));
4515 #else
4516 		script->script.main_op_array.literals = (zval*)(script->script.main_op_array.opcodes + 1);
4517 #endif
4518 		ZVAL_NULL(script->script.main_op_array.literals);
4519 		memset(script->script.main_op_array.opcodes, 0, sizeof(zend_op));
4520 		script->script.main_op_array.opcodes[0].opcode = ZEND_RETURN;
4521 		script->script.main_op_array.opcodes[0].op1_type = IS_CONST;
4522 		script->script.main_op_array.opcodes[0].op1.constant = 0;
4523 		ZEND_PASS_TWO_UPDATE_CONSTANT(&script->script.main_op_array, script->script.main_op_array.opcodes, script->script.main_op_array.opcodes[0].op1);
4524 		zend_vm_set_opcode_handler(script->script.main_op_array.opcodes);
4525 
4526 		script->script.filename = CG(compiled_filename);
4527 		CG(compiled_filename) = NULL;
4528 
4529 		preload_move_user_functions(CG(function_table), &script->script.function_table);
4530 		preload_move_user_classes(CG(class_table), &script->script.class_table);
4531 
4532 		zend_hash_sort_ex(&script->script.class_table, preload_sort_classes, NULL, 0);
4533 
4534 		preload_optimize(script);
4535 
4536 		zend_shared_alloc_init_xlat_table();
4537 
4538 		HANDLE_BLOCK_INTERRUPTIONS();
4539 		SHM_UNPROTECT();
4540 
4541 		ZCSG(preload_script) = preload_script_in_shared_memory(script);
4542 
4543 		SHM_PROTECT();
4544 		HANDLE_UNBLOCK_INTERRUPTIONS();
4545 
4546 		preload_load();
4547 
4548 		/* Store individual scripts with unlinked classes */
4549 		HANDLE_BLOCK_INTERRUPTIONS();
4550 		SHM_UNPROTECT();
4551 
4552 		i = 0;
4553 		ZCSG(saved_scripts) = zend_shared_alloc((zend_hash_num_elements(preload_scripts) + 1) * sizeof(void*));
4554 		ZEND_HASH_MAP_FOREACH_PTR(preload_scripts, script) {
4555 			if (zend_hash_num_elements(&script->script.class_table) > 1) {
4556 				zend_hash_sort_ex(&script->script.class_table, preload_sort_classes, NULL, 0);
4557 			}
4558 			ZCSG(saved_scripts)[i++] = preload_script_in_shared_memory(script);
4559 		} ZEND_HASH_FOREACH_END();
4560 		ZCSG(saved_scripts)[i] = NULL;
4561 
4562 		zend_shared_alloc_save_state();
4563 		accel_interned_strings_save_state();
4564 
4565 		SHM_PROTECT();
4566 		HANDLE_UNBLOCK_INTERRUPTIONS();
4567 
4568 		zend_shared_alloc_destroy_xlat_table();
4569 	} else {
4570 		CG(map_ptr_last) = orig_map_ptr_last;
4571 	}
4572 
4573 finish:
4574 	CG(compiler_options) = orig_compiler_options;
4575 	zend_hash_destroy(preload_scripts);
4576 	efree(preload_scripts);
4577 	preload_scripts = NULL;
4578 
4579 	return ret;
4580 }
4581 
4582 static size_t preload_ub_write(const char *str, size_t str_length)
4583 {
4584 	return fwrite(str, 1, str_length, stdout);
4585 }
4586 
4587 static void preload_flush(void *server_context)
4588 {
4589 	fflush(stdout);
4590 }
4591 
4592 static int preload_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s)
4593 {
4594 	return 0;
4595 }
4596 
4597 static int preload_send_headers(sapi_headers_struct *sapi_headers)
4598 {
4599 	return SAPI_HEADER_SENT_SUCCESSFULLY;
4600 }
4601 
4602 static void preload_send_header(sapi_header_struct *sapi_header, void *server_context)
4603 {
4604 }
4605 
4606 #ifndef ZEND_WIN32
4607 static zend_result accel_finish_startup_preload(bool in_child)
4608 {
4609 	zend_result ret = SUCCESS;
4610 	int orig_error_reporting;
4611 
4612 	int (*orig_activate)(void) = sapi_module.activate;
4613 	int (*orig_deactivate)(void) = sapi_module.deactivate;
4614 	void (*orig_register_server_variables)(zval *track_vars_array) = sapi_module.register_server_variables;
4615 	int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers) = sapi_module.header_handler;
4616 	int (*orig_send_headers)(sapi_headers_struct *sapi_headers) = sapi_module.send_headers;
4617 	void (*orig_send_header)(sapi_header_struct *sapi_header, void *server_context)= sapi_module.send_header;
4618 	char *(*orig_getenv)(const char *name, size_t name_len) = sapi_module.getenv;
4619 	size_t (*orig_ub_write)(const char *str, size_t str_length) = sapi_module.ub_write;
4620 	void (*orig_flush)(void *server_context) = sapi_module.flush;
4621 #ifdef ZEND_SIGNALS
4622 	bool old_reset_signals = SIGG(reset);
4623 #endif
4624 
4625 	sapi_module.activate = NULL;
4626 	sapi_module.deactivate = NULL;
4627 	sapi_module.register_server_variables = NULL;
4628 	sapi_module.header_handler = preload_header_handler;
4629 	sapi_module.send_headers = preload_send_headers;
4630 	sapi_module.send_header = preload_send_header;
4631 	sapi_module.getenv = NULL;
4632 	sapi_module.ub_write = preload_ub_write;
4633 	sapi_module.flush = preload_flush;
4634 
4635 	zend_interned_strings_switch_storage(1);
4636 
4637 #ifdef ZEND_SIGNALS
4638 	SIGG(reset) = false;
4639 #endif
4640 
4641 	orig_error_reporting = EG(error_reporting);
4642 	EG(error_reporting) = 0;
4643 
4644 	const zend_result rc = php_request_startup();
4645 
4646 	EG(error_reporting) = orig_error_reporting;
4647 
4648 	if (rc == SUCCESS) {
4649 		bool orig_report_memleaks;
4650 
4651 		/* don't send headers */
4652 		SG(headers_sent) = true;
4653 		SG(request_info).no_headers = true;
4654 		php_output_set_status(0);
4655 
4656 		ZCG(auto_globals_mask) = 0;
4657 		ZCG(request_time) = (time_t)sapi_get_request_time();
4658 		ZCG(cache_opline) = NULL;
4659 		ZCG(cache_persistent_script) = NULL;
4660 		ZCG(include_path_key_len) = 0;
4661 		ZCG(include_path_check) = true;
4662 
4663 		ZCG(cwd) = NULL;
4664 		ZCG(cwd_key_len) = 0;
4665 		ZCG(cwd_check) = true;
4666 
4667 		if (accel_preload(ZCG(accel_directives).preload, in_child) != SUCCESS) {
4668 			ret = FAILURE;
4669 		}
4670 		preload_flush(NULL);
4671 
4672 		orig_report_memleaks = PG(report_memleaks);
4673 		PG(report_memleaks) = false;
4674 #ifdef ZEND_SIGNALS
4675 		/* We may not have registered signal handlers due to SIGG(reset)=0, so
4676 		 * also disable the check that they are registered. */
4677 		SIGG(check) = false;
4678 #endif
4679 		php_request_shutdown(NULL); /* calls zend_shared_alloc_unlock(); */
4680 		EG(class_table) = NULL;
4681 		EG(function_table) = NULL;
4682 		PG(report_memleaks) = orig_report_memleaks;
4683 	} else {
4684 		zend_shared_alloc_unlock();
4685 		ret = FAILURE;
4686 	}
4687 #ifdef ZEND_SIGNALS
4688 	SIGG(reset) = old_reset_signals;
4689 #endif
4690 
4691 	sapi_module.activate = orig_activate;
4692 	sapi_module.deactivate = orig_deactivate;
4693 	sapi_module.register_server_variables = orig_register_server_variables;
4694 	sapi_module.header_handler = orig_header_handler;
4695 	sapi_module.send_headers = orig_send_headers;
4696 	sapi_module.send_header = orig_send_header;
4697 	sapi_module.getenv = orig_getenv;
4698 	sapi_module.ub_write = orig_ub_write;
4699 	sapi_module.flush = orig_flush;
4700 
4701 	sapi_activate();
4702 
4703 	return ret;
4704 }
4705 
4706 static zend_result accel_finish_startup_preload_subprocess(pid_t *pid)
4707 {
4708 	uid_t euid = geteuid();
4709 	if (euid != 0) {
4710 		if (ZCG(accel_directives).preload_user
4711 		 && *ZCG(accel_directives).preload_user) {
4712 			zend_accel_error(ACCEL_LOG_WARNING, "\"opcache.preload_user\" is ignored because the current user is not \"root\"");
4713 		}
4714 
4715 		*pid = -1;
4716 		return SUCCESS;
4717 	}
4718 
4719 	if (!ZCG(accel_directives).preload_user
4720 	 || !*ZCG(accel_directives).preload_user) {
4721 
4722 		bool sapi_requires_preload_user = !(strcmp(sapi_module.name, "cli") == 0
4723 		  || strcmp(sapi_module.name, "phpdbg") == 0);
4724 
4725 		if (!sapi_requires_preload_user) {
4726 			*pid = -1;
4727 			return SUCCESS;
4728 		}
4729 
4730 		zend_shared_alloc_unlock();
4731 		zend_accel_error_noreturn(ACCEL_LOG_FATAL, "\"opcache.preload\" requires \"opcache.preload_user\" when running under uid 0");
4732 		return FAILURE;
4733 	}
4734 
4735 	struct passwd *pw = getpwnam(ZCG(accel_directives).preload_user);
4736 	if (pw == NULL) {
4737 		zend_shared_alloc_unlock();
4738 		zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to getpwnam(\"%s\")", ZCG(accel_directives).preload_user);
4739 		return FAILURE;
4740 	}
4741 
4742 	if (pw->pw_uid == euid) {
4743 		*pid = -1;
4744 		return SUCCESS;
4745 	}
4746 
4747 	*pid = fork();
4748 	if (*pid == -1) {
4749 		zend_shared_alloc_unlock();
4750 		zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to fork()");
4751 		return FAILURE;
4752 	}
4753 
4754 	if (*pid == 0) { /* children */
4755 		if (setgid(pw->pw_gid) < 0) {
4756 			zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setgid(%d)", pw->pw_gid);
4757 			exit(1);
4758 		}
4759 		if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
4760 			zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to initgroups(\"%s\", %d)", pw->pw_name, pw->pw_uid);
4761 			exit(1);
4762 		}
4763 		if (setuid(pw->pw_uid) < 0) {
4764 			zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid);
4765 			exit(1);
4766 		}
4767 	}
4768 
4769 	return SUCCESS;
4770 }
4771 #endif /* ZEND_WIN32 */
4772 
4773 static zend_result accel_finish_startup(void)
4774 {
4775 	if (!ZCG(enabled) || !accel_startup_ok) {
4776 		return SUCCESS;
4777 	}
4778 
4779 	if (!(ZCG(accel_directives).preload && *ZCG(accel_directives).preload)) {
4780 		return SUCCESS;
4781 	}
4782 
4783 #ifdef ZEND_WIN32
4784 	zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Preloading is not supported on Windows");
4785 	return FAILURE;
4786 #else /* ZEND_WIN32 */
4787 
4788 	if (UNEXPECTED(file_cache_only)) {
4789 		zend_accel_error(ACCEL_LOG_WARNING, "Preloading doesn't work in \"file_cache_only\" mode");
4790 		return SUCCESS;
4791 	}
4792 
4793 	/* exclusive lock */
4794 	zend_shared_alloc_lock();
4795 
4796 	if (ZCSG(preload_script)) {
4797 		/* Preloading was done in another process */
4798 		preload_load();
4799 		zend_shared_alloc_unlock();
4800 		return SUCCESS;
4801 	}
4802 
4803 
4804 	pid_t pid;
4805 	if (accel_finish_startup_preload_subprocess(&pid) == FAILURE) {
4806 		zend_shared_alloc_unlock();
4807 		return FAILURE;
4808 	}
4809 
4810 	if (pid == -1) { /* no subprocess was needed */
4811 		/* The called function unlocks the shared alloc lock */
4812 		return accel_finish_startup_preload(false);
4813 	} else if (pid == 0) { /* subprocess */
4814 		const zend_result ret = accel_finish_startup_preload(true);
4815 
4816 		exit(ret == SUCCESS ? 0 : 1);
4817 	} else { /* parent */
4818 		int status;
4819 
4820 		if (waitpid(pid, &status, 0) < 0) {
4821 			zend_shared_alloc_unlock();
4822 			zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
4823 		}
4824 
4825 		if (ZCSG(preload_script)) {
4826 			preload_load();
4827 		}
4828 
4829 		zend_shared_alloc_unlock();
4830 
4831 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
4832 			return SUCCESS;
4833 		} else {
4834 			return FAILURE;
4835 		}
4836 	}
4837 #endif /* ZEND_WIN32 */
4838 }
4839 
4840 ZEND_EXT_API zend_extension zend_extension_entry = {
4841 	ACCELERATOR_PRODUCT_NAME,               /* name */
4842 	PHP_VERSION,							/* version */
4843 	"Zend Technologies",					/* author */
4844 	"http://www.zend.com/",					/* URL */
4845 	"Copyright (c)",						/* copyright */
4846 	accel_startup,					   		/* startup */
4847 	NULL,									/* shutdown */
4848 	NULL,									/* per-script activation */
4849 #ifdef HAVE_JIT
4850 	accel_deactivate,                       /* per-script deactivation */
4851 #else
4852 	NULL,									/* per-script deactivation */
4853 #endif
4854 	NULL,									/* message handler */
4855 	NULL,									/* op_array handler */
4856 	NULL,									/* extended statement handler */
4857 	NULL,									/* extended fcall begin handler */
4858 	NULL,									/* extended fcall end handler */
4859 	NULL,									/* op_array ctor */
4860 	NULL,									/* op_array dtor */
4861 	STANDARD_ZEND_EXTENSION_PROPERTIES
4862 };
4863