1/*
2   +----------------------------------------------------------------------+
3   | Zend OPcache                                                         |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2016 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@zend.com>                                |
16   |          Zeev Suraski <zeev@zend.com>                                |
17   |          Stanislav Malyshev <stas@zend.com>                          |
18   |          Dmitry Stogov <dmitry@zend.com>                             |
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 "main/SAPI.h"
35#include "main/php_streams.h"
36#include "main/php_open_temporary_file.h"
37#include "zend_API.h"
38#include "zend_ini.h"
39#include "zend_virtual_cwd.h"
40#include "zend_accelerator_util_funcs.h"
41#include "zend_accelerator_hash.h"
42#include "ext/pcre/php_pcre.h"
43#include "ext/standard/md5.h"
44
45#ifdef HAVE_OPCACHE_FILE_CACHE
46# include "zend_file_cache.h"
47#endif
48
49#ifndef ZEND_WIN32
50#include  <netdb.h>
51#endif
52
53#ifdef ZEND_WIN32
54typedef int uid_t;
55typedef int gid_t;
56#include <io.h>
57#endif
58
59#ifndef ZEND_WIN32
60# include <sys/time.h>
61#else
62# include <process.h>
63#endif
64
65#ifdef HAVE_UNISTD_H
66# include <unistd.h>
67#endif
68#include <fcntl.h>
69#include <signal.h>
70#include <time.h>
71
72#ifndef ZEND_WIN32
73# include <sys/types.h>
74# include <sys/ipc.h>
75#endif
76
77#include <sys/stat.h>
78#include <errno.h>
79
80#define SHM_PROTECT() \
81	do { \
82		if (ZCG(accel_directives).protect_memory) { \
83			zend_accel_shared_protect(1); \
84		} \
85	} while (0)
86#define SHM_UNPROTECT() \
87	do { \
88		if (ZCG(accel_directives).protect_memory) { \
89			zend_accel_shared_protect(0); \
90		} \
91	} while (0)
92
93ZEND_EXTENSION();
94
95#ifndef ZTS
96zend_accel_globals accel_globals;
97#else
98int accel_globals_id;
99#if defined(COMPILE_DL_OPCACHE)
100ZEND_TSRMLS_CACHE_DEFINE()
101#endif
102#endif
103
104/* Points to the structure shared across all PHP processes */
105zend_accel_shared_globals *accel_shared_globals = NULL;
106
107/* true globals, no need for thread safety */
108zend_bool accel_startup_ok = 0;
109static char *zps_failure_reason = NULL;
110char *zps_api_failure_reason = NULL;
111#if ENABLE_FILE_CACHE_FALLBACK
112zend_bool fallback_process = 0; /* process uses file cache fallback */
113#endif
114
115static zend_op_array *(*accelerator_orig_compile_file)(zend_file_handle *file_handle, int type);
116static int (*accelerator_orig_zend_stream_open_function)(const char *filename, zend_file_handle *handle );
117static zend_string *(*accelerator_orig_zend_resolve_path)(const char *filename, int filename_len);
118static void (*orig_chdir)(INTERNAL_FUNCTION_PARAMETERS) = NULL;
119static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL;
120
121#ifdef ZEND_WIN32
122# define INCREMENT(v) InterlockedIncrement64(&ZCSG(v))
123# define DECREMENT(v) InterlockedDecrement64(&ZCSG(v))
124# define LOCKVAL(v)   (ZCSG(v))
125#endif
126
127#ifdef ZEND_WIN32
128static time_t zend_accel_get_time(void)
129{
130	FILETIME now;
131	GetSystemTimeAsFileTime(&now);
132
133	return (time_t) ((((((__int64)now.dwHighDateTime) << 32)|now.dwLowDateTime) - 116444736000000000L)/10000000);
134}
135#else
136# define zend_accel_get_time() time(NULL)
137#endif
138
139static inline int is_stream_path(const char *filename)
140{
141	const char *p;
142
143	for (p = filename;
144	     (*p >= 'a' && *p <= 'z') ||
145	     (*p >= 'A' && *p <= 'Z') ||
146	     (*p >= '0' && *p <= '9') ||
147	     *p == '+' || *p == '-' || *p == '.';
148	     p++);
149	return ((p != filename) && (p[0] == ':') && (p[1] == '/') && (p[2] == '/'));
150}
151
152static inline int is_cacheable_stream_path(const char *filename)
153{
154	return memcmp(filename, "file://", sizeof("file://") - 1) == 0 ||
155	       memcmp(filename, "phar://", sizeof("phar://") - 1) == 0;
156}
157
158/* O+ overrides PHP chdir() function and remembers the current working directory
159 * in ZCG(cwd) and ZCG(cwd_len). Later accel_getcwd() can use stored value and
160 * avoid getcwd() call.
161 */
162static ZEND_FUNCTION(accel_chdir)
163{
164	char cwd[MAXPATHLEN];
165
166	orig_chdir(INTERNAL_FUNCTION_PARAM_PASSTHRU);
167	if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
168		if (ZCG(cwd)) {
169			zend_string_release(ZCG(cwd));
170		}
171		ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
172	} else {
173		if (ZCG(cwd)) {
174			zend_string_release(ZCG(cwd));
175			ZCG(cwd) = NULL;
176		}
177	}
178	ZCG(cwd_key_len) = 0;
179	ZCG(cwd_check) = 1;
180}
181
182static inline zend_string* accel_getcwd(void)
183{
184	if (ZCG(cwd)) {
185		return ZCG(cwd);
186	} else {
187		char cwd[MAXPATHLEN + 1];
188
189		if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
190			return NULL;
191		}
192		ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
193		ZCG(cwd_key_len) = 0;
194		ZCG(cwd_check) = 1;
195		return ZCG(cwd);
196	}
197}
198
199void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason)
200{
201	if ((((double) ZSMMG(wasted_shared_memory)) / ZCG(accel_directives).memory_consumption) >= ZCG(accel_directives).max_wasted_percentage) {
202 		zend_accel_schedule_restart(reason);
203	}
204}
205
206/* O+ tracks changes of "include_path" directive. It stores all the requested
207 * values in ZCG(include_paths) shared hash table, current value in
208 * ZCG(include_path)/ZCG(include_path_len) and one letter "path key" in
209 * ZCG(include_path_key).
210 */
211static ZEND_INI_MH(accel_include_path_on_modify)
212{
213	int ret = orig_include_path_on_modify(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
214
215	if (ret == SUCCESS) {
216		ZCG(include_path) = new_value;
217		ZCG(include_path_key_len) = 0;
218		ZCG(include_path_check) = 1;
219	}
220	return ret;
221}
222
223static inline void accel_restart_enter(void)
224{
225#ifdef ZEND_WIN32
226	INCREMENT(restart_in);
227#else
228	static const FLOCK_STRUCTURE(restart_in_progress, F_WRLCK, SEEK_SET, 2, 1);
229
230	if (fcntl(lock_file, F_SETLK, &restart_in_progress) == -1) {
231		zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(+1):  %s (%d)", strerror(errno), errno);
232	}
233#endif
234	ZCSG(restart_in_progress) = 1;
235}
236
237static inline void accel_restart_leave(void)
238{
239#ifdef ZEND_WIN32
240	ZCSG(restart_in_progress) = 0;
241	DECREMENT(restart_in);
242#else
243	static const FLOCK_STRUCTURE(restart_finished, F_UNLCK, SEEK_SET, 2, 1);
244
245	ZCSG(restart_in_progress) = 0;
246	if (fcntl(lock_file, F_SETLK, &restart_finished) == -1) {
247		zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(-1):  %s (%d)", strerror(errno), errno);
248	}
249#endif
250}
251
252static inline int accel_restart_is_active(void)
253{
254	if (ZCSG(restart_in_progress)) {
255#ifndef ZEND_WIN32
256		FLOCK_STRUCTURE(restart_check, F_WRLCK, SEEK_SET, 2, 1);
257
258		if (fcntl(lock_file, F_GETLK, &restart_check) == -1) {
259			zend_accel_error(ACCEL_LOG_DEBUG, "RestartC:  %s (%d)", strerror(errno), errno);
260			return FAILURE;
261		}
262		if (restart_check.l_type == F_UNLCK) {
263			ZCSG(restart_in_progress) = 0;
264			return 0;
265		} else {
266			return 1;
267		}
268#else
269		return LOCKVAL(restart_in) != 0;
270#endif
271	}
272	return 0;
273}
274
275/* Creates a read lock for SHM access */
276static inline int accel_activate_add(void)
277{
278#ifdef ZEND_WIN32
279	INCREMENT(mem_usage);
280#else
281	static const FLOCK_STRUCTURE(mem_usage_lock, F_RDLCK, SEEK_SET, 1, 1);
282
283	if (fcntl(lock_file, F_SETLK, &mem_usage_lock) == -1) {
284		zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(+1):  %s (%d)", strerror(errno), errno);
285		return FAILURE;
286	}
287#endif
288	return SUCCESS;
289}
290
291/* Releases a lock for SHM access */
292static inline void accel_deactivate_sub(void)
293{
294#ifdef ZEND_WIN32
295	if (ZCG(counted)) {
296		DECREMENT(mem_usage);
297		ZCG(counted) = 0;
298	}
299#else
300	static const FLOCK_STRUCTURE(mem_usage_unlock, F_UNLCK, SEEK_SET, 1, 1);
301
302	if (fcntl(lock_file, F_SETLK, &mem_usage_unlock) == -1) {
303		zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(-1):  %s (%d)", strerror(errno), errno);
304	}
305#endif
306}
307
308static inline void accel_unlock_all(void)
309{
310#ifdef ZEND_WIN32
311	accel_deactivate_sub();
312#else
313	static const FLOCK_STRUCTURE(mem_usage_unlock_all, F_UNLCK, SEEK_SET, 0, 0);
314
315	if (fcntl(lock_file, F_SETLK, &mem_usage_unlock_all) == -1) {
316		zend_accel_error(ACCEL_LOG_DEBUG, "UnlockAll:  %s (%d)", strerror(errno), errno);
317	}
318#endif
319}
320
321/* Interned strings support */
322static zend_string *(*orig_new_interned_string)(zend_string *str);
323static void (*orig_interned_strings_snapshot)(void);
324static void (*orig_interned_strings_restore)(void);
325
326/* O+ disables creation of interned strings by regular PHP compiler, instead,
327 * it creates interned strings in shared memory when saves a script.
328 * Such interned strings are shared across all PHP processes
329 */
330static zend_string *accel_new_interned_string_for_php(zend_string *str)
331{
332	return str;
333}
334
335static void accel_interned_strings_snapshot_for_php(void)
336{
337}
338
339static void accel_interned_strings_restore_for_php(void)
340{
341}
342
343#ifndef ZTS
344static void accel_interned_strings_restore_state(void)
345{
346    uint idx = ZCSG(interned_strings).nNumUsed;
347    uint nIndex;
348    Bucket *p;
349
350	memset(ZCSG(interned_strings_saved_top),
351			0, ZCSG(interned_strings_top) - ZCSG(interned_strings_saved_top));
352	ZCSG(interned_strings_top) = ZCSG(interned_strings_saved_top);
353    while (idx > 0) {
354    	idx--;
355		p = ZCSG(interned_strings).arData + idx;
356		if ((char*)p->key < ZCSG(interned_strings_top)) break;
357		ZCSG(interned_strings).nNumUsed--;
358		ZCSG(interned_strings).nNumOfElements--;
359
360		nIndex = p->h | ZCSG(interned_strings).nTableMask;
361		if (HT_HASH(&ZCSG(interned_strings), nIndex) == HT_IDX_TO_HASH(idx)) {
362			HT_HASH(&ZCSG(interned_strings), nIndex) = Z_NEXT(p->val);
363		} else {
364			uint32_t prev = HT_HASH(&ZCSG(interned_strings), nIndex);
365			while (Z_NEXT(HT_HASH_TO_BUCKET(&ZCSG(interned_strings), prev)->val) != idx) {
366				prev = Z_NEXT(HT_HASH_TO_BUCKET(&ZCSG(interned_strings), prev)->val);
367 			}
368			Z_NEXT(HT_HASH_TO_BUCKET(&ZCSG(interned_strings), prev)->val) = Z_NEXT(p->val);
369 		}
370	}
371}
372
373static void accel_interned_strings_save_state(void)
374{
375	ZCSG(interned_strings_saved_top) = ZCSG(interned_strings_top);
376}
377#endif
378
379#ifndef ZTS
380static zend_string *accel_find_interned_string(zend_string *str)
381{
382/* for now interned strings are supported only for non-ZTS build */
383	zend_ulong h;
384	uint nIndex;
385	uint idx;
386	Bucket *arData, *p;
387
388	if (IS_ACCEL_INTERNED(str)) {
389		/* this is already an interned string */
390		return str;
391	}
392	if (!ZCG(counted)) {
393		if (accel_activate_add() == FAILURE) {
394			return str;
395		}
396		ZCG(counted) = 1;
397	}
398
399	h = zend_string_hash_val(str);
400	nIndex = h | ZCSG(interned_strings).nTableMask;
401
402	/* check for existing interned string */
403	idx = HT_HASH(&ZCSG(interned_strings), nIndex);
404	arData = ZCSG(interned_strings).arData;
405	while (idx != HT_INVALID_IDX) {
406		p = HT_HASH_TO_BUCKET_EX(arData, idx);
407		if ((p->h == h) && (ZSTR_LEN(p->key) == ZSTR_LEN(str))) {
408			if (!memcmp(ZSTR_VAL(p->key), ZSTR_VAL(str), ZSTR_LEN(str))) {
409				return p->key;
410			}
411		}
412		idx = Z_NEXT(p->val);
413	}
414
415	return NULL;
416}
417#endif
418
419zend_string *accel_new_interned_string(zend_string *str)
420{
421/* for now interned strings are supported only for non-ZTS build */
422#ifndef ZTS
423	zend_ulong h;
424	uint nIndex;
425	uint idx;
426	Bucket *p;
427
428#ifdef HAVE_OPCACHE_FILE_CACHE
429	if (ZCG(accel_directives).file_cache_only) {
430		return str;
431	}
432#endif
433
434	if (IS_ACCEL_INTERNED(str)) {
435		/* this is already an interned string */
436		return str;
437	}
438
439	h = zend_string_hash_val(str);
440	nIndex = h | ZCSG(interned_strings).nTableMask;
441
442	/* check for existing interned string */
443	idx = HT_HASH(&ZCSG(interned_strings), nIndex);
444	while (idx != HT_INVALID_IDX) {
445		p = HT_HASH_TO_BUCKET(&ZCSG(interned_strings), idx);
446		if ((p->h == h) && (ZSTR_LEN(p->key) == ZSTR_LEN(str))) {
447			if (!memcmp(ZSTR_VAL(p->key), ZSTR_VAL(str), ZSTR_LEN(str))) {
448				zend_string_release(str);
449				return p->key;
450			}
451		}
452		idx = Z_NEXT(p->val);
453	}
454
455	if (ZCSG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(ZSTR_LEN(str))) >=
456	    ZCSG(interned_strings_end)) {
457	    /* no memory, return the same non-interned string */
458		zend_accel_error(ACCEL_LOG_WARNING, "Interned string buffer overflow");
459		return str;
460	}
461
462	/* create new interning string in shared interned strings buffer */
463
464	idx = ZCSG(interned_strings).nNumUsed++;
465	ZCSG(interned_strings).nNumOfElements++;
466	p = ZCSG(interned_strings).arData + idx;
467	p->key = (zend_string*) ZCSG(interned_strings_top);
468	ZCSG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(ZSTR_LEN(str)));
469	p->h = h;
470	GC_REFCOUNT(p->key) = 1;
471#if 1
472	/* optimized single assignment */
473	GC_TYPE_INFO(p->key) = IS_STRING | ((IS_STR_INTERNED | IS_STR_PERMANENT) << 8);
474#else
475	GC_TYPE(p->key) = IS_STRING;
476	GC_FLAGS(p->key) = IS_STR_INTERNED | IS_STR_PERMANENT;
477#endif
478	ZSTR_H(p->key) = ZSTR_H(str);
479	ZSTR_LEN(p->key) = ZSTR_LEN(str);
480	memcpy(ZSTR_VAL(p->key), ZSTR_VAL(str), ZSTR_LEN(str));
481	ZVAL_INTERNED_STR(&p->val, p->key);
482	Z_NEXT(p->val) = HT_HASH(&ZCSG(interned_strings), nIndex);
483	HT_HASH(&ZCSG(interned_strings), nIndex) = HT_IDX_TO_HASH(idx);
484	zend_string_release(str);
485	return p->key;
486#else
487	return str;
488#endif
489}
490
491#ifndef ZTS
492/* Copy PHP interned strings from PHP process memory into the shared memory */
493static void accel_use_shm_interned_strings(void)
494{
495	uint idx, j;
496	Bucket *p, *q;
497
498	/* empty string */
499	CG(empty_string) = accel_new_interned_string(CG(empty_string));
500	for (j = 0; j < 256; j++) {
501		char s[2];
502		s[0] = j;
503		s[1] = 0;
504		CG(one_char_string)[j] = accel_new_interned_string(zend_string_init(s, 1, 0));
505	}
506
507	/* function table hash keys */
508	for (idx = 0; idx < CG(function_table)->nNumUsed; idx++) {
509		p = CG(function_table)->arData + idx;
510		if (Z_TYPE(p->val) == IS_UNDEF) continue;
511		if (p->key) {
512			p->key = accel_new_interned_string(p->key);
513		}
514		if (Z_FUNC(p->val)->common.function_name) {
515			Z_FUNC(p->val)->common.function_name = accel_new_interned_string(Z_FUNC(p->val)->common.function_name);
516		}
517	}
518
519	/* class table hash keys, class names, properties, methods, constants, etc */
520	for (idx = 0; idx < CG(class_table)->nNumUsed; idx++) {
521		zend_class_entry *ce;
522
523		p = CG(class_table)->arData + idx;
524		if (Z_TYPE(p->val) == IS_UNDEF) continue;
525		ce = (zend_class_entry*)Z_PTR(p->val);
526
527		if (p->key) {
528			p->key = accel_new_interned_string(p->key);
529		}
530
531		if (ce->name) {
532			ce->name = accel_new_interned_string(ce->name);
533		}
534
535		for (j = 0; j < ce->properties_info.nNumUsed; j++) {
536			zend_property_info *info;
537
538			q = ce->properties_info.arData + j;
539			if (Z_TYPE(q->val) == IS_UNDEF) continue;
540
541			info = (zend_property_info*)Z_PTR(q->val);
542
543			if (q->key) {
544				q->key = accel_new_interned_string(q->key);
545			}
546
547			if (info->name) {
548				info->name = accel_new_interned_string(info->name);
549			}
550		}
551
552		for (j = 0; j < ce->function_table.nNumUsed; j++) {
553			q = ce->function_table.arData + j;
554			if (Z_TYPE(q->val) == IS_UNDEF) continue;
555			if (q->key) {
556				q->key = accel_new_interned_string(q->key);
557			}
558			if (Z_FUNC(q->val)->common.function_name) {
559				Z_FUNC(q->val)->common.function_name = accel_new_interned_string(Z_FUNC(q->val)->common.function_name);
560			}
561		}
562
563		for (j = 0; j < ce->constants_table.nNumUsed; j++) {
564			q = ce->constants_table.arData + j;
565			if (!Z_TYPE(q->val) == IS_UNDEF) continue;
566			if (q->key) {
567				q->key = accel_new_interned_string(q->key);
568			}
569		}
570	}
571
572	/* constant hash keys */
573	for (idx = 0; idx < EG(zend_constants)->nNumUsed; idx++) {
574		p = EG(zend_constants)->arData + idx;
575		if (!Z_TYPE(p->val) == IS_UNDEF) continue;
576		if (p->key) {
577			p->key = accel_new_interned_string(p->key);
578		}
579	}
580
581	/* auto globals hash keys and names */
582	for (idx = 0; idx < CG(auto_globals)->nNumUsed; idx++) {
583		zend_auto_global *auto_global;
584
585		p = CG(auto_globals)->arData + idx;
586		if (Z_TYPE(p->val) == IS_UNDEF) continue;
587
588		auto_global = (zend_auto_global*)Z_PTR(p->val);;
589
590		zend_string_addref(auto_global->name);
591		auto_global->name = accel_new_interned_string(auto_global->name);
592		if (p->key) {
593			p->key = accel_new_interned_string(p->key);
594		}
595	}
596}
597#endif
598
599#ifndef ZEND_WIN32
600static inline void kill_all_lockers(struct flock *mem_usage_check)
601{
602	int tries = 10;
603
604	/* so that other process won't try to force while we are busy cleaning up */
605	ZCSG(force_restart_time) = 0;
606	while (mem_usage_check->l_pid > 0) {
607		while (tries--) {
608			zend_accel_error(ACCEL_LOG_ERROR, "Killed locker %d", mem_usage_check->l_pid);
609			if (kill(mem_usage_check->l_pid, SIGKILL)) {
610				break;
611			}
612			/* give it a chance to die */
613			usleep(20000);
614			if (kill(mem_usage_check->l_pid, 0)) {
615				/* can't kill it */
616				break;
617			}
618			usleep(10000);
619		}
620		if (!tries) {
621			zend_accel_error(ACCEL_LOG_ERROR, "Can't kill %d after 20 tries!", mem_usage_check->l_pid);
622			ZCSG(force_restart_time) = time(NULL); /* restore forced restart request */
623		}
624
625		mem_usage_check->l_type = F_WRLCK;
626		mem_usage_check->l_whence = SEEK_SET;
627		mem_usage_check->l_start = 1;
628		mem_usage_check->l_len = 1;
629		mem_usage_check->l_pid = -1;
630		if (fcntl(lock_file, F_GETLK, mem_usage_check) == -1) {
631			zend_accel_error(ACCEL_LOG_DEBUG, "KLockers:  %s (%d)", strerror(errno), errno);
632			break;
633		}
634
635		if (mem_usage_check->l_type == F_UNLCK || mem_usage_check->l_pid <= 0) {
636			break;
637		}
638	}
639}
640#endif
641
642static inline int accel_is_inactive(void)
643{
644#ifdef ZEND_WIN32
645	if (LOCKVAL(mem_usage) == 0) {
646		return SUCCESS;
647	}
648#else
649	FLOCK_STRUCTURE(mem_usage_check, F_WRLCK, SEEK_SET, 1, 1);
650
651	mem_usage_check.l_pid = -1;
652	if (fcntl(lock_file, F_GETLK, &mem_usage_check) == -1) {
653		zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC:  %s (%d)", strerror(errno), errno);
654		return FAILURE;
655	}
656	if (mem_usage_check.l_type == F_UNLCK) {
657		return SUCCESS;
658	}
659
660	if (ZCG(accel_directives).force_restart_timeout
661		&& ZCSG(force_restart_time)
662		&& time(NULL) >= ZCSG(force_restart_time)) {
663		zend_accel_error(ACCEL_LOG_WARNING, "Forced restart at %d (after %d seconds), locked by %d", time(NULL), ZCG(accel_directives).force_restart_timeout, mem_usage_check.l_pid);
664		kill_all_lockers(&mem_usage_check);
665
666		return FAILURE; /* next request should be able to restart it */
667	}
668#endif
669
670	return FAILURE;
671}
672
673static int zend_get_stream_timestamp(const char *filename, zend_stat_t *statbuf)
674{
675	php_stream_wrapper *wrapper;
676	php_stream_statbuf stream_statbuf;
677	int ret, er;
678
679	if (!filename) {
680		return FAILURE;
681	}
682
683	wrapper = php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY);
684	if (!wrapper) {
685		return FAILURE;
686	}
687	if (!wrapper->wops || !wrapper->wops->url_stat) {
688		statbuf->st_mtime = 1;
689		return SUCCESS; /* anything other than 0 is considered to be a valid timestamp */
690	}
691
692	er = EG(error_reporting);
693	EG(error_reporting) = 0;
694	zend_try {
695		ret = wrapper->wops->url_stat(wrapper, (char*)filename, PHP_STREAM_URL_STAT_QUIET, &stream_statbuf, NULL);
696	} zend_catch {
697		ret = -1;
698	} zend_end_try();
699	EG(error_reporting) = er;
700
701	if (ret != 0) {
702		return FAILURE;
703	}
704
705	*statbuf = stream_statbuf.sb;
706	return SUCCESS;
707}
708
709#if ZEND_WIN32
710static accel_time_t zend_get_file_handle_timestamp_win(zend_file_handle *file_handle, size_t *size)
711{
712	static unsigned __int64 utc_base = 0;
713	static FILETIME utc_base_ft;
714	WIN32_FILE_ATTRIBUTE_DATA fdata;
715
716	if (!file_handle->opened_path) {
717		return 0;
718	}
719
720	if (!utc_base) {
721		SYSTEMTIME st;
722
723		st.wYear = 1970;
724		st.wMonth = 1;
725		st.wDay = 1;
726		st.wHour = 0;
727		st.wMinute = 0;
728		st.wSecond = 0;
729		st.wMilliseconds = 0;
730
731		SystemTimeToFileTime (&st, &utc_base_ft);
732		utc_base = (((unsigned __int64)utc_base_ft.dwHighDateTime) << 32) + utc_base_ft.dwLowDateTime;
733    }
734
735	if (file_handle->opened_path && GetFileAttributesEx(file_handle->opened_path->val, GetFileExInfoStandard, &fdata) != 0) {
736		unsigned __int64 ftime;
737
738		if (CompareFileTime (&fdata.ftLastWriteTime, &utc_base_ft) < 0) {
739			return 0;
740		}
741
742		ftime = (((unsigned __int64)fdata.ftLastWriteTime.dwHighDateTime) << 32) + fdata.ftLastWriteTime.dwLowDateTime - utc_base;
743		ftime /= 10000000L;
744
745		if (size) {
746			*size = (size_t)((((unsigned __int64)fdata.nFileSizeHigh) << 32) + (unsigned __int64)fdata.nFileSizeLow);
747		}
748		return (accel_time_t)ftime;
749	}
750	return 0;
751}
752#endif
753
754accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size)
755{
756	zend_stat_t statbuf;
757#ifdef ZEND_WIN32
758	accel_time_t res;
759#endif
760
761	if (sapi_module.get_stat &&
762	    !EG(current_execute_data) &&
763	    file_handle->filename == SG(request_info).path_translated) {
764
765		zend_stat_t *tmpbuf = sapi_module.get_stat();
766
767		if (tmpbuf) {
768			if (size) {
769				*size = tmpbuf->st_size;
770			}
771			return tmpbuf->st_mtime;
772		}
773	}
774
775#ifdef ZEND_WIN32
776	res = zend_get_file_handle_timestamp_win(file_handle, size);
777	if (res) {
778		return res;
779	}
780#endif
781
782	switch (file_handle->type) {
783		case ZEND_HANDLE_FD:
784			if (zend_fstat(file_handle->handle.fd, &statbuf) == -1) {
785				return 0;
786			}
787			break;
788		case ZEND_HANDLE_FP:
789			if (zend_fstat(fileno(file_handle->handle.fp), &statbuf) == -1) {
790				if (zend_get_stream_timestamp(file_handle->filename, &statbuf) != SUCCESS) {
791					return 0;
792				}
793			}
794			break;
795		case ZEND_HANDLE_FILENAME:
796		case ZEND_HANDLE_MAPPED:
797			if (file_handle->opened_path) {
798				char *file_path = ZSTR_VAL(file_handle->opened_path);
799
800				if (is_stream_path(file_path)) {
801					if (zend_get_stream_timestamp(file_path, &statbuf) == SUCCESS) {
802						break;
803					}
804				}
805				if (VCWD_STAT(file_path, &statbuf) != -1) {
806					break;
807				}
808			}
809
810			if (zend_get_stream_timestamp(file_handle->filename, &statbuf) != SUCCESS) {
811				return 0;
812			}
813			break;
814		case ZEND_HANDLE_STREAM:
815			{
816				php_stream *stream = (php_stream *)file_handle->handle.stream.handle;
817				php_stream_statbuf sb;
818				int ret, er;
819
820				if (!stream ||
821				    !stream->ops ||
822				    !stream->ops->stat) {
823					return 0;
824				}
825
826				er = EG(error_reporting);
827				EG(error_reporting) = 0;
828				zend_try {
829					ret = stream->ops->stat(stream, &sb);
830				} zend_catch {
831					ret = -1;
832				} zend_end_try();
833				EG(error_reporting) = er;
834				if (ret != 0) {
835					return 0;
836				}
837
838				statbuf = sb.sb;
839			}
840			break;
841
842		default:
843			return 0;
844	}
845
846	if (size) {
847		*size = statbuf.st_size;
848	}
849	return statbuf.st_mtime;
850}
851
852static inline int do_validate_timestamps(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
853{
854	zend_file_handle ps_handle;
855	zend_string *full_path_ptr = NULL;
856
857	/** check that the persistent script is indeed the same file we cached
858	 * (if part of the path is a symlink than it possible that the user will change it)
859	 * See bug #15140
860	 */
861	if (file_handle->opened_path) {
862		if (persistent_script->script.filename != file_handle->opened_path &&
863		    (ZSTR_LEN(persistent_script->script.filename) != ZSTR_LEN(file_handle->opened_path) ||
864		     memcmp(ZSTR_VAL(persistent_script->script.filename), ZSTR_VAL(file_handle->opened_path), ZSTR_LEN(file_handle->opened_path)) != 0)) {
865			return FAILURE;
866		}
867	} else {
868		full_path_ptr = accelerator_orig_zend_resolve_path(file_handle->filename, strlen(file_handle->filename));
869		if (full_path_ptr &&
870		    persistent_script->script.filename != full_path_ptr &&
871		    (ZSTR_LEN(persistent_script->script.filename) != ZSTR_LEN(full_path_ptr) ||
872		     memcmp(ZSTR_VAL(persistent_script->script.filename), ZSTR_VAL(full_path_ptr), ZSTR_LEN(full_path_ptr)) != 0)) {
873			zend_string_release(full_path_ptr);
874			return FAILURE;
875		}
876		file_handle->opened_path = full_path_ptr;
877	}
878
879	if (persistent_script->timestamp == 0) {
880		if (full_path_ptr) {
881			zend_string_release(full_path_ptr);
882			file_handle->opened_path = NULL;
883		}
884		return FAILURE;
885	}
886
887	if (zend_get_file_handle_timestamp(file_handle, NULL) == persistent_script->timestamp) {
888		if (full_path_ptr) {
889			zend_string_release(full_path_ptr);
890			file_handle->opened_path = NULL;
891		}
892		return SUCCESS;
893	}
894	if (full_path_ptr) {
895		zend_string_release(full_path_ptr);
896		file_handle->opened_path = NULL;
897	}
898
899	ps_handle.type = ZEND_HANDLE_FILENAME;
900	ps_handle.filename = ZSTR_VAL(persistent_script->script.filename);
901	ps_handle.opened_path = persistent_script->script.filename;
902
903	if (zend_get_file_handle_timestamp(&ps_handle, NULL) == persistent_script->timestamp) {
904		return SUCCESS;
905	}
906
907	return FAILURE;
908}
909
910int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
911{
912	if (ZCG(accel_directives).revalidate_freq &&
913	    persistent_script->dynamic_members.revalidate >= ZCG(request_time)) {
914		return SUCCESS;
915	} else if (do_validate_timestamps(persistent_script, file_handle) == FAILURE) {
916		return FAILURE;
917	} else {
918		persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
919		return SUCCESS;
920	}
921}
922
923/* Instead of resolving full real path name each time we need to identify file,
924 * we create a key that consist from requested file name, current working
925 * directory, current include_path, etc */
926char *accel_make_persistent_key(const char *path, int path_length, int *key_len)
927{
928	int key_length;
929
930	/* CWD and include_path don't matter for absolute file names and streams */
931    if (IS_ABSOLUTE_PATH(path, path_length)) {
932		/* pass */
933		ZCG(key_len) = 0;
934    } else if (UNEXPECTED(is_stream_path(path))) {
935		if (!is_cacheable_stream_path(path)) {
936			return NULL;
937		}
938		/* pass */
939		ZCG(key_len) = 0;
940    } else if (UNEXPECTED(!ZCG(accel_directives).use_cwd)) {
941		/* pass */
942		ZCG(key_len) = 0;
943    } else {
944		const char *include_path = NULL, *cwd = NULL;
945		int include_path_len = 0, cwd_len = 0;
946		zend_string *parent_script = NULL;
947		size_t parent_script_len = 0;
948
949		if (EXPECTED(ZCG(cwd_key_len))) {
950			cwd = ZCG(cwd_key);
951			cwd_len = ZCG(cwd_key_len);
952		} else {
953			zend_string *cwd_str = accel_getcwd();
954
955			if (UNEXPECTED(!cwd_str)) {
956				/* we don't handle this well for now. */
957				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);
958				return NULL;
959			}
960			cwd = ZSTR_VAL(cwd_str);
961			cwd_len = ZSTR_LEN(cwd_str);
962#ifndef ZTS
963			if (ZCG(cwd_check)) {
964				ZCG(cwd_check) = 0;
965				if ((ZCG(counted) || ZCSG(accelerator_enabled))) {
966
967					zend_string *str = accel_find_interned_string(cwd_str);
968					if (!str) {
969						SHM_UNPROTECT();
970						zend_shared_alloc_lock();
971						str = accel_new_interned_string(zend_string_copy(cwd_str));
972						if (str == cwd_str) {
973							zend_string_release(str);
974							str = NULL;
975						}
976						zend_shared_alloc_unlock();
977						SHM_PROTECT();
978					}
979					if (str) {
980						char buf[32];
981						char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, ZSTR_VAL(str) - ZCSG(interned_strings_start));
982
983						cwd_len = ZCG(cwd_key_len) = buf + sizeof(buf) - 1 - res;
984						cwd = ZCG(cwd_key);
985						memcpy(ZCG(cwd_key), res, cwd_len + 1);
986					}
987				}
988			}
989#endif
990		}
991
992		if (EXPECTED(ZCG(include_path_key_len))) {
993			include_path = ZCG(include_path_key);
994			include_path_len = ZCG(include_path_key_len);
995		} else if (!ZCG(include_path) || ZSTR_LEN(ZCG(include_path)) == 0) {
996			include_path = "";
997			include_path_len = 0;
998		} else {
999			include_path = ZSTR_VAL(ZCG(include_path));
1000			include_path_len = ZSTR_LEN(ZCG(include_path));
1001
1002#ifndef ZTS
1003			if (ZCG(include_path_check)) {
1004				ZCG(include_path_check) = 0;
1005				if ((ZCG(counted) || ZCSG(accelerator_enabled))) {
1006
1007					zend_string *str = accel_find_interned_string(ZCG(include_path));
1008					if (!str) {
1009						SHM_UNPROTECT();
1010						zend_shared_alloc_lock();
1011						str = accel_new_interned_string(zend_string_copy(ZCG(include_path)));
1012						if (str == ZCG(include_path)) {
1013							str = NULL;
1014						}
1015						zend_shared_alloc_unlock();
1016						SHM_PROTECT();
1017					}
1018					if (str) {
1019						char buf[32];
1020						char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, ZSTR_VAL(str) - ZCSG(interned_strings_start));
1021
1022						include_path_len = ZCG(include_path_key_len) = buf + sizeof(buf) - 1 - res;
1023						include_path = ZCG(include_path_key);
1024						memcpy(ZCG(include_path_key), res, include_path_len + 1);
1025					}
1026				}
1027			}
1028#endif
1029		}
1030
1031		/* Calculate key length */
1032		if (UNEXPECTED((size_t)(cwd_len + path_length + include_path_len + 2) >= sizeof(ZCG(key)))) {
1033			return NULL;
1034		}
1035
1036		/* Generate key
1037		 * Note - the include_path must be the last element in the key,
1038		 * since in itself, it may include colons (which we use to separate
1039		 * different components of the key)
1040		 */
1041		memcpy(ZCG(key), path, path_length);
1042		ZCG(key)[path_length] = ':';
1043		key_length = path_length + 1;
1044		memcpy(ZCG(key) + key_length, cwd, cwd_len);
1045		key_length += cwd_len;
1046
1047		if (include_path_len) {
1048			ZCG(key)[key_length] = ':';
1049			key_length += 1;
1050			memcpy(ZCG(key) + key_length, include_path, include_path_len);
1051			key_length += include_path_len;
1052		}
1053
1054		/* Here we add to the key the parent script directory,
1055		 * since fopen_wrappers from version 4.0.7 use current script's path
1056		 * in include path too.
1057		 */
1058		if (EXPECTED(EG(current_execute_data)) &&
1059		    EXPECTED((parent_script = zend_get_executed_filename_ex()) != NULL)) {
1060
1061			parent_script_len = ZSTR_LEN(parent_script);
1062			while ((--parent_script_len > 0) && !IS_SLASH(ZSTR_VAL(parent_script)[parent_script_len]));
1063
1064			if (UNEXPECTED((size_t)(key_length + parent_script_len + 1) >= sizeof(ZCG(key)))) {
1065				return NULL;
1066			}
1067			ZCG(key)[key_length] = ':';
1068			key_length += 1;
1069			memcpy(ZCG(key) + key_length, ZSTR_VAL(parent_script), parent_script_len);
1070			key_length += parent_script_len;
1071		}
1072		ZCG(key)[key_length] = '\0';
1073		*key_len = ZCG(key_len) = key_length;
1074		return ZCG(key);
1075	}
1076
1077	/* not use_cwd */
1078	*key_len = path_length;
1079	return (char*)path;
1080}
1081
1082int zend_accel_invalidate(const char *filename, int filename_len, zend_bool force)
1083{
1084	zend_string *realpath;
1085	zend_persistent_script *persistent_script;
1086
1087	if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) {
1088		return FAILURE;
1089	}
1090
1091	realpath = accelerator_orig_zend_resolve_path(filename, filename_len);
1092
1093	if (!realpath) {
1094		return FAILURE;
1095	}
1096
1097#ifdef HAVE_OPCACHE_FILE_CACHE
1098	if (ZCG(accel_directives).file_cache) {
1099		zend_file_cache_invalidate(realpath);
1100	}
1101#endif
1102
1103	persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath);
1104	if (persistent_script && !persistent_script->corrupted) {
1105		zend_file_handle file_handle;
1106
1107		file_handle.type = ZEND_HANDLE_FILENAME;
1108		file_handle.filename = ZSTR_VAL(realpath);
1109		file_handle.opened_path = realpath;
1110
1111		if (force ||
1112			!ZCG(accel_directives).validate_timestamps ||
1113			do_validate_timestamps(persistent_script, &file_handle) == FAILURE) {
1114			SHM_UNPROTECT();
1115			zend_shared_alloc_lock();
1116			if (!persistent_script->corrupted) {
1117				persistent_script->corrupted = 1;
1118				persistent_script->timestamp = 0;
1119				ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1120				if (ZSMMG(memory_exhausted)) {
1121					zend_accel_restart_reason reason =
1122						zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
1123					zend_accel_schedule_restart_if_necessary(reason);
1124				}
1125			}
1126			zend_shared_alloc_unlock();
1127			SHM_PROTECT();
1128		}
1129	}
1130
1131	accelerator_shm_read_unlock();
1132	zend_string_release(realpath);
1133
1134	return SUCCESS;
1135}
1136
1137/* Adds another key for existing cached script */
1138static void zend_accel_add_key(char *key, unsigned int key_length, zend_accel_hash_entry *bucket)
1139{
1140	if (!zend_accel_hash_str_find(&ZCSG(hash), key, key_length)) {
1141		if (zend_accel_hash_is_full(&ZCSG(hash))) {
1142			zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1143			ZSMMG(memory_exhausted) = 1;
1144			zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
1145		} else {
1146			char *new_key = zend_shared_alloc(key_length + 1);
1147			if (new_key) {
1148				memcpy(new_key, key, key_length + 1);
1149				if (zend_accel_hash_update(&ZCSG(hash), new_key, key_length, 1, bucket)) {
1150					zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", new_key);
1151				}
1152			} else {
1153				zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
1154			}
1155		}
1156	}
1157}
1158
1159#ifdef HAVE_OPCACHE_FILE_CACHE
1160static zend_persistent_script *cache_script_in_file_cache(zend_persistent_script *new_persistent_script, int *from_shared_memory)
1161{
1162	uint memory_used;
1163
1164	/* Check if script may be stored in shared memory */
1165	if (!zend_accel_script_persistable(new_persistent_script)) {
1166		return new_persistent_script;
1167	}
1168
1169	if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) {
1170		return new_persistent_script;
1171	}
1172
1173	zend_shared_alloc_init_xlat_table();
1174
1175	/* Calculate the required memory size */
1176	memory_used = zend_accel_script_persist_calc(new_persistent_script, NULL, 0);
1177
1178	/* Allocate memory block */
1179#ifdef __SSE2__
1180	/* Align to 64-byte boundary */
1181	ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used + 64);
1182	ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
1183#else
1184	ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used);
1185#endif
1186
1187	/* Copy into shared memory */
1188	new_persistent_script = zend_accel_script_persist(new_persistent_script, NULL, 0);
1189
1190	zend_shared_alloc_destroy_xlat_table();
1191
1192	new_persistent_script->is_phar =
1193		new_persistent_script->script.filename &&
1194		strstr(ZSTR_VAL(new_persistent_script->script.filename), ".phar") &&
1195		!strstr(ZSTR_VAL(new_persistent_script->script.filename), "://");
1196
1197	/* Consistency check */
1198	if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
1199		zend_accel_error(
1200			((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
1201			"Internal error: wrong size calculation: %s start=0x%08x, end=0x%08x, real=0x%08x\n",
1202			ZSTR_VAL(new_persistent_script->script.filename),
1203			new_persistent_script->mem,
1204			(char *)new_persistent_script->mem + new_persistent_script->size,
1205			ZCG(mem));
1206	}
1207
1208	new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
1209
1210	zend_file_cache_script_store(new_persistent_script, 0);
1211
1212	*from_shared_memory = 1;
1213	return new_persistent_script;
1214}
1215#endif
1216
1217static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_script *new_persistent_script, char *key, unsigned int key_length, int *from_shared_memory)
1218{
1219	zend_accel_hash_entry *bucket;
1220	uint memory_used;
1221
1222	/* Check if script may be stored in shared memory */
1223	if (!zend_accel_script_persistable(new_persistent_script)) {
1224		return new_persistent_script;
1225	}
1226
1227	if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) {
1228		return new_persistent_script;
1229	}
1230
1231	/* exclusive lock */
1232	zend_shared_alloc_lock();
1233
1234	if (zend_accel_hash_is_full(&ZCSG(hash))) {
1235		zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1236		ZSMMG(memory_exhausted) = 1;
1237		zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
1238		zend_shared_alloc_unlock();
1239		return new_persistent_script;
1240	}
1241
1242	/* Check if we still need to put the file into the cache (may be it was
1243	 * already stored by another process. This final check is done under
1244	 * exclusive lock) */
1245	bucket = zend_accel_hash_find_entry(&ZCSG(hash), new_persistent_script->script.filename);
1246	if (bucket) {
1247		zend_persistent_script *existing_persistent_script = (zend_persistent_script *)bucket->data;
1248
1249		if (!existing_persistent_script->corrupted) {
1250			if (key &&
1251			    (!ZCG(accel_directives).validate_timestamps ||
1252			     (new_persistent_script->timestamp == existing_persistent_script->timestamp))) {
1253				zend_accel_add_key(key, key_length, bucket);
1254			}
1255			zend_shared_alloc_unlock();
1256			return new_persistent_script;
1257		}
1258	}
1259
1260
1261	zend_shared_alloc_init_xlat_table();
1262
1263	/* Calculate the required memory size */
1264	memory_used = zend_accel_script_persist_calc(new_persistent_script, key, key_length);
1265
1266	/* Allocate shared memory */
1267#ifdef __SSE2__
1268	/* Align to 64-byte boundary */
1269	ZCG(mem) = zend_shared_alloc(memory_used + 64);
1270	ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
1271#else
1272	ZCG(mem) = zend_shared_alloc(memory_used);
1273#endif
1274	if (!ZCG(mem)) {
1275		zend_shared_alloc_destroy_xlat_table();
1276		zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
1277		zend_shared_alloc_unlock();
1278		return new_persistent_script;
1279	}
1280
1281	/* Copy into shared memory */
1282	new_persistent_script = zend_accel_script_persist(new_persistent_script, &key, key_length);
1283
1284	zend_shared_alloc_destroy_xlat_table();
1285
1286	new_persistent_script->is_phar =
1287		new_persistent_script->script.filename &&
1288		strstr(ZSTR_VAL(new_persistent_script->script.filename), ".phar") &&
1289		!strstr(ZSTR_VAL(new_persistent_script->script.filename), "://");
1290
1291	/* Consistency check */
1292	if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
1293		zend_accel_error(
1294			((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
1295			"Internal error: wrong size calculation: %s start=0x%08x, end=0x%08x, real=0x%08x\n",
1296			ZSTR_VAL(new_persistent_script->script.filename),
1297			new_persistent_script->mem,
1298			(char *)new_persistent_script->mem + new_persistent_script->size,
1299			ZCG(mem));
1300	}
1301
1302	new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
1303
1304	/* store script structure in the hash table */
1305	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);
1306	if (bucket) {
1307		zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", new_persistent_script->script.filename);
1308		if (key &&
1309		    /* key may contain non-persistent PHAR aliases (see issues #115 and #149) */
1310		    memcmp(key, "phar://", sizeof("phar://") - 1) != 0 &&
1311		    (ZSTR_LEN(new_persistent_script->script.filename) != key_length ||
1312		     memcmp(ZSTR_VAL(new_persistent_script->script.filename), key, key_length) != 0)) {
1313			/* link key to the same persistent script in hash table */
1314			if (zend_accel_hash_update(&ZCSG(hash), key, key_length, 1, bucket)) {
1315				zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", key);
1316			} else {
1317				zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
1318				ZSMMG(memory_exhausted) = 1;
1319				zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
1320			}
1321		}
1322	}
1323
1324	new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
1325
1326	zend_shared_alloc_unlock();
1327
1328#ifdef HAVE_OPCACHE_FILE_CACHE
1329	if (ZCG(accel_directives).file_cache) {
1330		SHM_PROTECT();
1331		zend_file_cache_script_store(new_persistent_script, 1);
1332		SHM_UNPROTECT();
1333	}
1334#endif
1335
1336	*from_shared_memory = 1;
1337	return new_persistent_script;
1338}
1339
1340static const struct jit_auto_global_info
1341{
1342    const char *name;
1343    size_t len;
1344} jit_auto_globals_info[] = {
1345    { "_SERVER",  sizeof("_SERVER")-1},
1346    { "_ENV",     sizeof("_ENV")-1},
1347    { "_REQUEST", sizeof("_REQUEST")-1},
1348    { "GLOBALS",  sizeof("GLOBALS")-1},
1349};
1350
1351static zend_string *jit_auto_globals_str[4];
1352
1353static int zend_accel_get_auto_globals(void)
1354{
1355	int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
1356	int n = 1;
1357	int mask = 0;
1358
1359	for (i = 0; i < ag_size ; i++) {
1360		if (zend_hash_exists(&EG(symbol_table), jit_auto_globals_str[i])) {
1361			mask |= n;
1362		}
1363		n += n;
1364	}
1365	return mask;
1366}
1367
1368static int zend_accel_get_auto_globals_no_jit(void)
1369{
1370	if (zend_hash_exists(&EG(symbol_table), jit_auto_globals_str[3])) {
1371		return 8;
1372	}
1373	return 0;
1374}
1375
1376static void zend_accel_set_auto_globals(int mask)
1377{
1378	int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
1379	int n = 1;
1380
1381	for (i = 0; i < ag_size ; i++) {
1382		if ((mask & n) && !(ZCG(auto_globals_mask) & n)) {
1383			ZCG(auto_globals_mask) |= n;
1384			zend_is_auto_global(jit_auto_globals_str[i]);
1385		}
1386		n += n;
1387	}
1388}
1389
1390static void zend_accel_init_auto_globals(void)
1391{
1392	int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
1393
1394	for (i = 0; i < ag_size ; i++) {
1395		jit_auto_globals_str[i] = zend_string_init(jit_auto_globals_info[i].name, jit_auto_globals_info[i].len, 1);
1396		zend_string_hash_val(jit_auto_globals_str[i]);
1397		jit_auto_globals_str[i] = accel_new_interned_string(jit_auto_globals_str[i]);
1398	}
1399}
1400
1401static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handle, int type, char *key, unsigned int key_length, zend_op_array **op_array_p)
1402{
1403	zend_persistent_script *new_persistent_script;
1404	zend_op_array *orig_active_op_array;
1405	HashTable *orig_function_table, *orig_class_table;
1406	zval orig_user_error_handler;
1407	zend_op_array *op_array;
1408	int do_bailout = 0;
1409	accel_time_t timestamp = 0;
1410	uint32_t orig_compiler_options = 0;
1411
1412    /* Try to open file */
1413    if (file_handle->type == ZEND_HANDLE_FILENAME) {
1414        if (accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle) == SUCCESS) {
1415        	/* key may be changed by zend_stream_open_function() */
1416        	if (key == ZCG(key)) {
1417        		key_length = ZCG(key_len);
1418        	}
1419        } else {
1420			*op_array_p = NULL;
1421			if (type == ZEND_REQUIRE) {
1422				zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
1423				zend_bailout();
1424			} else {
1425				zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
1426			}
1427			return NULL;
1428    	}
1429    }
1430
1431	/* check blacklist right after ensuring that file was opened */
1432	if (file_handle->opened_path && zend_accel_blacklist_is_blacklisted(&accel_blacklist, ZSTR_VAL(file_handle->opened_path))) {
1433		ZCSG(blacklist_misses)++;
1434		*op_array_p = accelerator_orig_compile_file(file_handle, type);
1435		return NULL;
1436	}
1437
1438	if (ZCG(accel_directives).validate_timestamps ||
1439	    ZCG(accel_directives).file_update_protection ||
1440	    ZCG(accel_directives).max_file_size > 0) {
1441		size_t size = 0;
1442
1443		/* Obtain the file timestamps, *before* actually compiling them,
1444		 * otherwise we have a race-condition.
1445		 */
1446		timestamp = zend_get_file_handle_timestamp(file_handle, ZCG(accel_directives).max_file_size > 0 ? &size : NULL);
1447
1448		/* If we can't obtain a timestamp (that means file is possibly socket)
1449		 *  we won't cache it
1450		 */
1451		if (timestamp == 0) {
1452			*op_array_p = accelerator_orig_compile_file(file_handle, type);
1453			return NULL;
1454		}
1455
1456		/* check if file is too new (may be it's not written completely yet) */
1457		if (ZCG(accel_directives).file_update_protection &&
1458		    (ZCG(request_time) - ZCG(accel_directives).file_update_protection < timestamp)) {
1459			*op_array_p = accelerator_orig_compile_file(file_handle, type);
1460			return NULL;
1461		}
1462
1463		if (ZCG(accel_directives).max_file_size > 0 && size > (size_t)ZCG(accel_directives).max_file_size) {
1464			ZCSG(blacklist_misses)++;
1465			*op_array_p = accelerator_orig_compile_file(file_handle, type);
1466			return NULL;
1467		}
1468	}
1469
1470	new_persistent_script = create_persistent_script();
1471
1472	/* Save the original values for the op_array, function table and class table */
1473	orig_active_op_array = CG(active_op_array);
1474	orig_function_table = CG(function_table);
1475	orig_class_table = CG(class_table);
1476	ZVAL_COPY_VALUE(&orig_user_error_handler, &EG(user_error_handler));
1477
1478	/* Override them with ours */
1479	CG(function_table) = &ZCG(function_table);
1480	EG(class_table) = CG(class_table) = &new_persistent_script->script.class_table;
1481	ZVAL_UNDEF(&EG(user_error_handler));
1482
1483	zend_try {
1484		orig_compiler_options = CG(compiler_options);
1485		CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
1486		CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES;
1487		CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
1488		CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
1489		op_array = *op_array_p = accelerator_orig_compile_file(file_handle, type);
1490		CG(compiler_options) = orig_compiler_options;
1491	} zend_catch {
1492		op_array = NULL;
1493		do_bailout = 1;
1494		CG(compiler_options) = orig_compiler_options;
1495	} zend_end_try();
1496
1497	/* Restore originals */
1498	CG(active_op_array) = orig_active_op_array;
1499	CG(function_table) = orig_function_table;
1500	EG(class_table) = CG(class_table) = orig_class_table;
1501	EG(user_error_handler) = orig_user_error_handler;
1502
1503	if (!op_array) {
1504		/* compilation failed */
1505		free_persistent_script(new_persistent_script, 1);
1506		zend_accel_free_user_functions(&ZCG(function_table));
1507		if (do_bailout) {
1508			zend_bailout();
1509		}
1510		return NULL;
1511	}
1512
1513	/* Build the persistent_script structure.
1514	   Here we aren't sure we would store it, but we will need it
1515	   further anyway.
1516	*/
1517	zend_accel_move_user_functions(&ZCG(function_table), &new_persistent_script->script.function_table);
1518	new_persistent_script->script.main_op_array = *op_array;
1519
1520	efree(op_array); /* we have valid persistent_script, so it's safe to free op_array */
1521
1522    /* Fill in the ping_auto_globals_mask for the new script. If jit for auto globals is enabled we
1523       will have to ping the used auto global variables before execution */
1524	if (PG(auto_globals_jit)) {
1525		new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals();
1526	} else {
1527		new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals_no_jit();
1528	}
1529
1530	if (ZCG(accel_directives).validate_timestamps) {
1531		/* Obtain the file timestamps, *before* actually compiling them,
1532		 * otherwise we have a race-condition.
1533		 */
1534		new_persistent_script->timestamp = timestamp;
1535		new_persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
1536	}
1537
1538	if (file_handle->opened_path) {
1539		new_persistent_script->script.filename = zend_string_copy(file_handle->opened_path);
1540	} else {
1541		new_persistent_script->script.filename = zend_string_init(file_handle->filename, strlen(file_handle->filename), 0);
1542	}
1543	zend_string_hash_val(new_persistent_script->script.filename);
1544
1545	/* Now persistent_script structure is ready in process memory */
1546	return new_persistent_script;
1547}
1548
1549#ifdef HAVE_OPCACHE_FILE_CACHE
1550zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type)
1551{
1552	zend_persistent_script *persistent_script;
1553	zend_op_array *op_array = NULL;
1554	int from_memory; /* if the script we've got is stored in SHM */
1555
1556	if (is_stream_path(file_handle->filename) &&
1557	    !is_cacheable_stream_path(file_handle->filename)) {
1558		return accelerator_orig_compile_file(file_handle, type);
1559	}
1560
1561	if (!file_handle->opened_path) {
1562		if (file_handle->type == ZEND_HANDLE_FILENAME &&
1563		    accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle) == FAILURE) {
1564			if (type == ZEND_REQUIRE) {
1565				zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
1566				zend_bailout();
1567			} else {
1568				zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
1569			}
1570			return NULL;
1571	    }
1572	}
1573
1574	SHM_UNPROTECT();
1575	persistent_script = zend_file_cache_script_load(file_handle);
1576	SHM_PROTECT();
1577	if (persistent_script) {
1578		/* see bug #15471 (old BTS) */
1579		if (persistent_script->script.filename) {
1580			if (!EG(current_execute_data) || !EG(current_execute_data)->opline ||
1581			    !EG(current_execute_data)->func ||
1582			    !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
1583			    EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
1584			    (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
1585			     EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
1586				if (zend_hash_add_empty_element(&EG(included_files), persistent_script->script.filename) != NULL) {
1587					/* ext/phar has to load phar's metadata into memory */
1588					if (persistent_script->is_phar) {
1589						php_stream_statbuf ssb;
1590						char *fname = emalloc(sizeof("phar://") + ZSTR_LEN(persistent_script->script.filename));
1591
1592						memcpy(fname, "phar://", sizeof("phar://") - 1);
1593						memcpy(fname + sizeof("phar://") - 1, ZSTR_VAL(persistent_script->script.filename), ZSTR_LEN(persistent_script->script.filename) + 1);
1594						php_stream_stat_path(fname, &ssb);
1595						efree(fname);
1596					}
1597				}
1598			}
1599		}
1600		zend_file_handle_dtor(file_handle);
1601
1602	    if (persistent_script->ping_auto_globals_mask) {
1603			zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask);
1604		}
1605
1606		return zend_accel_load_script(persistent_script, 1);
1607	}
1608
1609	persistent_script = opcache_compile_file(file_handle, type, NULL, 0, &op_array);
1610
1611	if (persistent_script) {
1612		from_memory = 0;
1613		persistent_script = cache_script_in_file_cache(persistent_script, &from_memory);
1614		return zend_accel_load_script(persistent_script, from_memory);
1615	}
1616
1617	return op_array;
1618}
1619#endif
1620
1621/* zend_compile() replacement */
1622zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
1623{
1624	zend_persistent_script *persistent_script = NULL;
1625	char *key = NULL;
1626	int key_length;
1627	int from_shared_memory; /* if the script we've got is stored in SHM */
1628
1629	if (!file_handle->filename || !ZCG(enabled) || !accel_startup_ok) {
1630		/* The Accelerator is disabled, act as if without the Accelerator */
1631		return accelerator_orig_compile_file(file_handle, type);
1632#ifdef HAVE_OPCACHE_FILE_CACHE
1633	} else if (ZCG(accel_directives).file_cache_only) {
1634		return file_cache_compile_file(file_handle, type);
1635#endif
1636	} else if ((!ZCG(counted) && !ZCSG(accelerator_enabled)) ||
1637	           (ZCSG(restart_in_progress) && accel_restart_is_active())) {
1638#ifdef HAVE_OPCACHE_FILE_CACHE
1639		if (ZCG(accel_directives).file_cache) {
1640			return file_cache_compile_file(file_handle, type);
1641		}
1642#endif
1643		return accelerator_orig_compile_file(file_handle, type);
1644	}
1645
1646	/* In case this callback is called from include_once, require_once or it's
1647	 * a main FastCGI request, the key must be already calculated, and cached
1648	 * persistent script already found */
1649	if (ZCG(cache_persistent_script) &&
1650	    ((!EG(current_execute_data) &&
1651	      file_handle->filename == SG(request_info).path_translated &&
1652	      ZCG(cache_opline) == NULL) ||
1653	     (EG(current_execute_data) &&
1654	      EG(current_execute_data)->func &&
1655	      ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
1656	      ZCG(cache_opline) == EG(current_execute_data)->opline))) {
1657
1658		persistent_script = ZCG(cache_persistent_script);
1659		if (ZCG(key_len)) {
1660			key = ZCG(key);
1661			key_length = ZCG(key_len);
1662		}
1663
1664	} else {
1665		if (!ZCG(accel_directives).revalidate_path) {
1666			/* try to find cached script by key */
1667			key = accel_make_persistent_key(file_handle->filename, strlen(file_handle->filename), &key_length);
1668			if (!key) {
1669				return accelerator_orig_compile_file(file_handle, type);
1670			}
1671			persistent_script = zend_accel_hash_str_find(&ZCSG(hash), key, key_length);
1672		}
1673		if (!persistent_script) {
1674			/* try to find cached script by full real path */
1675			zend_accel_hash_entry *bucket;
1676
1677			/* open file to resolve the path */
1678		    if (file_handle->type == ZEND_HANDLE_FILENAME &&
1679        		accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle) == FAILURE) {
1680				if (type == ZEND_REQUIRE) {
1681					zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
1682					zend_bailout();
1683				} else {
1684					zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
1685				}
1686				return NULL;
1687		    }
1688
1689			if (file_handle->opened_path) {
1690				bucket = zend_accel_hash_find_entry(&ZCSG(hash), file_handle->opened_path);
1691
1692				if (bucket) {
1693					persistent_script = (zend_persistent_script *)bucket->data;
1694
1695					if (key && !persistent_script->corrupted) {
1696						SHM_UNPROTECT();
1697						zend_shared_alloc_lock();
1698						zend_accel_add_key(key, key_length, bucket);
1699						zend_shared_alloc_unlock();
1700						SHM_PROTECT();
1701					}
1702				}
1703			}
1704		}
1705	}
1706
1707	/* clear cache */
1708	ZCG(cache_opline) = NULL;
1709	ZCG(cache_persistent_script) = NULL;
1710
1711	if (persistent_script && persistent_script->corrupted) {
1712		persistent_script = NULL;
1713	}
1714
1715	/* Make sure we only increase the currently running processes semaphore
1716     * once each execution (this function can be called more than once on
1717     * each execution)
1718     */
1719	if (!ZCG(counted)) {
1720		if (accel_activate_add() == FAILURE) {
1721#ifdef HAVE_OPCACHE_FILE_CACHE
1722			if (ZCG(accel_directives).file_cache) {
1723				return file_cache_compile_file(file_handle, type);
1724			}
1725#endif
1726			return accelerator_orig_compile_file(file_handle, type);
1727		}
1728		ZCG(counted) = 1;
1729	}
1730
1731	SHM_UNPROTECT();
1732
1733	/* If script is found then validate_timestamps if option is enabled */
1734	if (persistent_script && ZCG(accel_directives).validate_timestamps) {
1735		if (validate_timestamp_and_record(persistent_script, file_handle) == FAILURE) {
1736			zend_shared_alloc_lock();
1737			if (!persistent_script->corrupted) {
1738				persistent_script->corrupted = 1;
1739				persistent_script->timestamp = 0;
1740				ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1741				if (ZSMMG(memory_exhausted)) {
1742					zend_accel_restart_reason reason =
1743						zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
1744					zend_accel_schedule_restart_if_necessary(reason);
1745				}
1746			}
1747			zend_shared_alloc_unlock();
1748			persistent_script = NULL;
1749		}
1750	}
1751
1752	/* if turned on - check the compiled script ADLER32 checksum */
1753	if (persistent_script && ZCG(accel_directives).consistency_checks
1754		&& persistent_script->dynamic_members.hits % ZCG(accel_directives).consistency_checks == 0) {
1755
1756		unsigned int checksum = zend_accel_script_checksum(persistent_script);
1757		if (checksum != persistent_script->dynamic_members.checksum ) {
1758			/* The checksum is wrong */
1759			zend_accel_error(ACCEL_LOG_INFO, "Checksum failed for '%s':  expected=0x%0.8X, found=0x%0.8X",
1760							 persistent_script->script.filename, persistent_script->dynamic_members.checksum, checksum);
1761			zend_shared_alloc_lock();
1762			if (!persistent_script->corrupted) {
1763				persistent_script->corrupted = 1;
1764				persistent_script->timestamp = 0;
1765				ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1766				if (ZSMMG(memory_exhausted)) {
1767					zend_accel_restart_reason reason =
1768						zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
1769					zend_accel_schedule_restart_if_necessary(reason);
1770				}
1771			}
1772			zend_shared_alloc_unlock();
1773			persistent_script = NULL;
1774		}
1775	}
1776
1777#ifdef HAVE_OPCACHE_FILE_CACHE
1778	/* Check the second level cache */
1779	if (!persistent_script && ZCG(accel_directives).file_cache) {
1780		persistent_script = zend_file_cache_script_load(file_handle);
1781	}
1782#endif
1783
1784	/* If script was not found or invalidated by validate_timestamps */
1785	if (!persistent_script) {
1786		uint32_t old_const_num = zend_hash_next_free_element(EG(zend_constants));
1787		zend_op_array *op_array;
1788
1789		/* Cache miss.. */
1790		ZCSG(misses)++;
1791
1792		/* No memory left. Behave like without the Accelerator */
1793		if (ZSMMG(memory_exhausted) || ZCSG(restart_pending)) {
1794			SHM_PROTECT();
1795			return accelerator_orig_compile_file(file_handle, type);
1796		}
1797
1798		/* Try and cache the script and assume that it is returned from_shared_memory.
1799         * If it isn't compile_and_cache_file() changes the flag to 0
1800         */
1801       	from_shared_memory = 0;
1802		persistent_script = opcache_compile_file(file_handle, type, key, key ? key_length : 0, &op_array);
1803		if (persistent_script) {
1804			persistent_script = cache_script_in_shared_memory(persistent_script, key, key ? key_length : 0, &from_shared_memory);
1805		}
1806
1807		/* Caching is disabled, returning op_array;
1808		 * or something went wrong during compilation, returning NULL
1809		 */
1810		if (!persistent_script) {
1811			SHM_PROTECT();
1812			return op_array;
1813		}
1814		if (from_shared_memory) {
1815			/* Delete immutable arrays moved into SHM */
1816			uint32_t new_const_num = zend_hash_next_free_element(EG(zend_constants));
1817			while (new_const_num > old_const_num) {
1818				new_const_num--;
1819				zend_hash_index_del(EG(zend_constants), new_const_num);
1820			}
1821		}
1822	} else {
1823
1824#if !ZEND_WIN32
1825		ZCSG(hits)++; /* TBFixed: may lose one hit */
1826		persistent_script->dynamic_members.hits++; /* see above */
1827#else
1828#ifdef _M_X64
1829		InterlockedIncrement64(&ZCSG(hits));
1830#else
1831		InterlockedIncrement(&ZCSG(hits));
1832#endif
1833		InterlockedIncrement64(&persistent_script->dynamic_members.hits);
1834#endif
1835
1836		/* see bug #15471 (old BTS) */
1837		if (persistent_script->script.filename) {
1838			if (!EG(current_execute_data) || !EG(current_execute_data)->opline ||
1839			    !EG(current_execute_data)->func ||
1840			    !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
1841			    EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
1842			    (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
1843			     EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
1844				if (zend_hash_add_empty_element(&EG(included_files), persistent_script->script.filename) != NULL) {
1845					/* ext/phar has to load phar's metadata into memory */
1846					if (persistent_script->is_phar) {
1847						php_stream_statbuf ssb;
1848						char *fname = emalloc(sizeof("phar://") + ZSTR_LEN(persistent_script->script.filename));
1849
1850						memcpy(fname, "phar://", sizeof("phar://") - 1);
1851						memcpy(fname + sizeof("phar://") - 1, ZSTR_VAL(persistent_script->script.filename), ZSTR_LEN(persistent_script->script.filename) + 1);
1852						php_stream_stat_path(fname, &ssb);
1853						efree(fname);
1854					}
1855				}
1856			}
1857		}
1858		zend_file_handle_dtor(file_handle);
1859		from_shared_memory = 1;
1860	}
1861
1862	persistent_script->dynamic_members.last_used = ZCG(request_time);
1863
1864	SHM_PROTECT();
1865
1866    /* Fetch jit auto globals used in the script before execution */
1867    if (persistent_script->ping_auto_globals_mask) {
1868		zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask);
1869	}
1870
1871	return zend_accel_load_script(persistent_script, from_shared_memory);
1872}
1873
1874/* zend_stream_open_function() replacement for PHP 5.3 and above */
1875static int persistent_stream_open_function(const char *filename, zend_file_handle *handle)
1876{
1877	if (ZCG(cache_persistent_script)) {
1878		/* check if callback is called from include_once or it's a main request */
1879		if ((!EG(current_execute_data) &&
1880		     filename == SG(request_info).path_translated &&
1881		     ZCG(cache_opline) == NULL) ||
1882		    (EG(current_execute_data) &&
1883		     EG(current_execute_data)->func &&
1884		     ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
1885		     ZCG(cache_opline) == EG(current_execute_data)->opline)) {
1886
1887			/* we are in include_once or FastCGI request */
1888			handle->filename = (char*)filename;
1889			handle->free_filename = 0;
1890			handle->opened_path = zend_string_copy(ZCG(cache_persistent_script)->script.filename);
1891			handle->type = ZEND_HANDLE_FILENAME;
1892			return SUCCESS;
1893		}
1894		ZCG(cache_opline) = NULL;
1895		ZCG(cache_persistent_script) = NULL;
1896	}
1897	return accelerator_orig_zend_stream_open_function(filename, handle);
1898}
1899
1900/* zend_resolve_path() replacement for PHP 5.3 and above */
1901static zend_string* persistent_zend_resolve_path(const char *filename, int filename_len)
1902{
1903	if (ZCG(enabled) && accel_startup_ok &&
1904	    (ZCG(counted) || ZCSG(accelerator_enabled)) &&
1905	    !ZCSG(restart_in_progress)) {
1906
1907		/* check if callback is called from include_once or it's a main request */
1908		if ((!EG(current_execute_data) &&
1909		     filename == SG(request_info).path_translated) ||
1910		    (EG(current_execute_data) &&
1911		     EG(current_execute_data)->func &&
1912		     ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
1913		     EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
1914		     (EG(current_execute_data)->opline->extended_value == ZEND_INCLUDE_ONCE ||
1915		      EG(current_execute_data)->opline->extended_value == ZEND_REQUIRE_ONCE))) {
1916
1917			/* we are in include_once or FastCGI request */
1918			zend_string *resolved_path;
1919			int key_length;
1920			char *key = NULL;
1921
1922			if (!ZCG(accel_directives).revalidate_path) {
1923				/* lookup by "not-real" path */
1924				key = accel_make_persistent_key(filename, filename_len, &key_length);
1925				if (key) {
1926					zend_accel_hash_entry *bucket = zend_accel_hash_str_find_entry(&ZCSG(hash), key, key_length);
1927					if (bucket != NULL) {
1928						zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
1929						if (!persistent_script->corrupted) {
1930							ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
1931							ZCG(cache_persistent_script) = persistent_script;
1932							return zend_string_copy(persistent_script->script.filename);
1933						}
1934					}
1935				} else {
1936					ZCG(cache_opline) = NULL;
1937					ZCG(cache_persistent_script) = NULL;
1938					return accelerator_orig_zend_resolve_path(filename, filename_len);
1939				}
1940			}
1941
1942			/* find the full real path */
1943			resolved_path = accelerator_orig_zend_resolve_path(filename, filename_len);
1944
1945			if (resolved_path) {
1946				/* lookup by real path */
1947				zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path);
1948				if (bucket) {
1949					zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
1950					if (!persistent_script->corrupted) {
1951						if (key) {
1952							/* add another "key" for the same bucket */
1953							SHM_UNPROTECT();
1954							zend_shared_alloc_lock();
1955							zend_accel_add_key(key, key_length, bucket);
1956							zend_shared_alloc_unlock();
1957							SHM_PROTECT();
1958						} else {
1959							ZCG(key_len) = 0;
1960						}
1961						ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
1962						ZCG(cache_persistent_script) = persistent_script;
1963						return resolved_path;
1964					}
1965				}
1966			}
1967
1968			ZCG(cache_opline) = NULL;
1969			ZCG(cache_persistent_script) = NULL;
1970			return resolved_path;
1971		}
1972	}
1973	ZCG(cache_opline) = NULL;
1974	ZCG(cache_persistent_script) = NULL;
1975	return accelerator_orig_zend_resolve_path(filename, filename_len);
1976}
1977
1978static void zend_reset_cache_vars(void)
1979{
1980	ZSMMG(memory_exhausted) = 0;
1981	ZCSG(hits) = 0;
1982	ZCSG(misses) = 0;
1983	ZCSG(blacklist_misses) = 0;
1984	ZSMMG(wasted_shared_memory) = 0;
1985	ZCSG(restart_pending) = 0;
1986	ZCSG(force_restart_time) = 0;
1987}
1988
1989static void accel_reset_pcre_cache(void)
1990{
1991	Bucket *p;
1992
1993	ZEND_HASH_FOREACH_BUCKET(&PCRE_G(pcre_cache), p) {
1994		/* Remove PCRE cache entries with inconsistent keys */
1995		if (zend_accel_in_shm(p->key)) {
1996			p->key = NULL;
1997			zend_hash_del_bucket(&PCRE_G(pcre_cache), p);
1998		}
1999	} ZEND_HASH_FOREACH_END();
2000}
2001
2002static void accel_activate(void)
2003{
2004	zend_bool reset_pcre = 0;
2005
2006	if (!ZCG(enabled) || !accel_startup_ok) {
2007		return;
2008	}
2009
2010	if (!ZCG(function_table).nTableSize) {
2011		zend_hash_init(&ZCG(function_table), zend_hash_num_elements(CG(function_table)), NULL, ZEND_FUNCTION_DTOR, 1);
2012		zend_accel_copy_internal_functions();
2013	}
2014
2015	/* PHP-5.4 and above return "double", but we use 1 sec precision */
2016	ZCG(auto_globals_mask) = 0;
2017	ZCG(request_time) = (time_t)sapi_get_request_time();
2018	ZCG(cache_opline) = NULL;
2019	ZCG(cache_persistent_script) = NULL;
2020	ZCG(include_path_key_len) = 0;
2021	ZCG(include_path_check) = 1;
2022
2023	/* check if ZCG(function_table) wasn't somehow polluted on the way */
2024	if (ZCG(internal_functions_count) != zend_hash_num_elements(&ZCG(function_table))) {
2025		zend_accel_error(ACCEL_LOG_WARNING, "Internal functions count changed - was %d, now %d", ZCG(internal_functions_count), zend_hash_num_elements(&ZCG(function_table)));
2026	}
2027
2028	ZCG(cwd) = NULL;
2029	ZCG(cwd_key_len) = 0;
2030	ZCG(cwd_check) = 1;
2031
2032#ifdef HAVE_OPCACHE_FILE_CACHE
2033	if (ZCG(accel_directives).file_cache_only) {
2034		return;
2035	}
2036#endif
2037
2038	SHM_UNPROTECT();
2039
2040	if (ZCG(counted)) {
2041#ifdef ZTS
2042		zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for thread id %d", tsrm_thread_id());
2043#else
2044		zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for pid %d", getpid());
2045#endif
2046		accel_unlock_all();
2047		ZCG(counted) = 0;
2048	}
2049
2050	if (ZCSG(restart_pending)) {
2051		zend_shared_alloc_lock();
2052		if (ZCSG(restart_pending) != 0) { /* check again, to ensure that the cache wasn't already cleaned by another process */
2053			if (accel_is_inactive() == SUCCESS) {
2054				zend_accel_error(ACCEL_LOG_DEBUG, "Restarting!");
2055				ZCSG(restart_pending) = 0;
2056				switch ZCSG(restart_reason) {
2057					case ACCEL_RESTART_OOM:
2058						ZCSG(oom_restarts)++;
2059						break;
2060					case ACCEL_RESTART_HASH:
2061						ZCSG(hash_restarts)++;
2062						break;
2063					case ACCEL_RESTART_USER:
2064						ZCSG(manual_restarts)++;
2065						break;
2066				}
2067				accel_restart_enter();
2068
2069				zend_reset_cache_vars();
2070				zend_accel_hash_clean(&ZCSG(hash));
2071
2072#if !defined(ZTS)
2073				if (ZCG(accel_directives).interned_strings_buffer) {
2074					accel_interned_strings_restore_state();
2075				}
2076#endif
2077
2078				zend_shared_alloc_restore_state();
2079				ZCSG(accelerator_enabled) = ZCSG(cache_status_before_restart);
2080				if (ZCSG(last_restart_time) < ZCG(request_time)) {
2081					ZCSG(last_restart_time) = ZCG(request_time);
2082				} else {
2083					ZCSG(last_restart_time)++;
2084				}
2085				accel_restart_leave();
2086			}
2087		} else {
2088			reset_pcre = 1;
2089		}
2090		zend_shared_alloc_unlock();
2091	}
2092
2093	SHM_PROTECT();
2094
2095	if (ZCSG(last_restart_time) != ZCG(last_restart_time)) {
2096		/* SHM was reinitialized. */
2097		ZCG(last_restart_time) = ZCSG(last_restart_time);
2098
2099		/* Reset in-process realpath cache */
2100		realpath_cache_clean();
2101
2102		accel_reset_pcre_cache();
2103	} else if (reset_pcre) {
2104		accel_reset_pcre_cache();
2105	}
2106}
2107
2108#if !ZEND_DEBUG
2109
2110/* Fast Request Shutdown
2111 * =====================
2112 * Zend Memory Manager frees memory by its own. We don't have to free each
2113 * allocated block separately, but we like to call all the destructors and
2114 * callbacks in exactly the same order.
2115 */
2116static void accel_fast_hash_destroy(HashTable *ht);
2117
2118static void accel_fast_zval_dtor(zval *zvalue)
2119{
2120tail_call:
2121	switch (Z_TYPE_P(zvalue)) {
2122		case IS_ARRAY:
2123			GC_REMOVE_FROM_BUFFER(Z_ARR_P(zvalue));
2124			if (Z_ARR_P(zvalue) != &EG(symbol_table)) {
2125				/* break possible cycles */
2126				ZVAL_NULL(zvalue);
2127				accel_fast_hash_destroy(Z_ARRVAL_P(zvalue));
2128			}
2129			break;
2130		case IS_OBJECT:
2131			OBJ_RELEASE(Z_OBJ_P(zvalue));
2132			break;
2133		case IS_RESOURCE:
2134			zend_list_delete(Z_RES_P(zvalue));
2135			break;
2136		case IS_REFERENCE: {
2137				zend_reference *ref = Z_REF_P(zvalue);
2138
2139				if (--GC_REFCOUNT(ref) == 0) {
2140					if (Z_REFCOUNTED(ref->val) && Z_DELREF(ref->val) == 0) {
2141						zvalue = &ref->val;
2142						goto tail_call;
2143					}
2144				}
2145			}
2146			break;
2147	}
2148}
2149
2150static void accel_fast_hash_destroy(HashTable *ht)
2151{
2152	Bucket *p = ht->arData;
2153	Bucket *end = p + ht->nNumUsed;
2154
2155	while (p != end) {
2156		if (Z_REFCOUNTED(p->val) && Z_DELREF(p->val) == 0) {
2157			accel_fast_zval_dtor(&p->val);
2158		}
2159		p++;
2160	}
2161}
2162
2163static inline void zend_accel_fast_del_bucket(HashTable *ht, uint32_t idx, Bucket *p)
2164{
2165	uint32_t nIndex = p->h | ht->nTableMask;
2166	uint32_t i = HT_HASH(ht, nIndex);
2167
2168	ht->nNumOfElements--;
2169	if (idx != i) {
2170		Bucket *prev = HT_HASH_TO_BUCKET(ht, i);
2171		while (Z_NEXT(prev->val) != idx) {
2172			i = Z_NEXT(prev->val);
2173			prev = HT_HASH_TO_BUCKET(ht, i);
2174		}
2175		Z_NEXT(prev->val) = Z_NEXT(p->val);
2176 	} else {
2177		HT_HASH(ht, p->h | ht->nTableMask) = Z_NEXT(p->val);
2178	}
2179}
2180
2181static void zend_accel_fast_shutdown(void)
2182{
2183	if (EG(full_tables_cleanup)) {
2184		return;
2185	}
2186
2187	if (EG(objects_store).top > 1 || zend_hash_num_elements(&EG(regular_list)) > 0) {
2188		/* We don't have to destroy all zvals if they cannot call any destructors */
2189		zend_try {
2190			ZEND_HASH_REVERSE_FOREACH(&EG(symbol_table), 0) {
2191				if (Z_REFCOUNTED(_p->val) && Z_DELREF(_p->val) == 0) {
2192					accel_fast_zval_dtor(&_p->val);
2193				}
2194				zend_accel_fast_del_bucket(&EG(symbol_table), HT_IDX_TO_HASH(_idx-1), _p);
2195			} ZEND_HASH_FOREACH_END();
2196		} zend_end_try();
2197		zend_hash_init(&EG(symbol_table), 8, NULL, NULL, 0);
2198
2199		ZEND_HASH_REVERSE_FOREACH(EG(function_table), 0) {
2200			zend_function *func = Z_PTR(_p->val);
2201
2202			if (func->type == ZEND_INTERNAL_FUNCTION) {
2203				break;
2204			} else {
2205				if (func->op_array.static_variables) {
2206					if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
2207						if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
2208							accel_fast_hash_destroy(func->op_array.static_variables);
2209						}
2210					}
2211				}
2212				zend_accel_fast_del_bucket(EG(function_table), HT_IDX_TO_HASH(_idx-1), _p);
2213			}
2214		} ZEND_HASH_FOREACH_END();
2215
2216		ZEND_HASH_REVERSE_FOREACH(EG(class_table), 0) {
2217			zend_class_entry *ce = Z_PTR(_p->val);
2218
2219			if (ce->type == ZEND_INTERNAL_CLASS) {
2220				break;
2221			} else {
2222				if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
2223					zend_function *func;
2224
2225					ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
2226						if (func->type == ZEND_USER_FUNCTION) {
2227							if (func->op_array.static_variables) {
2228								if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
2229									if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
2230										accel_fast_hash_destroy(func->op_array.static_variables);
2231									}
2232								}
2233								func->op_array.static_variables = NULL;
2234							}
2235						}
2236					} ZEND_HASH_FOREACH_END();
2237				}
2238				if (ce->static_members_table) {
2239					int i;
2240
2241					for (i = 0; i < ce->default_static_members_count; i++) {
2242						zval *zv = &ce->static_members_table[i];
2243						ZVAL_UNDEF(&ce->static_members_table[i]);
2244						if (Z_REFCOUNTED_P(zv) && Z_DELREF_P(zv) == 0) {
2245							accel_fast_zval_dtor(zv);
2246						}
2247					}
2248					ce->static_members_table = NULL;
2249				}
2250				zend_accel_fast_del_bucket(EG(class_table), HT_IDX_TO_HASH(_idx-1), _p);
2251			}
2252		} ZEND_HASH_FOREACH_END();
2253
2254	} else {
2255
2256		zend_hash_init(&EG(symbol_table), 8, NULL, NULL, 0);
2257
2258		ZEND_HASH_REVERSE_FOREACH(EG(function_table), 0) {
2259			zend_function *func = Z_PTR(_p->val);
2260
2261			if (func->type == ZEND_INTERNAL_FUNCTION) {
2262				break;
2263			} else {
2264				zend_accel_fast_del_bucket(EG(function_table), HT_IDX_TO_HASH(_idx-1), _p);
2265			}
2266		} ZEND_HASH_FOREACH_END();
2267
2268		ZEND_HASH_REVERSE_FOREACH(EG(class_table), 0) {
2269			zend_class_entry *ce = Z_PTR(_p->val);
2270
2271			if (ce->type == ZEND_INTERNAL_CLASS) {
2272				break;
2273			} else {
2274				zend_accel_fast_del_bucket(EG(class_table), HT_IDX_TO_HASH(_idx-1), _p);
2275			}
2276		} ZEND_HASH_FOREACH_END();
2277	}
2278
2279	ZEND_HASH_REVERSE_FOREACH(EG(zend_constants), 0) {
2280		zend_constant *c = Z_PTR(_p->val);
2281
2282		if (c->flags & CONST_PERSISTENT) {
2283			break;
2284		} else {
2285			zend_accel_fast_del_bucket(EG(zend_constants), HT_IDX_TO_HASH(_idx-1), _p);
2286		}
2287	} ZEND_HASH_FOREACH_END();
2288	EG(function_table)->nNumUsed = EG(function_table)->nNumOfElements;
2289	EG(class_table)->nNumUsed = EG(class_table)->nNumOfElements;
2290	EG(zend_constants)->nNumUsed = EG(zend_constants)->nNumOfElements;
2291
2292	CG(unclean_shutdown) = 1;
2293}
2294#endif
2295
2296int accel_post_deactivate(void)
2297{
2298	if (!ZCG(enabled) || !accel_startup_ok) {
2299		return SUCCESS;
2300	}
2301
2302	zend_shared_alloc_safe_unlock(); /* be sure we didn't leave cache locked */
2303	accel_unlock_all();
2304	ZCG(counted) = 0;
2305
2306	return SUCCESS;
2307}
2308
2309static void accel_deactivate(void)
2310{
2311	/* ensure that we restore function_table and class_table
2312	 * In general, they're restored by persistent_compile_file(), but in case
2313	 * the script is aborted abnormally, they may become messed up.
2314	 */
2315
2316	if (ZCG(cwd)) {
2317		zend_string_release(ZCG(cwd));
2318		ZCG(cwd) = NULL;
2319	}
2320
2321	if (!ZCG(enabled) || !accel_startup_ok) {
2322		return;
2323	}
2324
2325#if !ZEND_DEBUG
2326	if (ZCG(accel_directives).fast_shutdown && is_zend_mm()) {
2327		zend_accel_fast_shutdown();
2328	}
2329#endif
2330}
2331
2332static int accelerator_remove_cb(zend_extension *element1, zend_extension *element2)
2333{
2334	(void)element2; /* keep the compiler happy */
2335
2336	if (!strcmp(element1->name, ACCELERATOR_PRODUCT_NAME )) {
2337		element1->startup = NULL;
2338#if 0
2339		/* We have to call shutdown callback it to free TS resources */
2340		element1->shutdown = NULL;
2341#endif
2342		element1->activate = NULL;
2343		element1->deactivate = NULL;
2344		element1->op_array_handler = NULL;
2345
2346#ifdef __DEBUG_MESSAGES__
2347        fprintf(stderr, ACCELERATOR_PRODUCT_NAME " is disabled: %s\n", (zps_failure_reason ? zps_failure_reason : "unknown error"));
2348        fflush(stderr);
2349#endif
2350	}
2351
2352	return 0;
2353}
2354
2355static void zps_startup_failure(char *reason, char *api_reason, int (*cb)(zend_extension *, zend_extension *))
2356{
2357	accel_startup_ok = 0;
2358	zps_failure_reason = reason;
2359	zps_api_failure_reason = api_reason?api_reason:reason;
2360	zend_llist_del_element(&zend_extensions, NULL, (int (*)(void *, void *))cb);
2361}
2362
2363static inline int accel_find_sapi(void)
2364{
2365	static const char *supported_sapis[] = {
2366		"apache",
2367		"fastcgi",
2368		"cli-server",
2369		"cgi-fcgi",
2370		"fpm-fcgi",
2371		"isapi",
2372		"apache2filter",
2373		"apache2handler",
2374		"litespeed",
2375		"uwsgi",
2376		NULL
2377	};
2378	const char **sapi_name;
2379
2380	if (sapi_module.name) {
2381		for (sapi_name = supported_sapis; *sapi_name; sapi_name++) {
2382			if (strcmp(sapi_module.name, *sapi_name) == 0) {
2383				return SUCCESS;
2384			}
2385		}
2386		if (ZCG(accel_directives).enable_cli && (
2387		    strcmp(sapi_module.name, "cli") == 0
2388		  || strcmp(sapi_module.name, "phpdbg") == 0)) {
2389			return SUCCESS;
2390		}
2391	}
2392
2393	return FAILURE;
2394}
2395
2396static int zend_accel_init_shm(void)
2397{
2398	zend_shared_alloc_lock();
2399
2400	accel_shared_globals = zend_shared_alloc(sizeof(zend_accel_shared_globals));
2401	if (!accel_shared_globals) {
2402		zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
2403		zend_shared_alloc_unlock();
2404		return FAILURE;
2405	}
2406	ZSMMG(app_shared_globals) = accel_shared_globals;
2407
2408	zend_accel_hash_init(&ZCSG(hash), ZCG(accel_directives).max_accelerated_files);
2409
2410	ZCSG(interned_strings_start) = ZCSG(interned_strings_end) = NULL;
2411# ifndef ZTS
2412	zend_hash_init(&ZCSG(interned_strings), (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024) / (sizeof(Bucket) + sizeof(Bucket*) + 8 /* average string length */), NULL, NULL, 1);
2413	if (ZCG(accel_directives).interned_strings_buffer) {
2414		void *data;
2415
2416		ZCSG(interned_strings).nTableMask = -ZCSG(interned_strings).nTableSize;
2417		data = zend_shared_alloc(HT_SIZE(&ZCSG(interned_strings)));
2418		ZCSG(interned_strings_start) = zend_shared_alloc((ZCG(accel_directives).interned_strings_buffer * 1024 * 1024));
2419		if (!data || !ZCSG(interned_strings_start)) {
2420			zend_accel_error(ACCEL_LOG_FATAL, ACCELERATOR_PRODUCT_NAME " cannot allocate buffer for interned strings");
2421			zend_shared_alloc_unlock();
2422			return FAILURE;
2423		}
2424		HT_SET_DATA_ADDR(&ZCSG(interned_strings), data);
2425		HT_HASH_RESET(&ZCSG(interned_strings));
2426		ZCSG(interned_strings_end)   = ZCSG(interned_strings_start) + (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024);
2427		ZCSG(interned_strings_top)   = ZCSG(interned_strings_start);
2428
2429//		orig_interned_strings_start = CG(interned_strings_start);
2430//		orig_interned_strings_end = CG(interned_strings_end);
2431//		CG(interned_strings_start) = ZCSG(interned_strings_start);
2432//		CG(interned_strings_end) = ZCSG(interned_strings_end);
2433	}
2434# endif
2435
2436	orig_new_interned_string = zend_new_interned_string;
2437	orig_interned_strings_snapshot = zend_interned_strings_snapshot;
2438	orig_interned_strings_restore = zend_interned_strings_restore;
2439	zend_new_interned_string = accel_new_interned_string_for_php;
2440	zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php;
2441	zend_interned_strings_restore = accel_interned_strings_restore_for_php;
2442
2443# ifndef ZTS
2444	if (ZCG(accel_directives).interned_strings_buffer) {
2445		accel_use_shm_interned_strings();
2446		accel_interned_strings_save_state();
2447	}
2448# endif
2449
2450	zend_reset_cache_vars();
2451
2452	ZCSG(oom_restarts) = 0;
2453	ZCSG(hash_restarts) = 0;
2454	ZCSG(manual_restarts) = 0;
2455
2456	ZCSG(accelerator_enabled) = 1;
2457	ZCSG(start_time) = zend_accel_get_time();
2458	ZCSG(last_restart_time) = 0;
2459	ZCSG(restart_in_progress) = 0;
2460
2461	zend_shared_alloc_unlock();
2462
2463	return SUCCESS;
2464}
2465
2466static void accel_globals_ctor(zend_accel_globals *accel_globals)
2467{
2468#if defined(COMPILE_DL_OPCACHE) && defined(ZTS)
2469	ZEND_TSRMLS_CACHE_UPDATE();
2470#endif
2471	memset(accel_globals, 0, sizeof(zend_accel_globals));
2472}
2473
2474static void accel_globals_internal_func_dtor(zval *zv)
2475{
2476	free(Z_PTR_P(zv));
2477}
2478
2479static void accel_globals_dtor(zend_accel_globals *accel_globals)
2480{
2481	if (accel_globals->function_table.nTableSize) {
2482		accel_globals->function_table.pDestructor = accel_globals_internal_func_dtor;
2483		zend_hash_destroy(&accel_globals->function_table);
2484	}
2485}
2486
2487#define ZEND_BIN_ID "BIN_" ZEND_TOSTR(SIZEOF_CHAR) ZEND_TOSTR(SIZEOF_INT) ZEND_TOSTR(SIZEOF_LONG) ZEND_TOSTR(SIZEOF_SIZE_T) ZEND_TOSTR(SIZEOF_ZEND_LONG) ZEND_TOSTR(ZEND_MM_ALIGNMENT)
2488
2489static void accel_gen_system_id(void)
2490{
2491	PHP_MD5_CTX context;
2492	unsigned char digest[16], c;
2493	char *md5str = ZCG(system_id);
2494	int i;
2495
2496	PHP_MD5Init(&context);
2497	PHP_MD5Update(&context, PHP_VERSION, sizeof(PHP_VERSION)-1);
2498	PHP_MD5Update(&context, ZEND_EXTENSION_BUILD_ID, sizeof(ZEND_EXTENSION_BUILD_ID)-1);
2499	PHP_MD5Update(&context, ZEND_BIN_ID, sizeof(ZEND_BIN_ID)-1);
2500	if (strstr(PHP_VERSION, "-dev") != 0) {
2501		/* Development versions may be changed from build to build */
2502		PHP_MD5Update(&context, __DATE__, sizeof(__DATE__)-1);
2503		PHP_MD5Update(&context, __TIME__, sizeof(__TIME__)-1);
2504	}
2505	PHP_MD5Final(digest, &context);
2506	for (i = 0; i < 16; i++) {
2507		c = digest[i] >> 4;
2508		c = (c <= 9) ? c + '0' : c - 10 + 'a';
2509		md5str[i * 2] = c;
2510		c = digest[i] &  0x0f;
2511		c = (c <= 9) ? c + '0' : c - 10 + 'a';
2512		md5str[(i * 2) + 1] = c;
2513	}
2514}
2515
2516#ifdef HAVE_HUGE_CODE_PAGES
2517# ifndef _WIN32
2518#  include <sys/mman.h>
2519#  ifndef MAP_ANON
2520#   ifdef MAP_ANONYMOUS
2521#    define MAP_ANON MAP_ANONYMOUS
2522#   endif
2523#  endif
2524#  ifndef MAP_FAILED
2525#   define MAP_FAILED ((void*)-1)
2526#  endif
2527# endif
2528
2529# if defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE)
2530static int accel_remap_huge_pages(void *start, size_t size, const char *name, size_t offset)
2531{
2532	void *ret = MAP_FAILED;
2533	void *mem;
2534
2535	mem = mmap(NULL, size,
2536		PROT_READ | PROT_WRITE,
2537		MAP_PRIVATE | MAP_ANONYMOUS,
2538		-1, 0);
2539	if (mem == MAP_FAILED) {
2540		zend_error(E_WARNING,
2541			ACCELERATOR_PRODUCT_NAME " huge_code_pages: mmap failed: %s (%d)",
2542			strerror(errno), errno);
2543		return -1;
2544	}
2545	memcpy(mem, start, size);
2546
2547#  ifdef MAP_HUGETLB
2548	ret = mmap(start, size,
2549		PROT_READ | PROT_WRITE | PROT_EXEC,
2550		MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_HUGETLB,
2551		-1, 0);
2552#  endif
2553	if (ret == MAP_FAILED) {
2554		ret = mmap(start, size,
2555			PROT_READ | PROT_WRITE | PROT_EXEC,
2556			MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
2557			-1, 0);
2558		/* this should never happen? */
2559		ZEND_ASSERT(ret != MAP_FAILED);
2560#  ifdef MADV_HUGEPAGE
2561		if (-1 == madvise(start, size, MADV_HUGEPAGE)) {
2562			memcpy(start, mem, size);
2563			mprotect(start, size, PROT_READ | PROT_EXEC);
2564			munmap(mem, size);
2565			zend_error(E_WARNING,
2566				ACCELERATOR_PRODUCT_NAME " huge_code_pages: madvise(HUGEPAGE) failed: %s (%d)",
2567				strerror(errno), errno);
2568			return -1;
2569		}
2570#  else
2571		memcpy(start, mem, size);
2572		mprotect(start, size, PROT_READ | PROT_EXEC);
2573		munmap(mem, size);
2574		zend_error(E_WARNING,
2575			ACCELERATOR_PRODUCT_NAME " huge_code_pages: mmap(HUGETLB) failed: %s (%d)",
2576			strerror(errno), errno);
2577		return -1;
2578#  endif
2579	}
2580
2581	if (ret == start) {
2582		memcpy(start, mem, size);
2583		mprotect(start, size, PROT_READ | PROT_EXEC);
2584	}
2585	munmap(mem, size);
2586
2587	return (ret == start) ? 0 : -1;
2588}
2589
2590static void accel_move_code_to_huge_pages(void)
2591{
2592	FILE *f;
2593	long unsigned int huge_page_size = 2 * 1024 * 1024;
2594
2595	f = fopen("/proc/self/maps", "r");
2596	if (f) {
2597		long unsigned int  start, end, offset, inode;
2598		char perm[5], dev[6], name[MAXPATHLEN];
2599		int ret;
2600
2601		ret = fscanf(f, "%lx-%lx %4s %lx %5s %ld %s\n", &start, &end, perm, &offset, dev, &inode, name);
2602		if (ret == 7 && perm[0] == 'r' && perm[1] == '-' && perm[2] == 'x' && name[0] == '/') {
2603			long unsigned int  seg_start = ZEND_MM_ALIGNED_SIZE_EX(start, huge_page_size);
2604			long unsigned int  seg_end = (end & ~(huge_page_size-1L));
2605
2606			if (seg_end > seg_start) {
2607				zend_accel_error(ACCEL_LOG_DEBUG, "remap to huge page %lx-%lx %s \n", seg_start, seg_end, name);
2608				accel_remap_huge_pages((void*)seg_start, seg_end - seg_start, name, offset + seg_start - start);
2609			}
2610		}
2611		fclose(f);
2612	}
2613}
2614# else
2615static void accel_move_code_to_huge_pages(void)
2616{
2617	zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages has no affect as huge page is not supported");
2618	return;
2619}
2620# endif /* defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE) */
2621#endif /* HAVE_HUGE_CODE_PAGES */
2622
2623static int accel_startup(zend_extension *extension)
2624{
2625	zend_function *func;
2626	zend_ini_entry *ini_entry;
2627
2628#ifdef ZTS
2629	accel_globals_id = ts_allocate_id(&accel_globals_id, sizeof(zend_accel_globals), (ts_allocate_ctor) accel_globals_ctor, (ts_allocate_dtor) accel_globals_dtor);
2630#else
2631	accel_globals_ctor(&accel_globals);
2632#endif
2633
2634#ifdef ZEND_WIN32
2635	_setmaxstdio(2048); /* The default configuration is limited to 512 stdio files */
2636#endif
2637
2638	if (start_accel_module() == FAILURE) {
2639		accel_startup_ok = 0;
2640		zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": module registration failed!");
2641		return FAILURE;
2642	}
2643
2644	accel_gen_system_id();
2645
2646#ifdef HAVE_HUGE_CODE_PAGES
2647	if (ZCG(accel_directives).huge_code_pages &&
2648	    (strcmp(sapi_module.name, "cli") == 0 ||
2649	     strcmp(sapi_module.name, "cli-server") == 0 ||
2650		 strcmp(sapi_module.name, "cgi-fcgi") == 0 ||
2651		 strcmp(sapi_module.name, "fpm-fcgi") == 0)) {
2652		accel_move_code_to_huge_pages();
2653	}
2654#endif
2655
2656	/* no supported SAPI found - disable acceleration and stop initialization */
2657	if (accel_find_sapi() == FAILURE) {
2658		accel_startup_ok = 0;
2659		if (!ZCG(accel_directives).enable_cli &&
2660		    strcmp(sapi_module.name, "cli") == 0) {
2661			zps_startup_failure("Opcode Caching is disabled for CLI", NULL, accelerator_remove_cb);
2662		} else {
2663			zps_startup_failure("Opcode Caching is only supported in Apache, ISAPI, FPM, FastCGI and LiteSpeed SAPIs", NULL, accelerator_remove_cb);
2664		}
2665		return SUCCESS;
2666	}
2667
2668	if (ZCG(enabled) == 0) {
2669		return SUCCESS ;
2670	}
2671
2672/********************************************/
2673/* End of non-SHM dependent initializations */
2674/********************************************/
2675#ifdef HAVE_OPCACHE_FILE_CACHE
2676	if (!ZCG(accel_directives).file_cache_only) {
2677#else
2678	if (1) {
2679#endif
2680		switch (zend_shared_alloc_startup(ZCG(accel_directives).memory_consumption)) {
2681			case ALLOC_SUCCESS:
2682				if (zend_accel_init_shm() == FAILURE) {
2683					accel_startup_ok = 0;
2684					return FAILURE;
2685				}
2686				break;
2687			case ALLOC_FAILURE:
2688				accel_startup_ok = 0;
2689				zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
2690				return SUCCESS;
2691			case SUCCESSFULLY_REATTACHED:
2692				zend_shared_alloc_lock();
2693				accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals);
2694				orig_new_interned_string = zend_new_interned_string;
2695				orig_interned_strings_snapshot = zend_interned_strings_snapshot;
2696				orig_interned_strings_restore = zend_interned_strings_restore;
2697
2698				zend_new_interned_string = accel_new_interned_string_for_php;
2699				zend_interned_strings_snapshot = accel_interned_strings_snapshot_for_php;
2700				zend_interned_strings_restore = accel_interned_strings_restore_for_php;
2701#ifndef ZTS
2702				accel_use_shm_interned_strings();
2703#endif
2704				zend_shared_alloc_unlock();
2705				break;
2706			case FAILED_REATTACHED:
2707				accel_startup_ok = 0;
2708				zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can not reattach to exiting shared memory.");
2709				return SUCCESS;
2710				break;
2711#if ENABLE_FILE_CACHE_FALLBACK
2712			case ALLOC_FALLBACK:
2713				zend_shared_alloc_lock();
2714				fallback_process = 1;
2715				zend_accel_init_auto_globals();
2716				zend_shared_alloc_unlock();
2717				goto file_cache_fallback;
2718				break;
2719#endif
2720		}
2721
2722		/* from this point further, shared memory is supposed to be OK */
2723
2724		/* remeber the last restart time in the process memory */
2725		ZCG(last_restart_time) = ZCSG(last_restart_time);
2726
2727		/* Init auto-global strings */
2728		zend_accel_init_auto_globals();
2729
2730		zend_shared_alloc_lock();
2731		zend_shared_alloc_save_state();
2732		zend_shared_alloc_unlock();
2733
2734		SHM_PROTECT();
2735#ifdef HAVE_OPCACHE_FILE_CACHE
2736	} else if (!ZCG(accel_directives).file_cache) {
2737		accel_startup_ok = 0;
2738		zend_accel_error(ACCEL_LOG_FATAL, "opcache.file_cache_only is set without a proper setting of opcache.file_cache");
2739		return SUCCESS;
2740	} else {
2741		accel_shared_globals = calloc(1, sizeof(zend_accel_shared_globals));
2742
2743		/* Init auto-global strings */
2744		zend_accel_init_auto_globals();
2745#endif
2746	}
2747#if ENABLE_FILE_CACHE_FALLBACK
2748file_cache_fallback:
2749#endif
2750
2751	/* Override compiler */
2752	accelerator_orig_compile_file = zend_compile_file;
2753	zend_compile_file = persistent_compile_file;
2754
2755	/* Override stream opener function (to eliminate open() call caused by
2756	 * include/require statements ) */
2757	accelerator_orig_zend_stream_open_function = zend_stream_open_function;
2758	zend_stream_open_function = persistent_stream_open_function;
2759
2760	/* Override path resolver function (to eliminate stat() calls caused by
2761	 * include_once/require_once statements */
2762	accelerator_orig_zend_resolve_path = zend_resolve_path;
2763	zend_resolve_path = persistent_zend_resolve_path;
2764
2765	/* Override chdir() function */
2766	if ((func = zend_hash_str_find_ptr(CG(function_table), "chdir", sizeof("chdir")-1)) != NULL &&
2767	    func->type == ZEND_INTERNAL_FUNCTION) {
2768		orig_chdir = func->internal_function.handler;
2769		func->internal_function.handler = ZEND_FN(accel_chdir);
2770	}
2771	ZCG(cwd) = NULL;
2772	ZCG(include_path) = NULL;
2773
2774	/* Override "include_path" modifier callback */
2775	if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
2776		ZCG(include_path) = ini_entry->value;
2777		orig_include_path_on_modify = ini_entry->on_modify;
2778		ini_entry->on_modify = accel_include_path_on_modify;
2779	}
2780
2781	accel_startup_ok = 1;
2782
2783	/* Override file_exists(), is_file() and is_readable() */
2784	zend_accel_override_file_functions();
2785
2786	/* Load black list */
2787	accel_blacklist.entries = NULL;
2788	if (ZCG(enabled) && accel_startup_ok &&
2789	    ZCG(accel_directives).user_blacklist_filename &&
2790	    *ZCG(accel_directives.user_blacklist_filename)) {
2791		zend_accel_blacklist_init(&accel_blacklist);
2792		zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename));
2793	}
2794
2795	zend_optimizer_startup();
2796
2797	return SUCCESS;
2798}
2799
2800static void accel_free_ts_resources()
2801{
2802#ifndef ZTS
2803	accel_globals_dtor(&accel_globals);
2804#else
2805	ts_free_id(accel_globals_id);
2806#endif
2807}
2808
2809void accel_shutdown(void)
2810{
2811	zend_ini_entry *ini_entry;
2812	zend_bool file_cache_only = 0;
2813
2814	zend_optimizer_shutdown();
2815
2816	zend_accel_blacklist_shutdown(&accel_blacklist);
2817
2818	if (!ZCG(enabled) || !accel_startup_ok) {
2819		accel_free_ts_resources();
2820		return;
2821	}
2822
2823	if (ZCG(accel_directives).interned_strings_buffer) {
2824#ifndef ZTS
2825		zend_hash_clean(CG(auto_globals));
2826		zend_hash_clean(CG(function_table));
2827		zend_hash_clean(CG(class_table));
2828		zend_hash_clean(EG(zend_constants));
2829#endif
2830	}
2831
2832	accel_reset_pcre_cache();
2833
2834	zend_new_interned_string = orig_new_interned_string;
2835	zend_interned_strings_snapshot = orig_interned_strings_snapshot;
2836	zend_interned_strings_restore = orig_interned_strings_restore;
2837
2838#ifdef HAVE_OPCACHE_FILE_CACHE
2839	file_cache_only = ZCG(accel_directives).file_cache_only;
2840#endif
2841
2842	accel_free_ts_resources();
2843
2844	if (!file_cache_only) {
2845		zend_shared_alloc_shutdown();
2846	}
2847	zend_compile_file = accelerator_orig_compile_file;
2848
2849	if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
2850		ini_entry->on_modify = orig_include_path_on_modify;
2851	}
2852}
2853
2854void zend_accel_schedule_restart(zend_accel_restart_reason reason)
2855{
2856	if (ZCSG(restart_pending)) {
2857		/* don't schedule twice */
2858		return;
2859	}
2860	zend_accel_error(ACCEL_LOG_DEBUG, "Restart Scheduled!");
2861
2862	SHM_UNPROTECT();
2863	ZCSG(restart_pending) = 1;
2864	ZCSG(restart_reason) = reason;
2865	ZCSG(cache_status_before_restart) = ZCSG(accelerator_enabled);
2866	ZCSG(accelerator_enabled) = 0;
2867
2868	if (ZCG(accel_directives).force_restart_timeout) {
2869		ZCSG(force_restart_time) = zend_accel_get_time() + ZCG(accel_directives).force_restart_timeout;
2870	} else {
2871		ZCSG(force_restart_time) = 0;
2872	}
2873	SHM_PROTECT();
2874}
2875
2876/* this is needed because on WIN32 lock is not decreased unless ZCG(counted) is set */
2877#ifdef ZEND_WIN32
2878#define accel_deactivate_now() ZCG(counted) = 1; accel_deactivate_sub()
2879#else
2880#define accel_deactivate_now() accel_deactivate_sub()
2881#endif
2882
2883/* ensures it is OK to read SHM
2884	if it's not OK (restart in progress) returns FAILURE
2885	if OK returns SUCCESS
2886	MUST call accelerator_shm_read_unlock after done lock operations
2887*/
2888int accelerator_shm_read_lock(void)
2889{
2890	if (ZCG(counted)) {
2891		/* counted means we are holding read lock for SHM, so that nothing bad can happen */
2892		return SUCCESS;
2893	} else {
2894		/* here accelerator is active but we do not hold SHM lock. This means restart was scheduled
2895			or is in progress now */
2896		if (accel_activate_add() == FAILURE) { /* acquire usage lock */
2897			return FAILURE;
2898		}
2899		/* Now if we weren't inside restart, restart would not begin until we remove usage lock */
2900		if (ZCSG(restart_in_progress)) {
2901			/* we already were inside restart this means it's not safe to touch shm */
2902			accel_deactivate_now(); /* drop usage lock */
2903			return FAILURE;
2904		}
2905		ZCG(counted) = 1;
2906	}
2907	return SUCCESS;
2908}
2909
2910/* must be called ONLY after SUCCESSFUL accelerator_shm_read_lock */
2911void accelerator_shm_read_unlock(void)
2912{
2913	if (!ZCG(counted)) {
2914		/* counted is 0 - meaning we had to readlock manually, release readlock now */
2915		accel_deactivate_now();
2916	}
2917}
2918
2919ZEND_EXT_API zend_extension zend_extension_entry = {
2920	ACCELERATOR_PRODUCT_NAME,               /* name */
2921	ACCELERATOR_VERSION,					/* version */
2922	"Zend Technologies",					/* author */
2923	"http://www.zend.com/",					/* URL */
2924	"Copyright (c) 1999-2016",				/* copyright */
2925	accel_startup,					   		/* startup */
2926	NULL,									/* shutdown */
2927	accel_activate,							/* per-script activation */
2928	accel_deactivate,						/* per-script deactivation */
2929	NULL,									/* message handler */
2930	NULL,									/* op_array handler */
2931	NULL,									/* extended statement handler */
2932	NULL,									/* extended fcall begin handler */
2933	NULL,									/* extended fcall end handler */
2934	NULL,									/* op_array ctor */
2935	NULL,									/* op_array dtor */
2936	STANDARD_ZEND_EXTENSION_PROPERTIES
2937};
2938