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