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