Coverage Report

Created: 2026-01-18 06:47

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