Coverage Report

Created: 2025-12-14 06:05

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