Coverage Report

Created: 2026-02-14 06:52

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