PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/opcache - ZendAccelerator.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 603 1196 50.4 %
Date: 2015-09-02 Functions: 37 59 62.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 02 Sep 2015 17:19:14 +0000 (38 hours ago)

Copyright © 2005-2015 The PHP Group
All rights reserved.