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