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