Coverage Report

Created: 2026-04-01 06:49

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