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