Coverage Report

Created: 2025-12-14 06:10

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