Coverage Report

Created: 2026-06-02 06:39

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
25.9k
{
162
25.9k
#if defined(__x86_64__)
163
25.9k
  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
25.9k
}
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
111
{
205
111
  return memcmp(filename, "file://", sizeof("file://") - 1) == 0 ||
206
111
         memcmp(filename, "phar://", sizeof("phar://") - 1) == 0;
207
111
}
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
188
{
235
188
  if (ZCG(cwd)) {
236
0
    return ZCG(cwd);
237
188
  } else {
238
188
    char cwd[MAXPATHLEN + 1];
239
240
188
    if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
241
0
      return NULL;
242
0
    }
243
188
    ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
244
188
    ZCG(cwd_key_len) = 0;
245
188
    ZCG(cwd_check) = true;
246
188
    return ZCG(cwd);
247
188
  }
248
188
}
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
58
{
264
58
  int ret = orig_include_path_on_modify(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
265
266
58
  if (ret == SUCCESS) {
267
58
    ZCG(include_path) = new_value;
268
58
    ZCG(include_path_key_len) = 0;
269
58
    ZCG(include_path_check) = true;
270
58
  }
271
58
  return ret;
272
58
}
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
44.4k
{
344
#ifdef ZEND_WIN32
345
  SHM_UNPROTECT();
346
  INCREMENT(mem_usage);
347
  SHM_PROTECT();
348
#else
349
44.4k
  struct flock mem_usage_lock;
350
351
44.4k
  mem_usage_lock.l_type = F_RDLCK;
352
44.4k
  mem_usage_lock.l_whence = SEEK_SET;
353
44.4k
  mem_usage_lock.l_start = 1;
354
44.4k
  mem_usage_lock.l_len = 1;
355
356
44.4k
  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
44.4k
#endif
361
44.4k
  return SUCCESS;
362
44.4k
}
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
44.4k
{
390
#ifdef ZEND_WIN32
391
  accel_deactivate_sub();
392
#else
393
44.4k
  if (lock_file == -1) {
394
0
    return;
395
0
  }
396
397
44.4k
  struct flock mem_usage_unlock_all;
398
399
44.4k
  mem_usage_unlock_all.l_type = F_UNLCK;
400
44.4k
  mem_usage_unlock_all.l_whence = SEEK_SET;
401
44.4k
  mem_usage_unlock_all.l_start = 0;
402
44.4k
  mem_usage_unlock_all.l_len = 0;
403
404
44.4k
  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
44.4k
#endif
408
44.4k
}
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
470k
#define STRTAB_INVALID_POS 0
418
419
#define STRTAB_HASH_TO_SLOT(tab, h) \
420
911k
  ((zend_string_table_pos_t*)((char*)(tab) + sizeof(*(tab)) + ((h) & (tab)->nTableMask)))
421
#define STRTAB_STR_TO_POS(tab, s) \
422
41.8k
  ((zend_string_table_pos_t)(((char*)s - (char*)(tab)) / ZEND_STRING_TABLE_POS_ALIGNMENT))
423
#define STRTAB_POS_TO_STR(tab, pos) \
424
1.18M
  ((zend_string*)((char*)(tab) + ((uintptr_t)(pos) * ZEND_STRING_TABLE_POS_ALIGNMENT)))
425
#define STRTAB_COLLISION(s) \
426
512k
  (*((zend_string_table_pos_t*)((char*)s - sizeof(zend_string_table_pos_t))))
427
#define STRTAB_STR_SIZE(s) \
428
41.5k
  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
41.5k
  ((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
927k
{
480
927k
  zend_ulong   h;
481
927k
  zend_string_table_pos_t pos;
482
927k
  zend_string *s;
483
484
927k
  if (IS_ACCEL_INTERNED(str)) {
485
    /* this is already an interned string */
486
232k
    return str;
487
232k
  }
488
489
695k
  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
695k
  h = zend_string_hash_val(str);
497
498
  /* check for existing interned string */
499
695k
  pos = *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
500
695k
  if (EXPECTED(pos != STRTAB_INVALID_POS)) {
501
1.04M
    do {
502
1.04M
      s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
503
1.04M
      if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
504
605k
        return s;
505
605k
      }
506
435k
      pos = STRTAB_COLLISION(s);
507
435k
    } while (pos != STRTAB_INVALID_POS);
508
612k
  }
509
510
89.9k
  return NULL;
511
695k
}
512
513
zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str)
514
165k
{
515
165k
  zend_ulong   h;
516
165k
  zend_string_table_pos_t pos, *hash_slot;
517
165k
  zend_string *s;
518
519
165k
  if (UNEXPECTED(file_cache_only)) {
520
0
    return str;
521
0
  }
522
523
165k
  if (IS_ACCEL_INTERNED(str)) {
524
    /* this is already an interned string */
525
648
    return str;
526
648
  }
527
528
164k
  h = zend_string_hash_val(str);
529
530
  /* check for existing interned string */
531
164k
  hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
532
164k
  pos = *hash_slot;
533
164k
  if (EXPECTED(pos != STRTAB_INVALID_POS)) {
534
135k
    do {
535
135k
      s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
536
135k
      if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
537
101k
        goto finish;
538
101k
      }
539
33.4k
      pos = STRTAB_COLLISION(s);
540
33.4k
    } while (pos != STRTAB_INVALID_POS);
541
106k
  }
542
543
62.8k
  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
21.3k
    zend_accel_error(ACCEL_LOG_WARNING, "Interned string buffer overflow");
546
21.3k
    return str;
547
21.3k
  }
548
549
  /* create new interning string in shared interned strings buffer */
550
41.5k
  ZCSG(interned_strings).nNumOfElements++;
551
41.5k
  s = ZCSG(interned_strings).top;
552
41.5k
  hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
553
41.5k
  STRTAB_COLLISION(s) = *hash_slot;
554
41.5k
  *hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s);
555
41.5k
  GC_SET_REFCOUNT(s, 2);
556
41.5k
  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
41.5k
  ZSTR_H(s) = h;
558
41.5k
  ZSTR_LEN(s) = ZSTR_LEN(str);
559
41.5k
  memcpy(ZSTR_VAL(s), ZSTR_VAL(str), ZSTR_LEN(s) + 1);
560
41.5k
  ZCSG(interned_strings).top = STRTAB_NEXT(s);
561
562
143k
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
143k
  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
143k
  zend_string_release(str);
572
143k
  return s;
573
143k
}
574
575
static zend_string* ZEND_FASTCALL accel_new_interned_string_for_php(zend_string *str)
576
927k
{
577
927k
  zend_string_hash_val(str);
578
927k
  if (ZCG(counted)) {
579
927k
    zend_string *ret = accel_find_interned_string(str);
580
581
927k
    if (ret) {
582
837k
      zend_string_release(str);
583
837k
      return ret;
584
837k
    }
585
927k
  }
586
89.9k
  return str;
587
927k
}
588
589
static zend_always_inline zend_string *accel_find_interned_string_ex(zend_ulong h, const char *str, size_t size)
590
9.79k
{
591
9.79k
  zend_string_table_pos_t pos;
592
593
  /* check for existing interned string */
594
9.79k
  pos = *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
595
9.79k
  if (EXPECTED(pos != STRTAB_INVALID_POS)) {
596
11.2k
    do {
597
11.2k
      zend_string *s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
598
11.2k
      if (EXPECTED(ZSTR_H(s) == h) && zend_string_equals_cstr(s, str, size)) {
599
8.82k
        return s;
600
8.82k
      }
601
2.38k
      pos = STRTAB_COLLISION(s);
602
2.38k
    } while (pos != STRTAB_INVALID_POS);
603
8.82k
  }
604
972
  return NULL;
605
9.79k
}
606
607
static zend_string* ZEND_FASTCALL accel_init_interned_string_for_php(const char *str, size_t size, bool permanent)
608
9.79k
{
609
9.79k
  if (ZCG(counted)) {
610
9.79k
      zend_ulong h = zend_inline_hash_func(str, size);
611
9.79k
    zend_string *ret = accel_find_interned_string_ex(h, str, size);
612
613
9.79k
    if (!ret) {
614
972
      ret = zend_string_init(str, size, permanent);
615
972
      ZSTR_H(ret) = h;
616
972
    }
617
618
9.79k
    return ret;
619
9.79k
  }
620
621
0
  return zend_string_init(str, size, permanent);
622
9.79k
}
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
0
{
1045
0
  zend_stat_t statbuf = {0};
1046
#ifdef ZEND_WIN32
1047
  accel_time_t res;
1048
#endif
1049
1050
0
  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
0
  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
0
    case ZEND_HANDLE_STREAM:
1098
0
      {
1099
0
        php_stream *stream = (php_stream *)file_handle->handle.stream.handle;
1100
0
        php_stream_statbuf sb;
1101
0
        int ret, er;
1102
1103
0
        if (!stream ||
1104
0
            !stream->ops ||
1105
0
            !stream->ops->stat) {
1106
0
          return 0;
1107
0
        }
1108
1109
0
        er = EG(error_reporting);
1110
0
        EG(error_reporting) = 0;
1111
0
        zend_try {
1112
0
          ret = stream->ops->stat(stream, &sb);
1113
0
        } zend_catch {
1114
0
          ret = -1;
1115
0
        } zend_end_try();
1116
0
        EG(error_reporting) = er;
1117
0
        if (ret != 0) {
1118
0
          return 0;
1119
0
        }
1120
1121
0
        statbuf = sb.sb;
1122
0
      }
1123
0
      break;
1124
1125
0
    default:
1126
0
      return 0;
1127
0
  }
1128
1129
0
  if (size) {
1130
0
    *size = statbuf.st_size;
1131
0
  }
1132
0
  return statbuf.st_mtime;
1133
0
}
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
0
{
1194
0
  if (persistent_script->timestamp == 0) {
1195
0
    return SUCCESS; /* Don't check timestamps of preloaded scripts */
1196
0
  } else if (ZCG(accel_directives).revalidate_freq &&
1197
0
      persistent_script->dynamic_members.revalidate >= ZCG(request_time)) {
1198
0
    return SUCCESS;
1199
0
  } 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
0
}
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
72.3k
{
1221
72.3k
  const char *path = ZSTR_VAL(str);
1222
72.3k
  size_t path_length = ZSTR_LEN(str);
1223
1224
72.3k
  ZEND_ASSERT(GC_REFCOUNT(ZCG(key)) == 1);
1225
72.3k
  ZSTR_LEN(ZCG(key)) = 0;
1226
1227
  /* CWD and include_path don't matter for absolute file names and streams */
1228
72.3k
  if (IS_ABSOLUTE_PATH(path, path_length)) {
1229
    /* pass */
1230
71.5k
  } else if (UNEXPECTED(php_is_stream_path(path))) {
1231
111
    if (!is_cacheable_stream_path(path)) {
1232
111
      return NULL;
1233
111
    }
1234
    /* pass */
1235
689
  } else if (UNEXPECTED(!ZCG(accel_directives).use_cwd)) {
1236
    /* pass */
1237
689
  } else {
1238
689
    const char *include_path = NULL, *cwd = NULL;
1239
689
    size_t include_path_len = 0, cwd_len = 0;
1240
689
    const zend_string *parent_script = NULL;
1241
1242
689
    if (EXPECTED(ZCG(cwd_key_len))) {
1243
501
      cwd = ZCG(cwd_key);
1244
501
      cwd_len = ZCG(cwd_key_len);
1245
501
    } else {
1246
188
      zend_string *cwd_str = accel_getcwd();
1247
1248
188
      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
188
      cwd = ZSTR_VAL(cwd_str);
1254
188
      cwd_len = ZSTR_LEN(cwd_str);
1255
188
      if (ZCG(cwd_check)) {
1256
188
        ZCG(cwd_check) = false;
1257
188
        if (ZCG(accelerator_enabled)) {
1258
1259
188
          zend_string *str = accel_find_interned_string(cwd_str);
1260
188
          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
188
          if (str) {
1274
188
            char buf[32];
1275
188
            const char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, STRTAB_STR_TO_POS(&ZCSG(interned_strings), str));
1276
1277
188
            cwd_len = ZCG(cwd_key_len) = buf + sizeof(buf) - 1 - res;
1278
188
            cwd = ZCG(cwd_key);
1279
188
            memcpy(ZCG(cwd_key), res, cwd_len + 1);
1280
188
          } else {
1281
0
            return NULL;
1282
0
          }
1283
188
        } else {
1284
0
          return NULL;
1285
0
        }
1286
188
      }
1287
188
    }
1288
1289
689
    if (EXPECTED(ZCG(include_path_key_len))) {
1290
501
      include_path = ZCG(include_path_key);
1291
501
      include_path_len = ZCG(include_path_key_len);
1292
501
    } else if (!ZCG(include_path) || ZSTR_LEN(ZCG(include_path)) == 0) {
1293
0
      include_path = "";
1294
0
      include_path_len = 0;
1295
188
    } else {
1296
188
      include_path = ZSTR_VAL(ZCG(include_path));
1297
188
      include_path_len = ZSTR_LEN(ZCG(include_path));
1298
1299
188
      if (ZCG(include_path_check)) {
1300
188
        ZCG(include_path_check) = false;
1301
188
        if (ZCG(accelerator_enabled)) {
1302
1303
188
          zend_string *str = accel_find_interned_string(ZCG(include_path));
1304
188
          if (!str) {
1305
0
            HANDLE_BLOCK_INTERRUPTIONS();
1306
0
            SHM_UNPROTECT();
1307
0
            zend_shared_alloc_lock();
1308
0
            str = accel_new_interned_string(zend_string_copy(ZCG(include_path)));
1309
0
            if (str == ZCG(include_path)) {
1310
0
              zend_string_release(str);
1311
0
              str = NULL;
1312
0
            }
1313
0
            zend_shared_alloc_unlock();
1314
0
            SHM_PROTECT();
1315
0
            HANDLE_UNBLOCK_INTERRUPTIONS();
1316
0
          }
1317
188
          if (str) {
1318
188
            char buf[32];
1319
188
            const char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, STRTAB_STR_TO_POS(&ZCSG(interned_strings), str));
1320
1321
188
            include_path_len = ZCG(include_path_key_len) = buf + sizeof(buf) - 1 - res;
1322
188
            include_path = ZCG(include_path_key);
1323
188
            memcpy(ZCG(include_path_key), res, include_path_len + 1);
1324
188
          } else {
1325
0
            return NULL;
1326
0
          }
1327
188
        } else {
1328
0
          return NULL;
1329
0
        }
1330
188
      }
1331
188
    }
1332
1333
    /* Calculate key length */
1334
689
    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
689
    char *key = ZSTR_VAL(ZCG(key));
1344
689
    memcpy(key, path, path_length);
1345
689
    key[path_length] = ':';
1346
689
    size_t key_length = path_length + 1;
1347
689
    memcpy(key + key_length, cwd, cwd_len);
1348
689
    key_length += cwd_len;
1349
1350
689
    if (include_path_len) {
1351
689
      key[key_length] = ':';
1352
689
      key_length += 1;
1353
689
      memcpy(key + key_length, include_path, include_path_len);
1354
689
      key_length += include_path_len;
1355
689
    }
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
689
    if (EXPECTED(EG(current_execute_data)) &&
1362
689
        EXPECTED((parent_script = zend_get_executed_filename_ex()) != NULL)) {
1363
1364
689
      size_t parent_script_len = ZSTR_LEN(parent_script);
1365
7.57k
      while (parent_script_len > 0) {
1366
7.57k
        --parent_script_len;
1367
7.57k
        if (IS_SLASH(ZSTR_VAL(parent_script)[parent_script_len])) {
1368
689
          break;
1369
689
        }
1370
7.57k
      }
1371
1372
689
      if (UNEXPECTED((size_t)(key_length + parent_script_len + 1) >= ZCG_KEY_LEN)) {
1373
0
        return NULL;
1374
0
      }
1375
689
      key[key_length] = ':';
1376
689
      key_length += 1;
1377
689
      memcpy(key + key_length, ZSTR_VAL(parent_script), parent_script_len);
1378
689
      key_length += parent_script_len;
1379
689
    }
1380
689
    key[key_length] = '\0';
1381
689
    ZSTR_H(ZCG(key)) = 0;
1382
689
    ZSTR_LEN(ZCG(key)) = key_length;
1383
689
    return ZCG(key);
1384
689
  }
1385
1386
  /* not use_cwd */
1387
71.5k
  return str;
1388
72.3k
}
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
25.9k
{
1398
25.9k
  if (persistent_script->corrupted) {
1399
    /* already discarded */
1400
0
    return;
1401
0
  }
1402
1403
25.9k
  persistent_script->corrupted = true;
1404
25.9k
  persistent_script->timestamp = 0;
1405
25.9k
  ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1406
25.9k
  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
25.9k
}
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
25.9k
{
1419
25.9k
  zend_shared_alloc_lock();
1420
25.9k
  zend_accel_discard_script(persistent_script);
1421
25.9k
  zend_shared_alloc_unlock();
1422
25.9k
}
1423
1424
zend_result zend_accel_invalidate(zend_string *filename, bool force)
1425
31.2k
{
1426
31.2k
  zend_string *realpath;
1427
31.2k
  zend_persistent_script *persistent_script;
1428
31.2k
  zend_bool file_found = true;
1429
1430
31.2k
  if (!ZCG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) {
1431
0
    return FAILURE;
1432
0
  }
1433
1434
31.2k
  realpath = accelerator_orig_zend_resolve_path(filename);
1435
1436
31.2k
  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
31.2k
  if (ZCG(accel_directives).file_cache) {
1444
0
    zend_file_cache_invalidate(realpath);
1445
0
  }
1446
1447
31.2k
  persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath);
1448
31.2k
  if (persistent_script && !persistent_script->corrupted) {
1449
25.9k
    zend_file_handle file_handle;
1450
25.9k
    zend_stream_init_filename_ex(&file_handle, realpath);
1451
25.9k
    file_handle.opened_path = realpath;
1452
1453
25.9k
    if (force ||
1454
0
      !ZCG(accel_directives).validate_timestamps ||
1455
25.9k
      do_validate_timestamps(persistent_script, &file_handle) == FAILURE) {
1456
25.9k
      HANDLE_BLOCK_INTERRUPTIONS();
1457
25.9k
      SHM_UNPROTECT();
1458
25.9k
      zend_accel_lock_discard_script(persistent_script);
1459
25.9k
      SHM_PROTECT();
1460
25.9k
      HANDLE_UNBLOCK_INTERRUPTIONS();
1461
25.9k
    }
1462
1463
25.9k
    file_handle.opened_path = NULL;
1464
25.9k
    zend_destroy_file_handle(&file_handle);
1465
25.9k
    file_found = true;
1466
25.9k
  }
1467
1468
31.2k
  accelerator_shm_read_unlock();
1469
31.2k
  zend_string_release_ex(realpath, 0);
1470
1471
31.2k
  return file_found ? SUCCESS : FAILURE;
1472
31.2k
}
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
25.9k
{
1520
25.9k
  return filename && ZSTR_LEN(filename) >= sizeof(".phar") &&
1521
25.9k
    !memcmp(ZSTR_VAL(filename) + ZSTR_LEN(filename) - (sizeof(".phar")-1), ".phar", sizeof(".phar")-1) &&
1522
0
    !strstr(ZSTR_VAL(filename), "://");
1523
25.9k
}
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
25.9k
{
1588
25.9k
  zend_accel_hash_entry *bucket;
1589
25.9k
  uint32_t memory_used;
1590
25.9k
  uint32_t orig_compiler_options;
1591
1592
25.9k
  orig_compiler_options = CG(compiler_options);
1593
25.9k
  if (ZCG(accel_directives).file_cache) {
1594
0
    CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
1595
0
  }
1596
25.9k
  zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level);
1597
25.9k
  zend_accel_finalize_delayed_early_binding_list(new_persistent_script);
1598
25.9k
  CG(compiler_options) = orig_compiler_options;
1599
1600
  /* exclusive lock */
1601
25.9k
  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
25.9k
  bucket = zend_accel_hash_find_entry(&ZCSG(hash), new_persistent_script->script.filename);
1607
25.9k
  if (bucket) {
1608
25.9k
    zend_persistent_script *existing_persistent_script = (zend_persistent_script *)bucket->data;
1609
1610
25.9k
    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
25.9k
  }
1627
1628
25.9k
  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
25.9k
  zend_shared_alloc_init_xlat_table();
1641
1642
  /* Calculate the required memory size */
1643
25.9k
  memory_used = zend_accel_script_persist_calc(new_persistent_script, 1);
1644
1645
  /* Allocate shared memory */
1646
25.9k
  ZCG(mem) = zend_shared_alloc_aligned(memory_used);
1647
25.9k
  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
25.9k
  bzero_aligned(ZCG(mem), memory_used);
1659
1660
25.9k
  zend_shared_alloc_clear_xlat_table();
1661
1662
  /* Copy into shared memory */
1663
25.9k
  new_persistent_script = zend_accel_script_persist(new_persistent_script, 1);
1664
1665
25.9k
  zend_shared_alloc_destroy_xlat_table();
1666
1667
25.9k
  new_persistent_script->is_phar = is_phar_file(new_persistent_script->script.filename);
1668
1669
  /* Consistency check */
1670
25.9k
  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
25.9k
  bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->script.filename, 0, new_persistent_script);
1682
25.9k
  if (bucket) {
1683
25.9k
    zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", ZSTR_VAL(new_persistent_script->script.filename));
1684
25.9k
    if (key &&
1685
        /* key may contain non-persistent PHAR aliases (see issues #115 and #149) */
1686
25.9k
        !zend_string_starts_with_literal(key, "phar://") &&
1687
25.9k
        !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
25.9k
  }
1704
1705
25.9k
  new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
1706
1707
25.9k
  zend_shared_alloc_unlock();
1708
1709
25.9k
  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
25.9k
  *from_shared_memory = true;
1716
25.9k
  return new_persistent_script;
1717
25.9k
}
1718
1719
25
#define ZEND_AUTOGLOBAL_MASK_SERVER  (1 << 0)
1720
18
#define ZEND_AUTOGLOBAL_MASK_ENV     (1 << 1)
1721
16
#define ZEND_AUTOGLOBAL_MASK_REQUEST (1 << 2)
1722
1723
static int zend_accel_get_auto_globals(void)
1724
25.9k
{
1725
25.9k
  int mask = 0;
1726
25.9k
  if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER))) {
1727
9
    mask |= ZEND_AUTOGLOBAL_MASK_SERVER;
1728
9
  }
1729
25.9k
  if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_ENV))) {
1730
2
    mask |= ZEND_AUTOGLOBAL_MASK_ENV;
1731
2
  }
1732
25.9k
  if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_REQUEST))) {
1733
0
    mask |= ZEND_AUTOGLOBAL_MASK_REQUEST;
1734
0
  }
1735
25.9k
  return mask;
1736
25.9k
}
1737
1738
static void zend_accel_set_auto_globals(int mask)
1739
16
{
1740
16
  if (mask & ZEND_AUTOGLOBAL_MASK_SERVER) {
1741
13
    zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER));
1742
13
  }
1743
16
  if (mask & ZEND_AUTOGLOBAL_MASK_ENV) {
1744
3
    zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_ENV));
1745
3
  }
1746
16
  if (mask & ZEND_AUTOGLOBAL_MASK_REQUEST) {
1747
0
    zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_REQUEST));
1748
0
  }
1749
16
  ZCG(auto_globals_mask) |= mask;
1750
16
}
1751
1752
static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handle, int type, zend_op_array **op_array_p)
1753
33.8k
{
1754
33.8k
  zend_persistent_script *new_persistent_script;
1755
33.8k
  uint32_t orig_functions_count, orig_class_count;
1756
33.8k
  zend_op_array *orig_active_op_array;
1757
33.8k
  zend_op_array *op_array;
1758
33.8k
  bool do_bailout = false;
1759
33.8k
  accel_time_t timestamp = 0;
1760
33.8k
  uint32_t orig_compiler_options = 0;
1761
1762
  /* Try to open file */
1763
33.8k
  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
33.8k
  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
33.8k
  if (ZCG(accel_directives).validate_timestamps ||
1787
33.8k
      ZCG(accel_directives).file_update_protection ||
1788
33.8k
      ZCG(accel_directives).max_file_size > 0) {
1789
0
    size_t size = 0;
1790
1791
    /* Obtain the file timestamps, *before* actually compiling them,
1792
     * otherwise we have a race-condition.
1793
     */
1794
0
    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
0
    if (timestamp == 0) {
1800
0
      *op_array_p = accelerator_orig_compile_file(file_handle, type);
1801
0
      return NULL;
1802
0
    }
1803
1804
    /* check if file is too new (may be it's not written completely yet) */
1805
0
    if (ZCG(accel_directives).file_update_protection &&
1806
0
        ((accel_time_t)(ZCG(request_time) - ZCG(accel_directives).file_update_protection) < timestamp)) {
1807
0
      *op_array_p = accelerator_orig_compile_file(file_handle, type);
1808
0
      return NULL;
1809
0
    }
1810
1811
0
    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
0
  }
1819
1820
  /* Save the original values for the op_array, function table and class table */
1821
33.8k
  orig_active_op_array = CG(active_op_array);
1822
33.8k
  orig_functions_count = EG(function_table)->nNumUsed;
1823
33.8k
  orig_class_count = EG(class_table)->nNumUsed;
1824
1825
33.8k
  zend_try {
1826
33.8k
    orig_compiler_options = CG(compiler_options);
1827
33.8k
    CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
1828
33.8k
    CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
1829
33.8k
    CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
1830
33.8k
    CG(compiler_options) |= ZEND_COMPILE_IGNORE_OTHER_FILES;
1831
33.8k
    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
33.8k
    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
33.8k
    op_array = *op_array_p = accelerator_orig_compile_file(file_handle, type);
1844
33.8k
    CG(compiler_options) = orig_compiler_options;
1845
33.8k
  } zend_catch {
1846
2.34k
    op_array = NULL;
1847
2.34k
    do_bailout = true;
1848
2.34k
    CG(compiler_options) = orig_compiler_options;
1849
33.8k
  } zend_end_try();
1850
1851
  /* Restore originals */
1852
33.8k
  CG(active_op_array) = orig_active_op_array;
1853
1854
33.8k
  if (!op_array) {
1855
    /* compilation failed */
1856
7.96k
    if (do_bailout) {
1857
2.34k
      EG(record_errors) = false;
1858
2.34k
      zend_free_recorded_errors();
1859
2.34k
      zend_bailout();
1860
2.34k
    }
1861
5.62k
    return NULL;
1862
7.96k
  }
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
25.9k
  new_persistent_script = create_persistent_script();
1869
25.9k
  new_persistent_script->script.main_op_array = *op_array;
1870
25.9k
  zend_accel_move_user_functions(CG(function_table), CG(function_table)->nNumUsed - orig_functions_count, &new_persistent_script->script);
1871
25.9k
  zend_accel_move_user_classes(CG(class_table), CG(class_table)->nNumUsed - orig_class_count, &new_persistent_script->script);
1872
25.9k
  zend_accel_build_delayed_early_binding_list(new_persistent_script);
1873
1874
25.9k
  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
25.9k
  if (PG(auto_globals_jit)) {
1879
25.9k
    new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals();
1880
25.9k
  }
1881
1882
25.9k
  if (ZCG(accel_directives).validate_timestamps) {
1883
    /* Obtain the file timestamps, *before* actually compiling them,
1884
     * otherwise we have a race-condition.
1885
     */
1886
0
    new_persistent_script->timestamp = timestamp;
1887
0
    new_persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
1888
0
  }
1889
1890
25.9k
  if (file_handle->opened_path) {
1891
0
    new_persistent_script->script.filename = zend_string_copy(file_handle->opened_path);
1892
25.9k
  } else {
1893
25.9k
    new_persistent_script->script.filename = zend_string_copy(file_handle->filename);
1894
25.9k
  }
1895
25.9k
  zend_string_hash_val(new_persistent_script->script.filename);
1896
1897
  /* Now persistent_script structure is ready in process memory */
1898
25.9k
  return new_persistent_script;
1899
33.8k
}
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
72.2k
{
2012
72.2k
  zend_persistent_script *persistent_script = NULL;
2013
72.2k
  zend_string *key = NULL;
2014
72.2k
  bool from_shared_memory; /* if the script we've got is stored in SHM */
2015
2016
72.2k
  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
72.2k
  } 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
72.2k
  } 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
72.2k
  if (ZCG(cache_persistent_script) &&
2043
8
      ((!EG(current_execute_data) &&
2044
0
        file_handle->primary_script &&
2045
0
        ZCG(cache_opline) == NULL) ||
2046
8
       (EG(current_execute_data) &&
2047
8
        EG(current_execute_data)->func &&
2048
8
        ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
2049
8
        ZCG(cache_opline) == EG(current_execute_data)->opline))) {
2050
2051
8
    persistent_script = ZCG(cache_persistent_script);
2052
8
    if (ZSTR_LEN(ZCG(key))) {
2053
0
      key = ZCG(key);
2054
0
    }
2055
2056
72.1k
  } else {
2057
72.1k
    if (!ZCG(accel_directives).revalidate_path) {
2058
      /* try to find cached script by key */
2059
72.1k
      key = accel_make_persistent_key(file_handle->filename);
2060
72.1k
      if (!key) {
2061
111
        ZCG(cache_opline) = NULL;
2062
111
        ZCG(cache_persistent_script) = NULL;
2063
111
        return accelerator_orig_compile_file(file_handle, type);
2064
111
      }
2065
72.0k
      persistent_script = zend_accel_hash_find(&ZCSG(hash), key);
2066
72.0k
    } 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
72.0k
    if (!persistent_script) {
2073
      /* try to find cached script by full real path */
2074
685
      zend_accel_hash_entry *bucket;
2075
2076
      /* open file to resolve the path */
2077
685
        if (file_handle->type == ZEND_HANDLE_FILENAME
2078
684
         && accelerator_orig_zend_stream_open_function(file_handle) == FAILURE) {
2079
684
        if (!EG(exception)) {
2080
675
          if (type == ZEND_REQUIRE) {
2081
90
            zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
2082
585
          } else {
2083
585
            zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
2084
585
          }
2085
675
        }
2086
684
        return NULL;
2087
684
        }
2088
2089
1
      if (file_handle->opened_path) {
2090
0
        bucket = zend_accel_hash_find_entry(&ZCSG(hash), file_handle->opened_path);
2091
2092
0
        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
0
      }
2106
1
    }
2107
72.0k
  }
2108
2109
  /* clear cache */
2110
71.4k
  ZCG(cache_opline) = NULL;
2111
71.4k
  ZCG(cache_persistent_script) = NULL;
2112
2113
71.4k
  if (persistent_script && persistent_script->corrupted) {
2114
33.8k
    persistent_script = NULL;
2115
33.8k
  }
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
71.4k
  if (!ZCG(counted)) {
2122
44.4k
    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
44.4k
    ZCG(counted) = true;
2129
44.4k
  }
2130
2131
  /* Revalidate accessibility of cached file */
2132
71.4k
  if (EXPECTED(persistent_script != NULL) &&
2133
37.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
71.4k
  HANDLE_BLOCK_INTERRUPTIONS();
2147
71.4k
  SHM_UNPROTECT();
2148
2149
  /* If script is found then validate_timestamps if option is enabled */
2150
71.4k
  if (persistent_script && ZCG(accel_directives).validate_timestamps) {
2151
0
    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
0
  }
2156
2157
  /* Check the second level cache */
2158
71.4k
  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
71.4k
  if (!persistent_script) {
2164
33.8k
    uint32_t old_const_num = zend_hash_next_free_element(EG(zend_constants));
2165
33.8k
    zend_op_array *op_array;
2166
2167
    /* Cache miss.. */
2168
33.8k
    ZCSG(misses)++;
2169
2170
    /* No memory left. Behave like without the Accelerator */
2171
33.8k
    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
33.8k
    zend_begin_record_errors();
2181
2182
33.8k
    SHM_PROTECT();
2183
33.8k
    HANDLE_UNBLOCK_INTERRUPTIONS();
2184
33.8k
    persistent_script = opcache_compile_file(file_handle, type, &op_array);
2185
33.8k
    HANDLE_BLOCK_INTERRUPTIONS();
2186
33.8k
    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
33.8k
    from_shared_memory = false;
2192
33.8k
    if (persistent_script) {
2193
25.9k
      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
25.9k
      bool orig_gc_state = gc_enable(false);
2200
25.9k
      persistent_script = cache_script_in_shared_memory(persistent_script, key, &from_shared_memory);
2201
25.9k
      gc_enable(orig_gc_state);
2202
25.9k
    }
2203
2204
    /* Caching is disabled, returning op_array;
2205
     * or something went wrong during compilation, returning NULL
2206
     */
2207
33.8k
    if (!persistent_script) {
2208
5.62k
      SHM_PROTECT();
2209
5.62k
      HANDLE_UNBLOCK_INTERRUPTIONS();
2210
5.62k
      zend_emit_recorded_errors();
2211
5.62k
      zend_free_recorded_errors();
2212
5.62k
      return op_array;
2213
5.62k
    }
2214
28.2k
    if (from_shared_memory) {
2215
      /* Delete immutable arrays moved into SHM */
2216
25.9k
      uint32_t new_const_num = zend_hash_next_free_element(EG(zend_constants));
2217
25.9k
      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
25.9k
    }
2222
28.2k
    persistent_script->dynamic_members.last_used = ZCG(request_time);
2223
28.2k
    SHM_PROTECT();
2224
28.2k
    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
28.2k
    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
28.2k
    } else {
2232
28.2k
      zend_emit_recorded_errors();
2233
28.2k
    }
2234
28.2k
    zend_free_recorded_errors();
2235
37.5k
  } else {
2236
2237
37.5k
#ifndef ZEND_WIN32
2238
37.5k
    ZCSG(hits)++; /* TBFixed: may lose one hit */
2239
37.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
37.5k
    if (persistent_script->script.filename) {
2252
37.5k
      if (!EG(current_execute_data) ||
2253
26.9k
          !EG(current_execute_data)->func ||
2254
26.9k
          !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
2255
26.9k
          !EG(current_execute_data)->opline ||
2256
26.9k
          EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
2257
26.9k
          (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
2258
37.5k
           EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
2259
37.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
12.0k
          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
12.0k
        }
2271
37.5k
      }
2272
37.5k
    }
2273
37.5k
    persistent_script->dynamic_members.last_used = ZCG(request_time);
2274
37.5k
    SHM_PROTECT();
2275
37.5k
    HANDLE_UNBLOCK_INTERRUPTIONS();
2276
2277
37.5k
    zend_emit_recorded_errors_ex(persistent_script->num_warnings, persistent_script->warnings);
2278
37.5k
    from_shared_memory = true;
2279
37.5k
  }
2280
2281
  /* Fetch jit auto globals used in the script before execution */
2282
65.7k
  if (persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask)) {
2283
16
    zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask));
2284
16
  }
2285
2286
65.7k
  return zend_accel_load_script(persistent_script, from_shared_memory);
2287
71.4k
}
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
784
{
2291
784
  uint32_t i;
2292
2293
784
  ZEND_ASSERT(ce->ce_flags & ZEND_ACC_IMMUTABLE);
2294
784
  ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
2295
2296
784
  while (entry) {
2297
784
    bool found = true;
2298
784
    bool needs_autoload = false;
2299
2300
784
    if (entry->parent != parent) {
2301
0
      found = false;
2302
784
    } else {
2303
1.59k
      for (i = 0; i < ce->num_traits + ce->num_interfaces; i++) {
2304
813
        if (entry->traits_and_interfaces[i] != traits_and_interfaces[i]) {
2305
0
          found = false;
2306
0
          break;
2307
0
        }
2308
813
      }
2309
784
      if (found && entry->dependencies) {
2310
123
        for (i = 0; i < entry->dependencies_count; i++) {
2311
85
          const zend_class_entry *dependency_ce = zend_lookup_class_ex(entry->dependencies[i].name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
2312
2313
85
          if (dependency_ce != entry->dependencies[i].ce) {
2314
20
            if (!dependency_ce) {
2315
20
              needs_autoload = true;
2316
20
            } else {
2317
0
              found = false;
2318
0
              break;
2319
0
            }
2320
20
          }
2321
85
        }
2322
38
      }
2323
784
    }
2324
784
    if (found) {
2325
784
      *needs_autoload_ptr = needs_autoload;
2326
784
      return entry;
2327
784
    }
2328
0
    entry = entry->next;
2329
0
  }
2330
2331
0
  return NULL;
2332
784
}
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
3.05k
{
2336
3.05k
  bool needs_autoload;
2337
3.05k
  zend_inheritance_cache_entry *entry = ce->inheritance_cache;
2338
2339
3.06k
  while (entry) {
2340
780
    entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload);
2341
780
    if (entry) {
2342
780
      if (!needs_autoload) {
2343
768
        zend_emit_recorded_errors_ex(entry->num_warnings, entry->warnings);
2344
768
        if (ZCSG(map_ptr_last) > CG(map_ptr_last)) {
2345
0
          zend_map_ptr_extend(ZCSG(map_ptr_last));
2346
0
        }
2347
768
        ce = entry->ce;
2348
768
        if (ZSTR_HAS_CE_CACHE(ce->name)) {
2349
736
          ZSTR_SET_CE_CACHE_EX(ce->name, ce, 0);
2350
736
        }
2351
768
        return ce;
2352
768
      }
2353
2354
16
      for (uint32_t i = 0; i < entry->dependencies_count; i++) {
2355
14
        const zend_class_entry *dependency_ce = zend_lookup_class_ex(entry->dependencies[i].name, NULL, 0);
2356
2357
14
        if (dependency_ce == NULL) {
2358
10
          return NULL;
2359
10
        }
2360
14
      }
2361
12
    }
2362
780
  }
2363
2364
2.28k
  return NULL;
2365
3.05k
}
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
1.56k
{
2369
1.56k
  zend_persistent_script dummy;
2370
1.56k
  size_t size;
2371
1.56k
  uint32_t i;
2372
1.56k
  bool needs_autoload;
2373
1.56k
  zend_class_entry *new_ce;
2374
1.56k
  zend_inheritance_cache_entry *entry;
2375
2376
1.56k
  ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_IMMUTABLE));
2377
1.56k
  ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
2378
2379
1.56k
  if (!ZCG(accelerator_enabled) ||
2380
1.56k
      (ZCSG(restart_in_progress) && accel_restart_is_active())) {
2381
0
    return NULL;
2382
0
  }
2383
2384
1.56k
  if (traits_and_interfaces && dependencies) {
2385
52
    for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
2386
26
      if (traits_and_interfaces[i]) {
2387
26
        zend_hash_del(dependencies, traits_and_interfaces[i]->name);
2388
26
      }
2389
26
    }
2390
26
  }
2391
2392
1.56k
  SHM_UNPROTECT();
2393
1.56k
  zend_shared_alloc_lock();
2394
2395
1.56k
  entry = proto->inheritance_cache;
2396
1.56k
  while (entry) {
2397
4
    entry = zend_accel_inheritance_cache_find(entry, proto, parent, traits_and_interfaces, &needs_autoload);
2398
4
    if (entry) {
2399
4
      zend_shared_alloc_unlock();
2400
4
      SHM_PROTECT();
2401
4
      if (!needs_autoload) {
2402
0
        zend_map_ptr_extend(ZCSG(map_ptr_last));
2403
0
        return entry->ce;
2404
4
      } else {
2405
4
        return NULL;
2406
4
      }
2407
4
    }
2408
4
  }
2409
2410
1.56k
  zend_shared_alloc_init_xlat_table();
2411
2412
1.56k
  memset(&dummy, 0, sizeof(dummy));
2413
1.56k
  dummy.size = ZEND_ALIGNED_SIZE(
2414
1.56k
    sizeof(zend_inheritance_cache_entry) -
2415
1.56k
    sizeof(void*) +
2416
1.56k
    (sizeof(void*) * (proto->num_traits + proto->num_interfaces)));
2417
1.56k
  if (dependencies) {
2418
56
    dummy.size += ZEND_ALIGNED_SIZE(zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency));
2419
56
  }
2420
1.56k
  ZCG(current_persistent_script) = &dummy;
2421
1.56k
  zend_persist_class_entry_calc(ce);
2422
1.56k
  zend_persist_warnings_calc(EG(errors).size, EG(errors).errors);
2423
1.56k
  size = dummy.size;
2424
2425
1.56k
  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
1.56k
  ZCG(mem) = zend_shared_alloc(size);
2432
1.56k
#endif
2433
2434
1.56k
  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
1.56k
  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
1.56k
  memset(ZCG(mem), 0, size);
2449
1.56k
  entry = (zend_inheritance_cache_entry*)ZCG(mem);
2450
1.56k
  ZCG(mem) = (char*)ZCG(mem) +
2451
1.56k
    ZEND_ALIGNED_SIZE(
2452
1.56k
      (sizeof(zend_inheritance_cache_entry) -
2453
1.56k
       sizeof(void*) +
2454
1.56k
       (sizeof(void*) * (proto->num_traits + proto->num_interfaces))));
2455
1.56k
  entry->parent = parent;
2456
3.19k
  for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
2457
1.63k
    entry->traits_and_interfaces[i] = traits_and_interfaces[i];
2458
1.63k
  }
2459
1.56k
  if (dependencies && zend_hash_num_elements(dependencies)) {
2460
52
    zend_string *dep_name;
2461
52
    zend_class_entry *dep_ce;
2462
2463
52
    i = 0;
2464
52
    entry->dependencies_count = zend_hash_num_elements(dependencies);
2465
52
    entry->dependencies = (zend_class_dependency*)ZCG(mem);
2466
360
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(dependencies, dep_name, dep_ce) {
2467
360
#if ZEND_DEBUG
2468
360
      ZEND_ASSERT(zend_accel_in_shm(dep_name));
2469
360
#endif
2470
360
      entry->dependencies[i].name = dep_name;
2471
128
      entry->dependencies[i].ce = dep_ce;
2472
128
      i++;
2473
128
    } ZEND_HASH_FOREACH_END();
2474
52
    ZCG(mem) = (char*)ZCG(mem) + zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency);
2475
52
  }
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
1.56k
#ifdef HAVE_JIT
2481
1.56k
  bool jit_on_old = JIT_G(on);
2482
1.56k
  JIT_G(on) = false;
2483
1.56k
#endif
2484
2485
1.56k
  entry->ce = new_ce = zend_persist_class_entry(ce);
2486
1.56k
  zend_update_parent_ce(new_ce);
2487
2488
1.56k
#ifdef HAVE_JIT
2489
1.56k
  JIT_G(on) = jit_on_old;
2490
1.56k
#endif
2491
2492
1.56k
  entry->num_warnings = EG(errors).size;
2493
1.56k
  entry->warnings = zend_persist_warnings(EG(errors).size, EG(errors).errors);
2494
1.56k
  entry->next = proto->inheritance_cache;
2495
1.56k
  proto->inheritance_cache = entry;
2496
2497
1.56k
  ZCSG(map_ptr_last) = CG(map_ptr_last);
2498
2499
1.56k
  zend_shared_alloc_destroy_xlat_table();
2500
2501
1.56k
  zend_shared_alloc_unlock();
2502
1.56k
  SHM_PROTECT();
2503
2504
  /* Consistency check */
2505
1.56k
  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
1.56k
  zend_map_ptr_extend(ZCSG(map_ptr_last));
2516
2517
1.56k
  return new_ce;
2518
1.56k
}
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
200
{
2543
200
  if (ZCG(cache_persistent_script)) {
2544
    /* check if callback is called from include_once or it's a main request */
2545
8
    if ((!EG(current_execute_data) &&
2546
0
         handle->primary_script &&
2547
0
         ZCG(cache_opline) == NULL) ||
2548
8
        (EG(current_execute_data) &&
2549
8
         EG(current_execute_data)->func &&
2550
8
         ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
2551
8
         ZCG(cache_opline) == EG(current_execute_data)->opline)) {
2552
2553
      /* we are in include_once or FastCGI request */
2554
8
      handle->opened_path = zend_string_copy(ZCG(cache_persistent_script)->script.filename);
2555
8
      return SUCCESS;
2556
8
    }
2557
0
    ZCG(cache_opline) = NULL;
2558
0
    ZCG(cache_persistent_script) = NULL;
2559
0
  }
2560
192
  return accelerator_orig_zend_stream_open_function(handle);
2561
200
}
2562
2563
/* zend_resolve_path() replacement for PHP 5.3 and above */
2564
static zend_string* persistent_zend_resolve_path(zend_string *filename)
2565
977
{
2566
977
  if (!file_cache_only &&
2567
977
      ZCG(accelerator_enabled)) {
2568
2569
    /* check if callback is called from include_once or it's a main request */
2570
977
    if ((!EG(current_execute_data)) ||
2571
977
        (EG(current_execute_data) &&
2572
977
         EG(current_execute_data)->func &&
2573
977
         ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
2574
971
         EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
2575
971
         (EG(current_execute_data)->opline->extended_value == ZEND_INCLUDE_ONCE ||
2576
962
          EG(current_execute_data)->opline->extended_value == ZEND_REQUIRE_ONCE))) {
2577
2578
      /* we are in include_once or FastCGI request */
2579
179
      zend_string *resolved_path;
2580
179
      zend_string *key = NULL;
2581
2582
179
      if (!ZCG(accel_directives).revalidate_path) {
2583
        /* lookup by "not-real" path */
2584
179
        key = accel_make_persistent_key(filename);
2585
179
        if (key) {
2586
179
          const zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), key);
2587
179
          if (bucket != NULL) {
2588
12
            zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
2589
12
            if (!persistent_script->corrupted) {
2590
12
              ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
2591
12
              ZCG(cache_persistent_script) = persistent_script;
2592
12
              return zend_string_copy(persistent_script->script.filename);
2593
12
            }
2594
12
          }
2595
179
        } 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
179
      }
2601
2602
      /* find the full real path */
2603
167
      resolved_path = accelerator_orig_zend_resolve_path(filename);
2604
2605
167
      if (resolved_path) {
2606
        /* lookup by real path */
2607
6
        zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path);
2608
6
        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
6
      }
2629
2630
167
      ZCG(cache_opline) = NULL;
2631
167
      ZCG(cache_persistent_script) = NULL;
2632
167
      return resolved_path;
2633
167
    }
2634
977
  }
2635
798
  ZCG(cache_opline) = NULL;
2636
798
  ZCG(cache_persistent_script) = NULL;
2637
798
  return accelerator_orig_zend_resolve_path(filename);
2638
977
}
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
44.4k
{
2668
44.4k
  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
44.4k
  ZCG(auto_globals_mask) = 0;
2675
44.4k
  ZCG(request_time) = (time_t)sapi_get_request_time();
2676
44.4k
  ZCG(cache_opline) = NULL;
2677
44.4k
  ZCG(cache_persistent_script) = NULL;
2678
44.4k
  ZCG(include_path_key_len) = 0;
2679
44.4k
  ZCG(include_path_check) = true;
2680
2681
44.4k
  ZCG(cwd) = NULL;
2682
44.4k
  ZCG(cwd_key_len) = 0;
2683
44.4k
  ZCG(cwd_check) = true;
2684
2685
44.4k
  if (file_cache_only) {
2686
0
    ZCG(accelerator_enabled) = false;
2687
0
    return SUCCESS;
2688
0
  }
2689
2690
44.4k
#ifndef ZEND_WIN32
2691
44.4k
  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
44.4k
  } else {
2709
44.4k
    ZCG(root_hash) = 0;
2710
44.4k
  }
2711
44.4k
#endif
2712
2713
44.4k
  HANDLE_BLOCK_INTERRUPTIONS();
2714
44.4k
  SHM_UNPROTECT();
2715
2716
44.4k
  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
44.4k
  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
44.4k
  ZCG(accelerator_enabled) = ZCSG(accelerator_enabled);
2777
2778
44.4k
  SHM_PROTECT();
2779
44.4k
  HANDLE_UNBLOCK_INTERRUPTIONS();
2780
2781
44.4k
  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
44.4k
  } 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
44.4k
#ifdef HAVE_JIT
2797
44.4k
  zend_jit_activate();
2798
44.4k
#endif
2799
2800
44.4k
#ifdef PRELOAD_SUPPORT
2801
44.4k
  if (ZCSG(preload_script)) {
2802
0
    preload_activate();
2803
0
  }
2804
44.4k
#endif
2805
2806
44.4k
  return SUCCESS;
2807
44.4k
}
2808
2809
#ifdef HAVE_JIT
2810
void accel_deactivate(void)
2811
44.4k
{
2812
44.4k
  zend_jit_deactivate();
2813
44.4k
}
2814
#endif
2815
2816
zend_result accel_post_deactivate(void)
2817
44.4k
{
2818
44.4k
  if (ZCG(cwd)) {
2819
188
    zend_string_release_ex(ZCG(cwd), 0);
2820
188
    ZCG(cwd) = NULL;
2821
188
  }
2822
2823
44.4k
  if (!ZCG(enabled) || !accel_startup_ok) {
2824
0
    return SUCCESS;
2825
0
  }
2826
2827
44.4k
  zend_shared_alloc_safe_unlock(); /* be sure we didn't leave cache locked */
2828
44.4k
  accel_unlock_all();
2829
44.4k
  ZCG(counted) = false;
2830
2831
44.4k
  return SUCCESS;
2832
44.4k
}
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
31.2k
{
3590
31.2k
  if (ZCG(counted)) {
3591
    /* counted means we are holding read lock for SHM, so that nothing bad can happen */
3592
31.2k
    return SUCCESS;
3593
31.2k
  } 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
31.2k
}
3609
3610
/* must be called ONLY after SUCCESSFUL accelerator_shm_read_lock */
3611
void accelerator_shm_read_unlock(void)
3612
31.2k
{
3613
31.2k
  if (!ZCG(counted)) {
3614
    /* counted is false - meaning we had to readlock manually, release readlock now */
3615
0
    accel_deactivate_now();
3616
0
  }
3617
31.2k
}
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
44.4k
static void accel_activate(void) {
5156
44.4k
  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
44.4k
}
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
};