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