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