Coverage Report

Created: 2025-12-14 06:09

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