Coverage Report

Created: 2025-09-27 06:26

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