Coverage Report

Created: 2026-06-02 06:40

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
16
#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
49.4k
{
162
49.4k
#if defined(__x86_64__)
163
49.4k
  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
49.4k
}
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
16
# define zend_accel_get_time() time(NULL)
201
#endif
202
203
static inline bool is_cacheable_stream_path(const char *filename)
204
1.53k
{
205
1.53k
  return memcmp(filename, "file://", sizeof("file://") - 1) == 0 ||
206
1.53k
         memcmp(filename, "phar://", sizeof("phar://") - 1) == 0;
207
1.53k
}
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
39.2k
{
235
39.2k
  if (ZCG(cwd)) {
236
0
    return ZCG(cwd);
237
39.2k
  } else {
238
39.2k
    char cwd[MAXPATHLEN + 1];
239
240
39.2k
    if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
241
0
      return NULL;
242
0
    }
243
39.2k
    ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
244
39.2k
    ZCG(cwd_key_len) = 0;
245
39.2k
    ZCG(cwd_check) = true;
246
39.2k
    return ZCG(cwd);
247
39.2k
  }
248
39.2k
}
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
100
{
264
100
  int ret = orig_include_path_on_modify(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
265
266
100
  if (ret == SUCCESS) {
267
100
    ZCG(include_path) = new_value;
268
100
    ZCG(include_path_key_len) = 0;
269
100
    ZCG(include_path_check) = true;
270
100
  }
271
100
  return ret;
272
100
}
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
142k
{
344
#ifdef ZEND_WIN32
345
  SHM_UNPROTECT();
346
  INCREMENT(mem_usage);
347
  SHM_PROTECT();
348
#else
349
142k
  struct flock mem_usage_lock;
350
351
142k
  mem_usage_lock.l_type = F_RDLCK;
352
142k
  mem_usage_lock.l_whence = SEEK_SET;
353
142k
  mem_usage_lock.l_start = 1;
354
142k
  mem_usage_lock.l_len = 1;
355
356
142k
  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
142k
#endif
361
142k
  return SUCCESS;
362
142k
}
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
228k
{
390
#ifdef ZEND_WIN32
391
  accel_deactivate_sub();
392
#else
393
228k
  if (lock_file == -1) {
394
0
    return;
395
0
  }
396
397
228k
  struct flock mem_usage_unlock_all;
398
399
228k
  mem_usage_unlock_all.l_type = F_UNLCK;
400
228k
  mem_usage_unlock_all.l_whence = SEEK_SET;
401
228k
  mem_usage_unlock_all.l_start = 0;
402
228k
  mem_usage_unlock_all.l_len = 0;
403
404
228k
  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
228k
#endif
408
228k
}
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
2.18M
#define STRTAB_INVALID_POS 0
418
419
#define STRTAB_HASH_TO_SLOT(tab, h) \
420
44.2M
  ((zend_string_table_pos_t*)((char*)(tab) + sizeof(*(tab)) + ((h) & (tab)->nTableMask)))
421
#define STRTAB_STR_TO_POS(tab, s) \
422
206k
  ((zend_string_table_pos_t)(((char*)s - (char*)(tab)) / ZEND_STRING_TABLE_POS_ALIGNMENT))
423
#define STRTAB_POS_TO_STR(tab, pos) \
424
5.79M
  ((zend_string*)((char*)(tab) + ((uintptr_t)(pos) * ZEND_STRING_TABLE_POS_ALIGNMENT)))
425
#define STRTAB_COLLISION(s) \
426
2.31M
  (*((zend_string_table_pos_t*)((char*)s - sizeof(zend_string_table_pos_t))))
427
#define STRTAB_STR_SIZE(s) \
428
127k
  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
127k
  ((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
16
{
475
16
  ZCSG(interned_strings).saved_top = ZCSG(interned_strings).top;
476
16
}
477
478
static zend_always_inline zend_string *accel_find_interned_string(zend_string *str)
479
46.1M
{
480
46.1M
  zend_ulong   h;
481
46.1M
  zend_string_table_pos_t pos;
482
46.1M
  zend_string *s;
483
484
46.1M
  if (IS_ACCEL_INTERNED(str)) {
485
    /* this is already an interned string */
486
2.56M
    return str;
487
2.56M
  }
488
489
43.6M
  if (!ZCG(counted)) {
490
38.9k
    if (!ZCG(accelerator_enabled) || accel_activate_add() == FAILURE) {
491
0
      return NULL;
492
0
    }
493
38.9k
    ZCG(counted) = true;
494
38.9k
  }
495
496
43.6M
  h = zend_string_hash_val(str);
497
498
  /* check for existing interned string */
499
43.6M
  pos = *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
500
43.6M
  if (EXPECTED(pos != STRTAB_INVALID_POS)) {
501
5.37M
    do {
502
5.37M
      s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
503
5.37M
      if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
504
3.27M
        return s;
505
3.27M
      }
506
2.09M
      pos = STRTAB_COLLISION(s);
507
2.09M
    } while (pos != STRTAB_INVALID_POS);
508
3.40M
  }
509
510
40.3M
  return NULL;
511
43.6M
}
512
513
zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str)
514
479k
{
515
479k
  zend_ulong   h;
516
479k
  zend_string_table_pos_t pos, *hash_slot;
517
479k
  zend_string *s;
518
519
479k
  if (UNEXPECTED(file_cache_only)) {
520
0
    return str;
521
0
  }
522
523
479k
  if (IS_ACCEL_INTERNED(str)) {
524
    /* this is already an interned string */
525
5.18k
    return str;
526
5.18k
  }
527
528
474k
  h = zend_string_hash_val(str);
529
530
  /* check for existing interned string */
531
474k
  hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
532
474k
  pos = *hash_slot;
533
474k
  if (EXPECTED(pos != STRTAB_INVALID_POS)) {
534
371k
    do {
535
371k
      s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
536
371k
      if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
537
294k
        goto finish;
538
294k
      }
539
77.1k
      pos = STRTAB_COLLISION(s);
540
77.1k
    } while (pos != STRTAB_INVALID_POS);
541
307k
  }
542
543
179k
  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
51.8k
    zend_accel_error(ACCEL_LOG_WARNING, "Interned string buffer overflow");
546
51.8k
    return str;
547
51.8k
  }
548
549
  /* create new interning string in shared interned strings buffer */
550
127k
  ZCSG(interned_strings).nNumOfElements++;
551
127k
  s = ZCSG(interned_strings).top;
552
127k
  hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
553
127k
  STRTAB_COLLISION(s) = *hash_slot;
554
127k
  *hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s);
555
127k
  GC_SET_REFCOUNT(s, 2);
556
127k
  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
127k
  ZSTR_H(s) = h;
558
127k
  ZSTR_LEN(s) = ZSTR_LEN(str);
559
127k
  memcpy(ZSTR_VAL(s), ZSTR_VAL(str), ZSTR_LEN(s) + 1);
560
127k
  ZCSG(interned_strings).top = STRTAB_NEXT(s);
561
562
422k
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
422k
  if (ZSTR_HAS_CE_CACHE(str) && !ZSTR_HAS_CE_CACHE(s)) {
566
2.78k
    ZEND_ASSERT(GC_FLAGS(str) & IS_STR_PERMANENT);
567
2.78k
    GC_SET_REFCOUNT(s, GC_REFCOUNT(str));
568
2.78k
    GC_ADD_FLAGS(s, IS_STR_CLASS_NAME_MAP_PTR);
569
2.78k
  }
570
571
422k
  zend_string_release(str);
572
422k
  return s;
573
422k
}
574
575
static zend_string* ZEND_FASTCALL accel_new_interned_string_for_php(zend_string *str)
576
46.0M
{
577
46.0M
  zend_string_hash_val(str);
578
46.0M
  if (ZCG(counted)) {
579
46.0M
    zend_string *ret = accel_find_interned_string(str);
580
581
46.0M
    if (ret) {
582
5.76M
      zend_string_release(str);
583
5.76M
      return ret;
584
5.76M
    }
585
46.0M
  }
586
40.3M
  return str;
587
46.0M
}
588
589
static zend_always_inline zend_string *accel_find_interned_string_ex(zend_ulong h, const char *str, size_t size)
590
40.6k
{
591
40.6k
  zend_string_table_pos_t pos;
592
593
  /* check for existing interned string */
594
40.6k
  pos = *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
595
40.6k
  if (EXPECTED(pos != STRTAB_INVALID_POS)) {
596
47.8k
    do {
597
47.8k
      zend_string *s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
598
47.8k
      if (EXPECTED(ZSTR_H(s) == h) && zend_string_equals_cstr(s, str, size)) {
599
34.4k
        return s;
600
34.4k
      }
601
13.3k
      pos = STRTAB_COLLISION(s);
602
13.3k
    } while (pos != STRTAB_INVALID_POS);
603
34.5k
  }
604
6.20k
  return NULL;
605
40.6k
}
606
607
static zend_string* ZEND_FASTCALL accel_init_interned_string_for_php(const char *str, size_t size, bool permanent)
608
1.46M
{
609
1.46M
  if (ZCG(counted)) {
610
40.6k
      zend_ulong h = zend_inline_hash_func(str, size);
611
40.6k
    zend_string *ret = accel_find_interned_string_ex(h, str, size);
612
613
40.6k
    if (!ret) {
614
6.20k
      ret = zend_string_init(str, size, permanent);
615
6.20k
      ZSTR_H(ret) = h;
616
6.20k
    }
617
618
40.6k
    return ret;
619
40.6k
  }
620
621
1.42M
  return zend_string_init(str, size, permanent);
622
1.46M
}
623
624
static inline void accel_copy_permanent_list_types(
625
  zend_new_interned_string_func_t new_interned_string, zend_type type)
626
53.5k
{
627
53.5k
  zend_type *single_type;
628
107k
  ZEND_TYPE_FOREACH_MUTABLE(type, single_type) {
629
107k
    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
107k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
634
3.79k
      ZEND_TYPE_SET_PTR(*single_type, new_interned_string(ZEND_TYPE_NAME(*single_type)));
635
3.79k
    }
636
53.5k
  } ZEND_TYPE_FOREACH_END();
637
53.5k
}
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
16
{
642
16
  uint32_t j;
643
16
  Bucket *p, *q;
644
16
  HashTable *ht;
645
646
  /* empty string */
647
16
  zend_empty_string = new_interned_string(zend_empty_string);
648
4.11k
  for (j = 0; j < 256; j++) {
649
4.09k
    zend_one_char_string[j] = new_interned_string(ZSTR_CHAR(j));
650
4.09k
  }
651
1.44k
  for (j = 0; j < ZEND_STR_LAST_KNOWN; j++) {
652
1.42k
    zend_known_strings[j] = new_interned_string(zend_known_strings[j]);
653
1.42k
  }
654
655
  /* function table hash keys */
656
22.1k
  ZEND_HASH_MAP_FOREACH_BUCKET(CG(function_table), p) {
657
22.1k
    if (p->key) {
658
11.0k
      p->key = new_interned_string(p->key);
659
11.0k
    }
660
22.1k
    if (Z_FUNC(p->val)->common.function_name) {
661
11.0k
      Z_FUNC(p->val)->common.function_name = new_interned_string(Z_FUNC(p->val)->common.function_name);
662
11.0k
    }
663
22.1k
    if (Z_FUNC(p->val)->common.arg_info) {
664
11.0k
      uint32_t i;
665
11.0k
      uint32_t num_args = Z_FUNC(p->val)->common.num_args + 1;
666
11.0k
      zend_arg_info *arg_info = Z_FUNC(p->val)->common.arg_info - 1;
667
668
11.0k
      if (Z_FUNC(p->val)->common.fn_flags & ZEND_ACC_VARIADIC) {
669
640
        num_args++;
670
640
      }
671
41.0k
      for (i = 0 ; i < num_args; i++) {
672
30.0k
        if (i > 0) {
673
18.9k
          arg_info[i].name = new_interned_string(arg_info[i].name);
674
18.9k
          if (arg_info[i].default_value) {
675
6.16k
            arg_info[i].default_value = new_interned_string(arg_info[i].default_value);
676
6.16k
          }
677
18.9k
        }
678
30.0k
        accel_copy_permanent_list_types(new_interned_string, arg_info[i].type);
679
30.0k
      }
680
11.0k
    }
681
22.1k
  } ZEND_HASH_FOREACH_END();
682
683
  /* class table hash keys, class names, properties, methods, constants, etc */
684
5.60k
  ZEND_HASH_MAP_FOREACH_BUCKET(CG(class_table), p) {
685
5.60k
    zend_class_entry *ce;
686
687
5.60k
    ce = (zend_class_entry*)Z_PTR(p->val);
688
689
5.60k
    if (p->key) {
690
2.78k
      p->key = new_interned_string(p->key);
691
2.78k
    }
692
693
5.60k
    if (ce->name) {
694
2.78k
      ce->name = new_interned_string(ce->name);
695
2.78k
      ZEND_ASSERT(ZSTR_HAS_CE_CACHE(ce->name));
696
2.78k
    }
697
698
18.3k
    ZEND_HASH_MAP_FOREACH_BUCKET(&ce->properties_info, q) {
699
18.3k
      zend_property_info *info;
700
701
18.3k
      info = (zend_property_info*)Z_PTR(q->val);
702
703
18.3k
      if (q->key) {
704
6.36k
        q->key = new_interned_string(q->key);
705
6.36k
      }
706
707
18.3k
      if (info->name) {
708
6.36k
        info->name = new_interned_string(info->name);
709
6.36k
      }
710
18.3k
    } ZEND_HASH_FOREACH_END();
711
712
74.1k
    ZEND_HASH_MAP_FOREACH_BUCKET(&ce->function_table, q) {
713
74.1k
      if (q->key) {
714
34.2k
        q->key = new_interned_string(q->key);
715
34.2k
      }
716
74.1k
      if (Z_FUNC(q->val)->common.function_name) {
717
34.2k
        Z_FUNC(q->val)->common.function_name = new_interned_string(Z_FUNC(q->val)->common.function_name);
718
34.2k
      }
719
74.1k
      if (Z_FUNC(q->val)->common.scope == ce) {
720
15.4k
        uint32_t num_args = Z_FUNC(q->val)->common.num_args + 1;
721
15.4k
        zend_arg_info *arg_info = Z_FUNC(q->val)->common.arg_info - 1;
722
723
15.4k
        if (Z_FUNC(q->val)->common.fn_flags & ZEND_ACC_VARIADIC) {
724
96
          num_args++;
725
96
        }
726
39.0k
        for (uint32_t i = 0 ; i < num_args; i++) {
727
23.5k
          if (i > 0) {
728
8.03k
            arg_info[i].name = new_interned_string(arg_info[i].name);
729
8.03k
            if (arg_info[i].default_value) {
730
2.43k
              arg_info[i].default_value = new_interned_string(arg_info[i].default_value);
731
2.43k
            }
732
8.03k
          }
733
23.5k
          accel_copy_permanent_list_types(new_interned_string, arg_info[i].type);
734
23.5k
        }
735
15.4k
      }
736
74.1k
    } ZEND_HASH_FOREACH_END();
737
738
17.4k
    ZEND_HASH_MAP_FOREACH_BUCKET(&ce->constants_table, q) {
739
17.4k
      zend_class_constant* c;
740
741
17.4k
      if (q->key) {
742
5.93k
        q->key = new_interned_string(q->key);
743
5.93k
      }
744
17.4k
      c = (zend_class_constant*)Z_PTR(q->val);
745
17.4k
      if (Z_TYPE(c->value) == IS_STRING) {
746
672
        ZVAL_STR(&c->value, new_interned_string(Z_STR(c->value)));
747
672
      }
748
17.4k
    } ZEND_HASH_FOREACH_END();
749
2.78k
  } ZEND_HASH_FOREACH_END();
750
751
  /* constant hash keys */
752
17.5k
  ZEND_HASH_MAP_FOREACH_BUCKET(EG(zend_constants), p) {
753
17.5k
    zend_constant *c;
754
755
17.5k
    if (p->key) {
756
8.73k
      p->key = new_interned_string(p->key);
757
8.73k
    }
758
17.5k
    c = (zend_constant*)Z_PTR(p->val);
759
17.5k
    if (c->name) {
760
8.73k
      c->name = new_interned_string(c->name);
761
8.73k
    }
762
17.5k
    if (Z_TYPE(c->value) == IS_STRING) {
763
688
      ZVAL_STR(&c->value, new_interned_string(Z_STR(c->value)));
764
688
    }
765
17.5k
  } ZEND_HASH_FOREACH_END();
766
767
  /* auto globals hash keys and names */
768
288
  ZEND_HASH_MAP_FOREACH_BUCKET(CG(auto_globals), p) {
769
288
    zend_auto_global *auto_global;
770
771
288
    auto_global = (zend_auto_global*)Z_PTR(p->val);
772
773
288
    zend_string_addref(auto_global->name);
774
288
    auto_global->name = new_interned_string(auto_global->name);
775
288
    if (p->key) {
776
128
      p->key = new_interned_string(p->key);
777
128
    }
778
288
  } ZEND_HASH_FOREACH_END();
779
780
448
  ZEND_HASH_MAP_FOREACH_BUCKET(&module_registry, p) {
781
448
    if (p->key) {
782
208
      p->key = new_interned_string(p->key);
783
208
    }
784
448
  } ZEND_HASH_FOREACH_END();
785
786
5.76k
  ZEND_HASH_MAP_FOREACH_BUCKET(EG(ini_directives), p) {
787
5.76k
    zend_ini_entry *entry = (zend_ini_entry*)Z_PTR(p->val);
788
789
5.76k
    if (p->key) {
790
2.86k
      p->key = new_interned_string(p->key);
791
2.86k
    }
792
5.76k
    if (entry->name) {
793
2.86k
      entry->name = new_interned_string(entry->name);
794
2.86k
    }
795
5.76k
    if (entry->value) {
796
2.46k
      entry->value = new_interned_string(entry->value);
797
2.46k
    }
798
5.76k
    if (entry->orig_value) {
799
0
      entry->orig_value = new_interned_string(entry->orig_value);
800
0
    }
801
5.76k
  } ZEND_HASH_FOREACH_END();
802
803
16
  ht = php_get_stream_filters_hash_global();
804
224
  ZEND_HASH_MAP_FOREACH_BUCKET(ht, p) {
805
224
    if (p->key) {
806
96
      p->key = new_interned_string(p->key);
807
96
    }
808
224
  } ZEND_HASH_FOREACH_END();
809
810
16
  ht = php_stream_get_url_stream_wrappers_hash_global();
811
224
  ZEND_HASH_MAP_FOREACH_BUCKET(ht, p) {
812
224
    if (p->key) {
813
96
      p->key = new_interned_string(p->key);
814
96
    }
815
224
  } ZEND_HASH_FOREACH_END();
816
817
16
  ht = php_stream_xport_get_hash();
818
160
  ZEND_HASH_MAP_FOREACH_BUCKET(ht, p) {
819
160
    if (p->key) {
820
64
      p->key = new_interned_string(p->key);
821
64
    }
822
160
  } ZEND_HASH_FOREACH_END();
823
16
}
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
16
{
838
16
  HANDLE_BLOCK_INTERRUPTIONS();
839
16
  SHM_UNPROTECT();
840
16
  zend_shared_alloc_lock();
841
842
16
  if (ZCSG(interned_strings).saved_top == NULL) {
843
16
    accel_copy_permanent_strings(accel_new_interned_string);
844
16
  } 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
16
  accel_interned_strings_save_state();
850
851
16
  zend_shared_alloc_unlock();
852
16
  SHM_PROTECT();
853
16
  HANDLE_UNBLOCK_INTERRUPTIONS();
854
16
}
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
45.9k
{
1045
45.9k
  zend_stat_t statbuf = {0};
1046
#ifdef ZEND_WIN32
1047
  accel_time_t res;
1048
#endif
1049
1050
45.9k
  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
45.9k
  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
45.9k
    case ZEND_HANDLE_STREAM:
1098
45.9k
      {
1099
45.9k
        php_stream *stream = (php_stream *)file_handle->handle.stream.handle;
1100
45.9k
        php_stream_statbuf sb;
1101
45.9k
        int ret, er;
1102
1103
45.9k
        if (!stream ||
1104
3
            !stream->ops ||
1105
45.9k
            !stream->ops->stat) {
1106
45.9k
          return 0;
1107
45.9k
        }
1108
1109
3
        er = EG(error_reporting);
1110
3
        EG(error_reporting) = 0;
1111
3
        zend_try {
1112
3
          ret = stream->ops->stat(stream, &sb);
1113
3
        } zend_catch {
1114
0
          ret = -1;
1115
3
        } zend_end_try();
1116
3
        EG(error_reporting) = er;
1117
3
        if (ret != 0) {
1118
0
          return 0;
1119
0
        }
1120
1121
3
        statbuf = sb.sb;
1122
3
      }
1123
0
      break;
1124
1125
0
    default:
1126
0
      return 0;
1127
45.9k
  }
1128
1129
3
  if (size) {
1130
0
    *size = statbuf.st_size;
1131
0
  }
1132
3
  return statbuf.st_mtime;
1133
45.9k
}
1134
1135
static inline zend_result do_validate_timestamps(const zend_persistent_script *persistent_script, zend_file_handle *file_handle)
1136
0
{
1137
0
  zend_file_handle ps_handle;
1138
0
  zend_string *full_path_ptr = NULL;
1139
0
  zend_result ret;
1140
1141
  /** check that the persistent script is indeed the same file we cached
1142
   * (if part of the path is a symlink than it possible that the user will change it)
1143
   * See bug #15140
1144
   */
1145
0
  if (file_handle->opened_path) {
1146
0
    if (persistent_script->script.filename != file_handle->opened_path &&
1147
0
        !zend_string_equal_content(persistent_script->script.filename, file_handle->opened_path)) {
1148
0
      return FAILURE;
1149
0
    }
1150
0
  } else {
1151
0
    full_path_ptr = accelerator_orig_zend_resolve_path(file_handle->filename);
1152
0
    if (full_path_ptr &&
1153
0
        persistent_script->script.filename != full_path_ptr &&
1154
0
        !zend_string_equal_content(persistent_script->script.filename, full_path_ptr)) {
1155
0
      zend_string_release_ex(full_path_ptr, 0);
1156
0
      return FAILURE;
1157
0
    }
1158
0
    file_handle->opened_path = full_path_ptr;
1159
0
  }
1160
1161
0
  if (persistent_script->timestamp == 0) {
1162
0
    if (full_path_ptr) {
1163
0
      zend_string_release_ex(full_path_ptr, 0);
1164
0
      file_handle->opened_path = NULL;
1165
0
    }
1166
0
    return FAILURE;
1167
0
  }
1168
1169
0
  if (zend_get_file_handle_timestamp(file_handle, NULL) == persistent_script->timestamp) {
1170
0
    if (full_path_ptr) {
1171
0
      zend_string_release_ex(full_path_ptr, 0);
1172
0
      file_handle->opened_path = NULL;
1173
0
    }
1174
0
    return SUCCESS;
1175
0
  }
1176
0
  if (full_path_ptr) {
1177
0
    zend_string_release_ex(full_path_ptr, 0);
1178
0
    file_handle->opened_path = NULL;
1179
0
  }
1180
1181
0
  zend_stream_init_filename_ex(&ps_handle, persistent_script->script.filename);
1182
0
  ps_handle.opened_path = persistent_script->script.filename;
1183
1184
0
  ret = zend_get_file_handle_timestamp(&ps_handle, NULL) == persistent_script->timestamp
1185
0
    ? SUCCESS : FAILURE;
1186
1187
0
  zend_destroy_file_handle(&ps_handle);
1188
1189
0
  return ret;
1190
0
}
1191
1192
zend_result validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
1193
26.5k
{
1194
26.5k
  if (persistent_script->timestamp == 0) {
1195
0
    return SUCCESS; /* Don't check timestamps of preloaded scripts */
1196
26.5k
  } else if (ZCG(accel_directives).revalidate_freq &&
1197
26.5k
      persistent_script->dynamic_members.revalidate >= ZCG(request_time)) {
1198
26.5k
    return SUCCESS;
1199
26.5k
  } else if (do_validate_timestamps(persistent_script, file_handle) == FAILURE) {
1200
0
    return FAILURE;
1201
0
  } else {
1202
0
    persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
1203
0
    return SUCCESS;
1204
0
  }
1205
26.5k
}
1206
1207
zend_result validate_timestamp_and_record_ex(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
1208
0
{
1209
0
  SHM_UNPROTECT();
1210
0
  const zend_result ret = validate_timestamp_and_record(persistent_script, file_handle);
1211
0
  SHM_PROTECT();
1212
1213
0
  return ret;
1214
0
}
1215
1216
/* Instead of resolving full real path name each time we need to identify file,
1217
 * we create a key that consist from requested file name, current working
1218
 * directory, current include_path, etc */
1219
zend_string *accel_make_persistent_key(zend_string *str)
1220
255k
{
1221
255k
  const char *path = ZSTR_VAL(str);
1222
255k
  size_t path_length = ZSTR_LEN(str);
1223
1224
255k
  ZEND_ASSERT(GC_REFCOUNT(ZCG(key)) == 1);
1225
255k
  ZSTR_LEN(ZCG(key)) = 0;
1226
1227
  /* CWD and include_path don't matter for absolute file names and streams */
1228
255k
  if (IS_ABSOLUTE_PATH(path, path_length)) {
1229
    /* pass */
1230
209k
  } else if (UNEXPECTED(php_is_stream_path(path))) {
1231
1.53k
    if (!is_cacheable_stream_path(path)) {
1232
1.53k
      return NULL;
1233
1.53k
    }
1234
    /* pass */
1235
43.9k
  } else if (UNEXPECTED(!ZCG(accel_directives).use_cwd)) {
1236
    /* pass */
1237
43.9k
  } else {
1238
43.9k
    const char *include_path = NULL, *cwd = NULL;
1239
43.9k
    size_t include_path_len = 0, cwd_len = 0;
1240
43.9k
    const zend_string *parent_script = NULL;
1241
1242
43.9k
    if (EXPECTED(ZCG(cwd_key_len))) {
1243
4.67k
      cwd = ZCG(cwd_key);
1244
4.67k
      cwd_len = ZCG(cwd_key_len);
1245
39.2k
    } else {
1246
39.2k
      zend_string *cwd_str = accel_getcwd();
1247
1248
39.2k
      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
39.2k
      cwd = ZSTR_VAL(cwd_str);
1254
39.2k
      cwd_len = ZSTR_LEN(cwd_str);
1255
39.2k
      if (ZCG(cwd_check)) {
1256
39.2k
        ZCG(cwd_check) = false;
1257
39.2k
        if (ZCG(accelerator_enabled)) {
1258
1259
39.2k
          zend_string *str = accel_find_interned_string(cwd_str);
1260
39.2k
          if (!str) {
1261
4
            HANDLE_BLOCK_INTERRUPTIONS();
1262
4
            SHM_UNPROTECT();
1263
4
            zend_shared_alloc_lock();
1264
4
            str = accel_new_interned_string(zend_string_copy(cwd_str));
1265
4
            if (str == cwd_str) {
1266
0
              zend_string_release_ex(str, 0);
1267
0
              str = NULL;
1268
0
            }
1269
4
            zend_shared_alloc_unlock();
1270
4
            SHM_PROTECT();
1271
4
            HANDLE_UNBLOCK_INTERRUPTIONS();
1272
4
          }
1273
39.2k
          if (str) {
1274
39.2k
            char buf[32];
1275
39.2k
            const char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, STRTAB_STR_TO_POS(&ZCSG(interned_strings), str));
1276
1277
39.2k
            cwd_len = ZCG(cwd_key_len) = buf + sizeof(buf) - 1 - res;
1278
39.2k
            cwd = ZCG(cwd_key);
1279
39.2k
            memcpy(ZCG(cwd_key), res, cwd_len + 1);
1280
39.2k
          } else {
1281
0
            return NULL;
1282
0
          }
1283
39.2k
        } else {
1284
0
          return NULL;
1285
0
        }
1286
39.2k
      }
1287
39.2k
    }
1288
1289
43.9k
    if (EXPECTED(ZCG(include_path_key_len))) {
1290
4.67k
      include_path = ZCG(include_path_key);
1291
4.67k
      include_path_len = ZCG(include_path_key_len);
1292
39.2k
    } else if (!ZCG(include_path) || ZSTR_LEN(ZCG(include_path)) == 0) {
1293
0
      include_path = "";
1294
0
      include_path_len = 0;
1295
39.2k
    } else {
1296
39.2k
      include_path = ZSTR_VAL(ZCG(include_path));
1297
39.2k
      include_path_len = ZSTR_LEN(ZCG(include_path));
1298
1299
39.2k
      if (ZCG(include_path_check)) {
1300
39.2k
        ZCG(include_path_check) = false;
1301
39.2k
        if (ZCG(accelerator_enabled)) {
1302
1303
39.2k
          zend_string *str = accel_find_interned_string(ZCG(include_path));
1304
39.2k
          if (!str) {
1305
2
            HANDLE_BLOCK_INTERRUPTIONS();
1306
2
            SHM_UNPROTECT();
1307
2
            zend_shared_alloc_lock();
1308
2
            str = accel_new_interned_string(zend_string_copy(ZCG(include_path)));
1309
2
            if (str == ZCG(include_path)) {
1310
0
              zend_string_release(str);
1311
0
              str = NULL;
1312
0
            }
1313
2
            zend_shared_alloc_unlock();
1314
2
            SHM_PROTECT();
1315
2
            HANDLE_UNBLOCK_INTERRUPTIONS();
1316
2
          }
1317
39.2k
          if (str) {
1318
39.2k
            char buf[32];
1319
39.2k
            const char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, STRTAB_STR_TO_POS(&ZCSG(interned_strings), str));
1320
1321
39.2k
            include_path_len = ZCG(include_path_key_len) = buf + sizeof(buf) - 1 - res;
1322
39.2k
            include_path = ZCG(include_path_key);
1323
39.2k
            memcpy(ZCG(include_path_key), res, include_path_len + 1);
1324
39.2k
          } else {
1325
0
            return NULL;
1326
0
          }
1327
39.2k
        } else {
1328
0
          return NULL;
1329
0
        }
1330
39.2k
      }
1331
39.2k
    }
1332
1333
    /* Calculate key length */
1334
43.9k
    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
43.9k
    char *key = ZSTR_VAL(ZCG(key));
1344
43.9k
    memcpy(key, path, path_length);
1345
43.9k
    key[path_length] = ':';
1346
43.9k
    size_t key_length = path_length + 1;
1347
43.9k
    memcpy(key + key_length, cwd, cwd_len);
1348
43.9k
    key_length += cwd_len;
1349
1350
43.9k
    if (include_path_len) {
1351
43.9k
      key[key_length] = ':';
1352
43.9k
      key_length += 1;
1353
43.9k
      memcpy(key + key_length, include_path, include_path_len);
1354
43.9k
      key_length += include_path_len;
1355
43.9k
    }
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
43.9k
    if (EXPECTED(EG(current_execute_data)) &&
1362
4.99k
        EXPECTED((parent_script = zend_get_executed_filename_ex()) != NULL)) {
1363
1364
4.99k
      size_t parent_script_len = ZSTR_LEN(parent_script);
1365
54.9k
      while (parent_script_len > 0) {
1366
54.9k
        --parent_script_len;
1367
54.9k
        if (IS_SLASH(ZSTR_VAL(parent_script)[parent_script_len])) {
1368
4.99k
          break;
1369
4.99k
        }
1370
54.9k
      }
1371
1372
4.99k
      if (UNEXPECTED((size_t)(key_length + parent_script_len + 1) >= ZCG_KEY_LEN)) {
1373
0
        return NULL;
1374
0
      }
1375
4.99k
      key[key_length] = ':';
1376
4.99k
      key_length += 1;
1377
4.99k
      memcpy(key + key_length, ZSTR_VAL(parent_script), parent_script_len);
1378
4.99k
      key_length += parent_script_len;
1379
4.99k
    }
1380
43.9k
    key[key_length] = '\0';
1381
43.9k
    ZSTR_H(ZCG(key)) = 0;
1382
43.9k
    ZSTR_LEN(ZCG(key)) = key_length;
1383
43.9k
    return ZCG(key);
1384
43.9k
  }
1385
1386
  /* not use_cwd */
1387
209k
  return str;
1388
255k
}
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
49.4k
{
1398
49.4k
  if (persistent_script->corrupted) {
1399
    /* already discarded */
1400
0
    return;
1401
0
  }
1402
1403
49.4k
  persistent_script->corrupted = true;
1404
49.4k
  persistent_script->timestamp = 0;
1405
49.4k
  ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1406
49.4k
  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
49.4k
}
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
49.4k
{
1419
49.4k
  zend_shared_alloc_lock();
1420
49.4k
  zend_accel_discard_script(persistent_script);
1421
49.4k
  zend_shared_alloc_unlock();
1422
49.4k
}
1423
1424
zend_result zend_accel_invalidate(zend_string *filename, bool force)
1425
56.9k
{
1426
56.9k
  zend_string *realpath;
1427
56.9k
  zend_persistent_script *persistent_script;
1428
56.9k
  zend_bool file_found = true;
1429
1430
56.9k
  if (!ZCG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) {
1431
0
    return FAILURE;
1432
0
  }
1433
1434
56.9k
  realpath = accelerator_orig_zend_resolve_path(filename);
1435
1436
56.9k
  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
56.9k
  if (ZCG(accel_directives).file_cache) {
1444
0
    zend_file_cache_invalidate(realpath);
1445
0
  }
1446
1447
56.9k
  persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath);
1448
56.9k
  if (persistent_script && !persistent_script->corrupted) {
1449
49.4k
    zend_file_handle file_handle;
1450
49.4k
    zend_stream_init_filename_ex(&file_handle, realpath);
1451
49.4k
    file_handle.opened_path = realpath;
1452
1453
49.4k
    if (force ||
1454
0
      !ZCG(accel_directives).validate_timestamps ||
1455
49.4k
      do_validate_timestamps(persistent_script, &file_handle) == FAILURE) {
1456
49.4k
      HANDLE_BLOCK_INTERRUPTIONS();
1457
49.4k
      SHM_UNPROTECT();
1458
49.4k
      zend_accel_lock_discard_script(persistent_script);
1459
49.4k
      SHM_PROTECT();
1460
49.4k
      HANDLE_UNBLOCK_INTERRUPTIONS();
1461
49.4k
    }
1462
1463
49.4k
    file_handle.opened_path = NULL;
1464
49.4k
    zend_destroy_file_handle(&file_handle);
1465
49.4k
    file_found = true;
1466
49.4k
  }
1467
1468
56.9k
  accelerator_shm_read_unlock();
1469
56.9k
  zend_string_release_ex(realpath, 0);
1470
1471
56.9k
  return file_found ? SUCCESS : FAILURE;
1472
56.9k
}
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
49.4k
{
1520
49.4k
  return filename && ZSTR_LEN(filename) >= sizeof(".phar") &&
1521
49.4k
    !memcmp(ZSTR_VAL(filename) + ZSTR_LEN(filename) - (sizeof(".phar")-1), ".phar", sizeof(".phar")-1) &&
1522
0
    !strstr(ZSTR_VAL(filename), "://");
1523
49.4k
}
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
49.4k
{
1588
49.4k
  zend_accel_hash_entry *bucket;
1589
49.4k
  uint32_t memory_used;
1590
49.4k
  uint32_t orig_compiler_options;
1591
1592
49.4k
  orig_compiler_options = CG(compiler_options);
1593
49.4k
  if (ZCG(accel_directives).file_cache) {
1594
0
    CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
1595
0
  }
1596
49.4k
  zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level);
1597
49.4k
  zend_accel_finalize_delayed_early_binding_list(new_persistent_script);
1598
49.4k
  CG(compiler_options) = orig_compiler_options;
1599
1600
  /* exclusive lock */
1601
49.4k
  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
49.4k
  bucket = zend_accel_hash_find_entry(&ZCSG(hash), new_persistent_script->script.filename);
1607
49.4k
  if (bucket) {
1608
49.4k
    zend_persistent_script *existing_persistent_script = (zend_persistent_script *)bucket->data;
1609
1610
49.4k
    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
49.4k
  }
1627
1628
49.4k
  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
49.4k
  zend_shared_alloc_init_xlat_table();
1641
1642
  /* Calculate the required memory size */
1643
49.4k
  memory_used = zend_accel_script_persist_calc(new_persistent_script, 1);
1644
1645
  /* Allocate shared memory */
1646
49.4k
  ZCG(mem) = zend_shared_alloc_aligned(memory_used);
1647
49.4k
  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
49.4k
  bzero_aligned(ZCG(mem), memory_used);
1659
1660
49.4k
  zend_shared_alloc_clear_xlat_table();
1661
1662
  /* Copy into shared memory */
1663
49.4k
  new_persistent_script = zend_accel_script_persist(new_persistent_script, 1);
1664
1665
49.4k
  zend_shared_alloc_destroy_xlat_table();
1666
1667
49.4k
  new_persistent_script->is_phar = is_phar_file(new_persistent_script->script.filename);
1668
1669
  /* Consistency check */
1670
49.4k
  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
49.4k
  bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->script.filename, 0, new_persistent_script);
1682
49.4k
  if (bucket) {
1683
49.4k
    zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", ZSTR_VAL(new_persistent_script->script.filename));
1684
49.4k
    if (key &&
1685
        /* key may contain non-persistent PHAR aliases (see issues #115 and #149) */
1686
49.4k
        !zend_string_starts_with_literal(key, "phar://") &&
1687
49.4k
        !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
49.4k
  }
1704
1705
49.4k
  new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
1706
1707
49.4k
  zend_shared_alloc_unlock();
1708
1709
49.4k
  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
49.4k
  *from_shared_memory = true;
1716
49.4k
  return new_persistent_script;
1717
49.4k
}
1718
1719
119
#define ZEND_AUTOGLOBAL_MASK_SERVER  (1 << 0)
1720
68
#define ZEND_AUTOGLOBAL_MASK_ENV     (1 << 1)
1721
64
#define ZEND_AUTOGLOBAL_MASK_REQUEST (1 << 2)
1722
1723
static int zend_accel_get_auto_globals(void)
1724
49.4k
{
1725
49.4k
  int mask = 0;
1726
49.4k
  if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER))) {
1727
55
    mask |= ZEND_AUTOGLOBAL_MASK_SERVER;
1728
55
  }
1729
49.4k
  if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_ENV))) {
1730
4
    mask |= ZEND_AUTOGLOBAL_MASK_ENV;
1731
4
  }
1732
49.4k
  if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_REQUEST))) {
1733
0
    mask |= ZEND_AUTOGLOBAL_MASK_REQUEST;
1734
0
  }
1735
49.4k
  return mask;
1736
49.4k
}
1737
1738
static void zend_accel_set_auto_globals(int mask)
1739
64
{
1740
64
  if (mask & ZEND_AUTOGLOBAL_MASK_SERVER) {
1741
59
    zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER));
1742
59
  }
1743
64
  if (mask & ZEND_AUTOGLOBAL_MASK_ENV) {
1744
5
    zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_ENV));
1745
5
  }
1746
64
  if (mask & ZEND_AUTOGLOBAL_MASK_REQUEST) {
1747
0
    zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_REQUEST));
1748
0
  }
1749
64
  ZCG(auto_globals_mask) |= mask;
1750
64
}
1751
1752
static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handle, int type, zend_op_array **op_array_p)
1753
105k
{
1754
105k
  zend_persistent_script *new_persistent_script;
1755
105k
  uint32_t orig_functions_count, orig_class_count;
1756
105k
  zend_op_array *orig_active_op_array;
1757
105k
  zend_op_array *op_array;
1758
105k
  bool do_bailout = false;
1759
105k
  accel_time_t timestamp = 0;
1760
105k
  uint32_t orig_compiler_options = 0;
1761
1762
  /* Try to open file */
1763
105k
  if (file_handle->type == ZEND_HANDLE_FILENAME) {
1764
6
    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
6
  }
1776
1777
  /* check blacklist right after ensuring that file was opened */
1778
105k
  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
105k
  if (ZCG(accel_directives).validate_timestamps ||
1787
59.5k
      ZCG(accel_directives).file_update_protection ||
1788
59.5k
      ZCG(accel_directives).max_file_size > 0) {
1789
45.9k
    size_t size = 0;
1790
1791
    /* Obtain the file timestamps, *before* actually compiling them,
1792
     * otherwise we have a race-condition.
1793
     */
1794
45.9k
    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
45.9k
    if (timestamp == 0) {
1800
45.9k
      *op_array_p = accelerator_orig_compile_file(file_handle, type);
1801
45.9k
      return NULL;
1802
45.9k
    }
1803
1804
    /* check if file is too new (may be it's not written completely yet) */
1805
3
    if (ZCG(accel_directives).file_update_protection &&
1806
3
        ((accel_time_t)(ZCG(request_time) - ZCG(accel_directives).file_update_protection) < timestamp)) {
1807
2
      *op_array_p = accelerator_orig_compile_file(file_handle, type);
1808
2
      return NULL;
1809
2
    }
1810
1811
1
    if (ZCG(accel_directives).max_file_size > 0 && size > (size_t)ZCG(accel_directives).max_file_size) {
1812
0
      SHM_UNPROTECT();
1813
0
      ZCSG(blacklist_misses)++;
1814
0
      SHM_PROTECT();
1815
0
      *op_array_p = accelerator_orig_compile_file(file_handle, type);
1816
0
      return NULL;
1817
0
    }
1818
1
  }
1819
1820
  /* Save the original values for the op_array, function table and class table */
1821
59.5k
  orig_active_op_array = CG(active_op_array);
1822
59.5k
  orig_functions_count = EG(function_table)->nNumUsed;
1823
59.5k
  orig_class_count = EG(class_table)->nNumUsed;
1824
1825
59.5k
  zend_try {
1826
59.5k
    orig_compiler_options = CG(compiler_options);
1827
59.5k
    CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
1828
59.5k
    CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
1829
59.5k
    CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
1830
59.5k
    CG(compiler_options) |= ZEND_COMPILE_IGNORE_OTHER_FILES;
1831
59.5k
    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
59.5k
    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
59.5k
    op_array = *op_array_p = accelerator_orig_compile_file(file_handle, type);
1844
59.5k
    CG(compiler_options) = orig_compiler_options;
1845
59.5k
  } zend_catch {
1846
2.62k
    op_array = NULL;
1847
2.62k
    do_bailout = true;
1848
2.62k
    CG(compiler_options) = orig_compiler_options;
1849
59.5k
  } zend_end_try();
1850
1851
  /* Restore originals */
1852
59.5k
  CG(active_op_array) = orig_active_op_array;
1853
1854
59.5k
  if (!op_array) {
1855
    /* compilation failed */
1856
10.0k
    if (do_bailout) {
1857
2.62k
      EG(record_errors) = false;
1858
2.62k
      zend_free_recorded_errors();
1859
2.62k
      zend_bailout();
1860
2.62k
    }
1861
7.45k
    return NULL;
1862
10.0k
  }
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
49.4k
  new_persistent_script = create_persistent_script();
1869
49.4k
  new_persistent_script->script.main_op_array = *op_array;
1870
49.4k
  zend_accel_move_user_functions(CG(function_table), CG(function_table)->nNumUsed - orig_functions_count, &new_persistent_script->script);
1871
49.4k
  zend_accel_move_user_classes(CG(class_table), CG(class_table)->nNumUsed - orig_class_count, &new_persistent_script->script);
1872
49.4k
  zend_accel_build_delayed_early_binding_list(new_persistent_script);
1873
1874
49.4k
  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
49.4k
  if (PG(auto_globals_jit)) {
1879
49.4k
    new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals();
1880
49.4k
  }
1881
1882
49.4k
  if (ZCG(accel_directives).validate_timestamps) {
1883
    /* Obtain the file timestamps, *before* actually compiling them,
1884
     * otherwise we have a race-condition.
1885
     */
1886
1
    new_persistent_script->timestamp = timestamp;
1887
1
    new_persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
1888
1
  }
1889
1890
49.4k
  if (file_handle->opened_path) {
1891
7
    new_persistent_script->script.filename = zend_string_copy(file_handle->opened_path);
1892
49.4k
  } else {
1893
49.4k
    new_persistent_script->script.filename = zend_string_copy(file_handle->filename);
1894
49.4k
  }
1895
49.4k
  zend_string_hash_val(new_persistent_script->script.filename);
1896
1897
  /* Now persistent_script structure is ready in process memory */
1898
49.4k
  return new_persistent_script;
1899
59.5k
}
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
252k
{
2012
252k
  zend_persistent_script *persistent_script = NULL;
2013
252k
  zend_string *key = NULL;
2014
252k
  bool from_shared_memory; /* if the script we've got is stored in SHM */
2015
2016
252k
  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
252k
  } 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
252k
  } 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
252k
  if (ZCG(cache_persistent_script) &&
2043
10
      ((!EG(current_execute_data) &&
2044
0
        file_handle->primary_script &&
2045
0
        ZCG(cache_opline) == NULL) ||
2046
10
       (EG(current_execute_data) &&
2047
10
        EG(current_execute_data)->func &&
2048
10
        ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
2049
10
        ZCG(cache_opline) == EG(current_execute_data)->opline))) {
2050
2051
10
    persistent_script = ZCG(cache_persistent_script);
2052
10
    if (ZSTR_LEN(ZCG(key))) {
2053
0
      key = ZCG(key);
2054
0
    }
2055
2056
252k
  } else {
2057
252k
    if (!ZCG(accel_directives).revalidate_path) {
2058
      /* try to find cached script by key */
2059
252k
      key = accel_make_persistent_key(file_handle->filename);
2060
252k
      if (!key) {
2061
1.53k
        ZCG(cache_opline) = NULL;
2062
1.53k
        ZCG(cache_persistent_script) = NULL;
2063
1.53k
        return accelerator_orig_compile_file(file_handle, type);
2064
1.53k
      }
2065
251k
      persistent_script = zend_accel_hash_find(&ZCSG(hash), key);
2066
251k
    } 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
251k
    if (!persistent_script) {
2073
      /* try to find cached script by full real path */
2074
48.9k
      zend_accel_hash_entry *bucket;
2075
2076
      /* open file to resolve the path */
2077
48.9k
        if (file_handle->type == ZEND_HANDLE_FILENAME
2078
3.02k
         && accelerator_orig_zend_stream_open_function(file_handle) == FAILURE) {
2079
1.03k
        if (!EG(exception)) {
2080
1.02k
          if (type == ZEND_REQUIRE) {
2081
155
            zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
2082
867
          } else {
2083
867
            zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
2084
867
          }
2085
1.02k
        }
2086
1.03k
        return NULL;
2087
1.03k
        }
2088
2089
47.9k
      if (file_handle->opened_path) {
2090
3
        bucket = zend_accel_hash_find_entry(&ZCSG(hash), file_handle->opened_path);
2091
2092
3
        if (bucket) {
2093
0
          persistent_script = (zend_persistent_script *)bucket->data;
2094
2095
0
          if (key && !persistent_script->corrupted) {
2096
0
            HANDLE_BLOCK_INTERRUPTIONS();
2097
0
            SHM_UNPROTECT();
2098
0
            zend_shared_alloc_lock();
2099
0
            zend_accel_add_key(key, bucket);
2100
0
            zend_shared_alloc_unlock();
2101
0
            SHM_PROTECT();
2102
0
            HANDLE_UNBLOCK_INTERRUPTIONS();
2103
0
          }
2104
0
        }
2105
3
      }
2106
47.9k
    }
2107
251k
  }
2108
2109
  /* clear cache */
2110
250k
  ZCG(cache_opline) = NULL;
2111
250k
  ZCG(cache_persistent_script) = NULL;
2112
2113
250k
  if (persistent_script && persistent_script->corrupted) {
2114
59.5k
    persistent_script = NULL;
2115
59.5k
  }
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
250k
  if (!ZCG(counted)) {
2122
103k
    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
103k
    ZCG(counted) = true;
2129
103k
  }
2130
2131
  /* Revalidate accessibility of cached file */
2132
250k
  if (EXPECTED(persistent_script != NULL) &&
2133
142k
      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
250k
  HANDLE_BLOCK_INTERRUPTIONS();
2147
250k
  SHM_UNPROTECT();
2148
2149
  /* If script is found then validate_timestamps if option is enabled */
2150
250k
  if (persistent_script && ZCG(accel_directives).validate_timestamps) {
2151
26.5k
    if (validate_timestamp_and_record(persistent_script, file_handle) == FAILURE) {
2152
0
      zend_accel_lock_discard_script(persistent_script);
2153
0
      persistent_script = NULL;
2154
0
    }
2155
26.5k
  }
2156
2157
  /* Check the second level cache */
2158
250k
  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
250k
  if (!persistent_script) {
2164
105k
    uint32_t old_const_num = zend_hash_next_free_element(EG(zend_constants));
2165
105k
    zend_op_array *op_array;
2166
2167
    /* Cache miss.. */
2168
105k
    ZCSG(misses)++;
2169
2170
    /* No memory left. Behave like without the Accelerator */
2171
105k
    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
105k
    zend_begin_record_errors();
2181
2182
105k
    SHM_PROTECT();
2183
105k
    HANDLE_UNBLOCK_INTERRUPTIONS();
2184
105k
    persistent_script = opcache_compile_file(file_handle, type, &op_array);
2185
105k
    HANDLE_BLOCK_INTERRUPTIONS();
2186
105k
    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
105k
    from_shared_memory = false;
2192
105k
    if (persistent_script) {
2193
49.4k
      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
49.4k
      bool orig_gc_state = gc_enable(false);
2200
49.4k
      persistent_script = cache_script_in_shared_memory(persistent_script, key, &from_shared_memory);
2201
49.4k
      gc_enable(orig_gc_state);
2202
49.4k
    }
2203
2204
    /* Caching is disabled, returning op_array;
2205
     * or something went wrong during compilation, returning NULL
2206
     */
2207
105k
    if (!persistent_script) {
2208
50.6k
      SHM_PROTECT();
2209
50.6k
      HANDLE_UNBLOCK_INTERRUPTIONS();
2210
50.6k
      zend_emit_recorded_errors();
2211
50.6k
      zend_free_recorded_errors();
2212
50.6k
      return op_array;
2213
50.6k
    }
2214
54.8k
    if (from_shared_memory) {
2215
      /* Delete immutable arrays moved into SHM */
2216
49.4k
      uint32_t new_const_num = zend_hash_next_free_element(EG(zend_constants));
2217
49.4k
      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
49.4k
    }
2222
54.8k
    persistent_script->dynamic_members.last_used = ZCG(request_time);
2223
54.8k
    SHM_PROTECT();
2224
54.8k
    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
54.8k
    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
54.8k
    } else {
2232
54.8k
      zend_emit_recorded_errors();
2233
54.8k
    }
2234
54.8k
    zend_free_recorded_errors();
2235
144k
  } else {
2236
2237
144k
#ifndef ZEND_WIN32
2238
144k
    ZCSG(hits)++; /* TBFixed: may lose one hit */
2239
144k
    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
144k
    if (persistent_script->script.filename) {
2252
142k
      if (!EG(current_execute_data) ||
2253
105k
          !EG(current_execute_data)->func ||
2254
105k
          !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
2255
105k
          !EG(current_execute_data)->opline ||
2256
105k
          EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
2257
105k
          (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
2258
142k
           EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
2259
142k
        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
40.5k
          if (persistent_script->is_phar) {
2262
0
            php_stream_statbuf ssb;
2263
0
            char *fname = emalloc(sizeof("phar://") + ZSTR_LEN(persistent_script->script.filename));
2264
2265
0
            memcpy(fname, "phar://", sizeof("phar://") - 1);
2266
0
            memcpy(fname + sizeof("phar://") - 1, ZSTR_VAL(persistent_script->script.filename), ZSTR_LEN(persistent_script->script.filename) + 1);
2267
0
            php_stream_stat_path(fname, &ssb);
2268
0
            efree(fname);
2269
0
          }
2270
40.5k
        }
2271
142k
      }
2272
142k
    }
2273
144k
    persistent_script->dynamic_members.last_used = ZCG(request_time);
2274
144k
    SHM_PROTECT();
2275
144k
    HANDLE_UNBLOCK_INTERRUPTIONS();
2276
2277
144k
    zend_emit_recorded_errors_ex(persistent_script->num_warnings, persistent_script->warnings);
2278
144k
    from_shared_memory = true;
2279
144k
  }
2280
2281
  /* Fetch jit auto globals used in the script before execution */
2282
199k
  if (persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask)) {
2283
64
    zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask));
2284
64
  }
2285
2286
199k
  return zend_accel_load_script(persistent_script, from_shared_memory);
2287
250k
}
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
4.71k
{
2336
4.71k
  bool needs_autoload;
2337
4.71k
  zend_inheritance_cache_entry *entry = ce->inheritance_cache;
2338
2339
4.71k
  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
3.93k
  return NULL;
2365
4.71k
}
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
2.98k
{
2369
2.98k
  zend_persistent_script dummy;
2370
2.98k
  size_t size;
2371
2.98k
  uint32_t i;
2372
2.98k
  bool needs_autoload;
2373
2.98k
  zend_class_entry *new_ce;
2374
2.98k
  zend_inheritance_cache_entry *entry;
2375
2376
2.98k
  ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_IMMUTABLE));
2377
2.98k
  ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
2378
2379
2.98k
  if (!ZCG(accelerator_enabled) ||
2380
2.98k
      (ZCSG(restart_in_progress) && accel_restart_is_active())) {
2381
0
    return NULL;
2382
0
  }
2383
2384
2.98k
  if (traits_and_interfaces && dependencies) {
2385
100
    for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
2386
50
      if (traits_and_interfaces[i]) {
2387
50
        zend_hash_del(dependencies, traits_and_interfaces[i]->name);
2388
50
      }
2389
50
    }
2390
50
  }
2391
2392
2.98k
  SHM_UNPROTECT();
2393
2.98k
  zend_shared_alloc_lock();
2394
2395
2.98k
  entry = proto->inheritance_cache;
2396
2.98k
  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
2.97k
  zend_shared_alloc_init_xlat_table();
2411
2412
2.97k
  memset(&dummy, 0, sizeof(dummy));
2413
2.97k
  dummy.size = ZEND_ALIGNED_SIZE(
2414
2.97k
    sizeof(zend_inheritance_cache_entry) -
2415
2.97k
    sizeof(void*) +
2416
2.97k
    (sizeof(void*) * (proto->num_traits + proto->num_interfaces)));
2417
2.97k
  if (dependencies) {
2418
100
    dummy.size += ZEND_ALIGNED_SIZE(zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency));
2419
100
  }
2420
2.97k
  ZCG(current_persistent_script) = &dummy;
2421
2.97k
  zend_persist_class_entry_calc(ce);
2422
2.97k
  zend_persist_warnings_calc(EG(errors).size, EG(errors).errors);
2423
2.97k
  size = dummy.size;
2424
2425
2.97k
  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
2.97k
  ZCG(mem) = zend_shared_alloc(size);
2432
2.97k
#endif
2433
2434
2.97k
  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
2.97k
  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
2.97k
  memset(ZCG(mem), 0, size);
2449
2.97k
  entry = (zend_inheritance_cache_entry*)ZCG(mem);
2450
2.97k
  ZCG(mem) = (char*)ZCG(mem) +
2451
2.97k
    ZEND_ALIGNED_SIZE(
2452
2.97k
      (sizeof(zend_inheritance_cache_entry) -
2453
2.97k
       sizeof(void*) +
2454
2.97k
       (sizeof(void*) * (proto->num_traits + proto->num_interfaces))));
2455
2.97k
  entry->parent = parent;
2456
6.13k
  for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
2457
3.16k
    entry->traits_and_interfaces[i] = traits_and_interfaces[i];
2458
3.16k
  }
2459
2.97k
  if (dependencies && zend_hash_num_elements(dependencies)) {
2460
92
    zend_string *dep_name;
2461
92
    zend_class_entry *dep_ce;
2462
2463
92
    i = 0;
2464
92
    entry->dependencies_count = zend_hash_num_elements(dependencies);
2465
92
    entry->dependencies = (zend_class_dependency*)ZCG(mem);
2466
636
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(dependencies, dep_name, dep_ce) {
2467
636
#if ZEND_DEBUG
2468
636
      ZEND_ASSERT(zend_accel_in_shm(dep_name));
2469
636
#endif
2470
636
      entry->dependencies[i].name = dep_name;
2471
226
      entry->dependencies[i].ce = dep_ce;
2472
226
      i++;
2473
226
    } ZEND_HASH_FOREACH_END();
2474
92
    ZCG(mem) = (char*)ZCG(mem) + zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency);
2475
92
  }
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
2.97k
#ifdef HAVE_JIT
2481
2.97k
  bool jit_on_old = JIT_G(on);
2482
2.97k
  JIT_G(on) = false;
2483
2.97k
#endif
2484
2485
2.97k
  entry->ce = new_ce = zend_persist_class_entry(ce);
2486
2.97k
  zend_update_parent_ce(new_ce);
2487
2488
2.97k
#ifdef HAVE_JIT
2489
2.97k
  JIT_G(on) = jit_on_old;
2490
2.97k
#endif
2491
2492
2.97k
  entry->num_warnings = EG(errors).size;
2493
2.97k
  entry->warnings = zend_persist_warnings(EG(errors).size, EG(errors).errors);
2494
2.97k
  entry->next = proto->inheritance_cache;
2495
2.97k
  proto->inheritance_cache = entry;
2496
2497
2.97k
  ZCSG(map_ptr_last) = CG(map_ptr_last);
2498
2499
2.97k
  zend_shared_alloc_destroy_xlat_table();
2500
2501
2.97k
  zend_shared_alloc_unlock();
2502
2.97k
  SHM_PROTECT();
2503
2504
  /* Consistency check */
2505
2.97k
  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
2.97k
  zend_map_ptr_extend(ZCSG(map_ptr_last));
2516
2517
2.97k
  return new_ce;
2518
2.97k
}
2519
2520
#ifdef ZEND_WIN32
2521
static zend_result accel_gen_uname_id(void)
2522
{
2523
  PHP_MD5_CTX ctx;
2524
  unsigned char digest[16];
2525
  wchar_t uname[UNLEN + 1];
2526
  DWORD unsize = UNLEN;
2527
2528
  if (!GetUserNameW(uname, &unsize)) {
2529
    return FAILURE;
2530
  }
2531
  PHP_MD5Init(&ctx);
2532
  PHP_MD5Update(&ctx, (void *) uname, (unsize - 1) * sizeof(wchar_t));
2533
  PHP_MD5Update(&ctx, ZCG(accel_directives).cache_id, strlen(ZCG(accel_directives).cache_id));
2534
  PHP_MD5Final(digest, &ctx);
2535
  php_hash_bin2hex(accel_uname_id, digest, sizeof digest);
2536
  return SUCCESS;
2537
}
2538
#endif
2539
2540
/* zend_stream_open_function() replacement for PHP 5.3 and above */
2541
static zend_result persistent_stream_open_function(zend_file_handle *handle)
2542
1.67k
{
2543
1.67k
  if (ZCG(cache_persistent_script)) {
2544
    /* check if callback is called from include_once or it's a main request */
2545
10
    if ((!EG(current_execute_data) &&
2546
0
         handle->primary_script &&
2547
0
         ZCG(cache_opline) == NULL) ||
2548
10
        (EG(current_execute_data) &&
2549
10
         EG(current_execute_data)->func &&
2550
10
         ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
2551
10
         ZCG(cache_opline) == EG(current_execute_data)->opline)) {
2552
2553
      /* we are in include_once or FastCGI request */
2554
10
      handle->opened_path = zend_string_copy(ZCG(cache_persistent_script)->script.filename);
2555
10
      return SUCCESS;
2556
10
    }
2557
0
    ZCG(cache_opline) = NULL;
2558
0
    ZCG(cache_persistent_script) = NULL;
2559
0
  }
2560
1.66k
  return accelerator_orig_zend_stream_open_function(handle);
2561
1.67k
}
2562
2563
/* zend_resolve_path() replacement for PHP 5.3 and above */
2564
static zend_string* persistent_zend_resolve_path(zend_string *filename)
2565
6.83k
{
2566
6.83k
  if (!file_cache_only &&
2567
6.83k
      ZCG(accelerator_enabled)) {
2568
2569
    /* check if callback is called from include_once or it's a main request */
2570
6.83k
    if ((!EG(current_execute_data)) ||
2571
6.83k
        (EG(current_execute_data) &&
2572
6.83k
         EG(current_execute_data)->func &&
2573
6.83k
         ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
2574
6.83k
         EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
2575
6.83k
         (EG(current_execute_data)->opline->extended_value == ZEND_INCLUDE_ONCE ||
2576
6.80k
          EG(current_execute_data)->opline->extended_value == ZEND_REQUIRE_ONCE))) {
2577
2578
      /* we are in include_once or FastCGI request */
2579
2.27k
      zend_string *resolved_path;
2580
2.27k
      zend_string *key = NULL;
2581
2582
2.27k
      if (!ZCG(accel_directives).revalidate_path) {
2583
        /* lookup by "not-real" path */
2584
2.27k
        key = accel_make_persistent_key(filename);
2585
2.27k
        if (key) {
2586
2.27k
          const zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), key);
2587
2.27k
          if (bucket != NULL) {
2588
14
            zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
2589
14
            if (!persistent_script->corrupted) {
2590
14
              ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
2591
14
              ZCG(cache_persistent_script) = persistent_script;
2592
14
              return zend_string_copy(persistent_script->script.filename);
2593
14
            }
2594
14
          }
2595
2.27k
        } else {
2596
0
          ZCG(cache_opline) = NULL;
2597
0
          ZCG(cache_persistent_script) = NULL;
2598
0
          return accelerator_orig_zend_resolve_path(filename);
2599
0
        }
2600
2.27k
      }
2601
2602
      /* find the full real path */
2603
2.26k
      resolved_path = accelerator_orig_zend_resolve_path(filename);
2604
2605
2.26k
      if (resolved_path) {
2606
        /* lookup by real path */
2607
10
        zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path);
2608
10
        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
10
      }
2629
2630
2.26k
      ZCG(cache_opline) = NULL;
2631
2.26k
      ZCG(cache_persistent_script) = NULL;
2632
2.26k
      return resolved_path;
2633
2.26k
    }
2634
6.83k
  }
2635
4.56k
  ZCG(cache_opline) = NULL;
2636
4.56k
  ZCG(cache_persistent_script) = NULL;
2637
4.56k
  return accelerator_orig_zend_resolve_path(filename);
2638
6.83k
}
2639
2640
static void zend_reset_cache_vars(void)
2641
16
{
2642
16
  ZSMMG(memory_exhausted) = false;
2643
16
  ZCSG(hits) = 0;
2644
16
  ZCSG(misses) = 0;
2645
16
  ZCSG(blacklist_misses) = 0;
2646
16
  ZSMMG(wasted_shared_memory) = 0;
2647
16
  ZCSG(restart_pending) = false;
2648
16
  ZCSG(force_restart_time) = 0;
2649
16
  ZCSG(map_ptr_last) = CG(map_ptr_last);
2650
16
  ZCSG(map_ptr_static_last) = zend_map_ptr_static_last;
2651
16
}
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
228k
{
2668
228k
  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
228k
  ZCG(auto_globals_mask) = 0;
2675
228k
  ZCG(request_time) = (time_t)sapi_get_request_time();
2676
228k
  ZCG(cache_opline) = NULL;
2677
228k
  ZCG(cache_persistent_script) = NULL;
2678
228k
  ZCG(include_path_key_len) = 0;
2679
228k
  ZCG(include_path_check) = true;
2680
2681
228k
  ZCG(cwd) = NULL;
2682
228k
  ZCG(cwd_key_len) = 0;
2683
228k
  ZCG(cwd_check) = true;
2684
2685
228k
  if (file_cache_only) {
2686
0
    ZCG(accelerator_enabled) = false;
2687
0
    return SUCCESS;
2688
0
  }
2689
2690
228k
#ifndef ZEND_WIN32
2691
228k
  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
228k
  } else {
2709
228k
    ZCG(root_hash) = 0;
2710
228k
  }
2711
228k
#endif
2712
2713
228k
  HANDLE_BLOCK_INTERRUPTIONS();
2714
228k
  SHM_UNPROTECT();
2715
2716
228k
  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
228k
  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
228k
  ZCG(accelerator_enabled) = ZCSG(accelerator_enabled);
2777
2778
228k
  SHM_PROTECT();
2779
228k
  HANDLE_UNBLOCK_INTERRUPTIONS();
2780
2781
228k
  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
228k
  } 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
228k
#ifdef HAVE_JIT
2797
228k
  zend_jit_activate();
2798
228k
#endif
2799
2800
228k
#ifdef PRELOAD_SUPPORT
2801
228k
  if (ZCSG(preload_script)) {
2802
0
    preload_activate();
2803
0
  }
2804
228k
#endif
2805
2806
228k
  return SUCCESS;
2807
228k
}
2808
2809
#ifdef HAVE_JIT
2810
void accel_deactivate(void)
2811
228k
{
2812
228k
  zend_jit_deactivate();
2813
228k
}
2814
#endif
2815
2816
zend_result accel_post_deactivate(void)
2817
228k
{
2818
228k
  if (ZCG(cwd)) {
2819
39.2k
    zend_string_release_ex(ZCG(cwd), 0);
2820
39.2k
    ZCG(cwd) = NULL;
2821
39.2k
  }
2822
2823
228k
  if (!ZCG(enabled) || !accel_startup_ok) {
2824
0
    return SUCCESS;
2825
0
  }
2826
2827
228k
  zend_shared_alloc_safe_unlock(); /* be sure we didn't leave cache locked */
2828
228k
  accel_unlock_all();
2829
228k
  ZCG(counted) = false;
2830
2831
228k
  return SUCCESS;
2832
228k
}
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
16
{
2869
16
  return strcmp(sapi_module.name, "cli") == 0
2870
16
    || strcmp(sapi_module.name, "phpdbg") == 0;
2871
16
}
2872
2873
static zend_result zend_accel_init_shm(void)
2874
16
{
2875
16
  int i;
2876
16
  size_t accel_shared_globals_size;
2877
2878
16
  zend_shared_alloc_lock();
2879
2880
16
  if (ZCG(accel_directives).interned_strings_buffer) {
2881
16
    accel_shared_globals_size = sizeof(zend_accel_shared_globals) + ZCG(accel_directives).interned_strings_buffer * 1024 * 1024;
2882
16
  } 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
16
  accel_shared_globals = zend_shared_alloc(accel_shared_globals_size);
2889
16
  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
16
  memset(accel_shared_globals, 0, sizeof(zend_accel_shared_globals));
2897
16
  ZSMMG(app_shared_globals) = accel_shared_globals;
2898
2899
16
  zend_accel_hash_init(&ZCSG(hash), ZCG(accel_directives).max_accelerated_files);
2900
2901
16
  if (ZCG(accel_directives).interned_strings_buffer) {
2902
16
    uint32_t hash_size;
2903
2904
    /* must be a power of two */
2905
16
    hash_size = ZCG(accel_directives).interned_strings_buffer * (32 * 1024);
2906
16
    hash_size |= (hash_size >> 1);
2907
16
    hash_size |= (hash_size >> 2);
2908
16
    hash_size |= (hash_size >> 4);
2909
16
    hash_size |= (hash_size >> 8);
2910
16
    hash_size |= (hash_size >> 16);
2911
2912
16
    ZCSG(interned_strings).nTableMask =
2913
16
      hash_size * sizeof(zend_string_table_pos_t);
2914
16
    ZCSG(interned_strings).nNumOfElements = 0;
2915
16
    ZCSG(interned_strings).start =
2916
16
      (zend_string*)((char*)&ZCSG(interned_strings) +
2917
16
        sizeof(zend_string_table) +
2918
16
        ((hash_size + 1) * sizeof(zend_string_table_pos_t))) +
2919
16
        8;
2920
16
    ZEND_ASSERT(((uintptr_t)ZCSG(interned_strings).start & 0x7) == 0); /* should be 8 byte aligned */
2921
2922
16
    ZCSG(interned_strings).top =
2923
16
      ZCSG(interned_strings).start;
2924
16
    ZCSG(interned_strings).end =
2925
16
      (zend_string*)((char*)(accel_shared_globals + 1) + /* table data is stored after accel_shared_globals */
2926
16
        ZCG(accel_directives).interned_strings_buffer * 1024 * 1024);
2927
16
    ZEND_ASSERT(((uintptr_t)ZCSG(interned_strings).end - (uintptr_t)&ZCSG(interned_strings)) / ZEND_STRING_TABLE_POS_ALIGNMENT < ZEND_STRING_TABLE_POS_MAX);
2928
16
    ZCSG(interned_strings).saved_top = NULL;
2929
2930
16
    memset((char*)&ZCSG(interned_strings) + sizeof(zend_string_table),
2931
16
      STRTAB_INVALID_POS,
2932
16
      (char*)ZCSG(interned_strings).start -
2933
16
        ((char*)&ZCSG(interned_strings) + sizeof(zend_string_table)));
2934
16
  } 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
16
  zend_interned_strings_set_request_storage_handlers(
2941
16
    accel_new_interned_string_for_php,
2942
16
    accel_init_interned_string_for_php,
2943
16
    accel_init_interned_string_for_php);
2944
2945
16
  zend_reset_cache_vars();
2946
2947
16
  ZCSG(oom_restarts) = 0;
2948
16
  ZCSG(hash_restarts) = 0;
2949
16
  ZCSG(manual_restarts) = 0;
2950
2951
16
  ZCSG(accelerator_enabled) = true;
2952
16
  ZCSG(start_time) = zend_accel_get_time();
2953
16
  ZCSG(last_restart_time) = 0;
2954
16
  ZCSG(restart_in_progress) = false;
2955
2956
48
  for (i = 0; i < -HT_MIN_MASK; i++) {
2957
32
    ZCSG(uninitialized_bucket)[i] = HT_INVALID_IDX;
2958
32
  }
2959
2960
16
  zend_shared_alloc_unlock();
2961
2962
16
  return SUCCESS;
2963
16
}
2964
2965
static void accel_globals_ctor(zend_accel_globals *accel_globals)
2966
16
{
2967
16
  memset(accel_globals, 0, sizeof(zend_accel_globals));
2968
16
  accel_globals->key = zend_string_alloc(ZCG_KEY_LEN, true);
2969
16
  GC_MAKE_PERSISTENT_LOCAL(accel_globals->key);
2970
16
}
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
16
{
3184
16
  zend_register_extension(&opcache_extension_entry, NULL);
3185
16
}
3186
3187
static int accel_startup(zend_extension *extension)
3188
16
{
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
16
  accel_globals_ctor(&accel_globals);
3193
16
#endif
3194
3195
16
#ifdef HAVE_JIT
3196
16
  zend_jit_init();
3197
16
#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
16
  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
16
#ifdef HAVE_HUGE_CODE_PAGES
3215
16
  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
16
#endif
3223
3224
16
  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
16
  if (ZCG(enabled) == 0) {
3231
0
    return SUCCESS ;
3232
0
  }
3233
3234
16
  orig_post_startup_cb = zend_post_startup_cb;
3235
16
  zend_post_startup_cb = accel_post_startup;
3236
3237
  /* Prevent unloading */
3238
16
  extension->handle = 0;
3239
3240
16
  return SUCCESS;
3241
16
}
3242
3243
static zend_result accel_post_startup(void)
3244
16
{
3245
16
  zend_function *func;
3246
16
  zend_ini_entry *ini_entry;
3247
3248
16
  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
16
  file_cache_only = ZCG(accel_directives).file_cache_only;
3261
16
  if (!file_cache_only) {
3262
16
    size_t shm_size = ZCG(accel_directives).memory_consumption;
3263
16
#ifdef HAVE_JIT
3264
16
    size_t jit_size = 0;
3265
16
    bool reattached = false;
3266
3267
16
    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
16
    switch (zend_shared_alloc_startup(shm_size, jit_size)) {
3282
#else
3283
    switch (zend_shared_alloc_startup(shm_size, 0)) {
3284
#endif
3285
16
      case ALLOC_SUCCESS:
3286
16
        if (zend_accel_init_shm() == FAILURE) {
3287
0
          accel_startup_ok = false;
3288
0
          return FAILURE;
3289
0
        }
3290
16
        break;
3291
16
      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
16
    }
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
16
    ZCG(last_restart_time) = ZCSG(last_restart_time);
3331
3332
16
    zend_shared_alloc_lock();
3333
16
#ifdef HAVE_JIT
3334
16
    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
16
#endif
3346
16
    zend_shared_alloc_save_state();
3347
16
    zend_shared_alloc_unlock();
3348
3349
16
    SHM_PROTECT();
3350
16
  } 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
16
  int file_cache_access_mode = 0;
3364
3365
16
  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
16
  } else {
3381
    /* opcache.file_cache isn't read only, so ensure the directory is writable */
3382
16
#ifndef ZEND_WIN32
3383
16
    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
16
  }
3388
3389
16
  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
16
  accelerator_orig_compile_file = zend_compile_file;
3415
16
  zend_compile_file = persistent_compile_file;
3416
3417
  /* Override stream opener function (to eliminate open() call caused by
3418
   * include/require statements ) */
3419
16
  accelerator_orig_zend_stream_open_function = zend_stream_open_function;
3420
16
  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
16
  accelerator_orig_zend_resolve_path = zend_resolve_path;
3425
16
  zend_resolve_path = persistent_zend_resolve_path;
3426
3427
  /* Override chdir() function */
3428
16
  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
16
  ZCG(cwd) = NULL;
3434
16
  ZCG(include_path) = NULL;
3435
3436
  /* Override "include_path" modifier callback */
3437
16
  if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
3438
16
    ZCG(include_path) = ini_entry->value;
3439
16
    orig_include_path_on_modify = ini_entry->on_modify;
3440
16
    ini_entry->on_modify = accel_include_path_on_modify;
3441
16
  }
3442
3443
16
  accel_startup_ok = true;
3444
3445
  /* Override file_exists(), is_file() and is_readable() */
3446
16
  zend_accel_override_file_functions();
3447
3448
  /* Load black list */
3449
16
  accel_blacklist.entries = NULL;
3450
16
  if (ZCG(enabled) && accel_startup_ok &&
3451
16
      ZCG(accel_directives).user_blacklist_filename &&
3452
16
      *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
16
  if (!file_cache_only && ZCG(accel_directives).interned_strings_buffer) {
3458
16
    accel_use_shm_interned_strings();
3459
16
  }
3460
3461
16
  if (accel_finish_startup() != SUCCESS) {
3462
0
    return FAILURE;
3463
0
  }
3464
3465
16
  if (ZCG(enabled) && accel_startup_ok) {
3466
    /* Override inheritance cache callbaks */
3467
16
    accelerator_orig_inheritance_cache_get = zend_inheritance_cache_get;
3468
16
    accelerator_orig_inheritance_cache_add = zend_inheritance_cache_add;
3469
16
    zend_inheritance_cache_get = zend_accel_inheritance_cache_get;
3470
16
    zend_inheritance_cache_add = zend_accel_inheritance_cache_add;
3471
16
  }
3472
3473
16
  return SUCCESS;
3474
16
}
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
56.9k
{
3590
56.9k
  if (ZCG(counted)) {
3591
    /* counted means we are holding read lock for SHM, so that nothing bad can happen */
3592
56.9k
    return SUCCESS;
3593
56.9k
  } 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
56.9k
}
3609
3610
/* must be called ONLY after SUCCESSFUL accelerator_shm_read_lock */
3611
void accelerator_shm_read_unlock(void)
3612
56.9k
{
3613
56.9k
  if (!ZCG(counted)) {
3614
    /* counted is false - meaning we had to readlock manually, release readlock now */
3615
0
    accel_deactivate_now();
3616
0
  }
3617
56.9k
}
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
16
{
5058
16
  if (!ZCG(enabled) || !accel_startup_ok) {
5059
0
    return SUCCESS;
5060
0
  }
5061
5062
16
  if (!(ZCG(accel_directives).preload && *ZCG(accel_directives).preload)) {
5063
16
    return SUCCESS;
5064
16
  }
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
228k
static void accel_activate(void) {
5156
228k
  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
228k
}
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
};