Coverage Report

Created: 2026-06-02 06:36

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