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