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