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