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