Coverage Report

Created: 2025-12-31 07:28

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
14
#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
12.1k
{
164
12.1k
#if defined(__x86_64__)
165
12.1k
  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
12.1k
}
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
14
# define zend_accel_get_time() time(NULL)
203
#endif
204
205
static inline bool is_cacheable_stream_path(const char *filename)
206
1.33k
{
207
1.33k
  return memcmp(filename, "file://", sizeof("file://") - 1) == 0 ||
208
1.33k
         memcmp(filename, "phar://", sizeof("phar://") - 1) == 0;
209
1.33k
}
210
211
/* O+ overrides PHP chdir() function and remembers the current working directory
212
 * in ZCG(cwd) and ZCG(cwd_len). Later accel_getcwd() can use stored value and
213
 * avoid getcwd() call.
214
 */
215
static ZEND_FUNCTION(accel_chdir)
216
0
{
217
0
  char cwd[MAXPATHLEN];
218
219
0
  orig_chdir(INTERNAL_FUNCTION_PARAM_PASSTHRU);
220
0
  if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
221
0
    if (ZCG(cwd)) {
222
0
      zend_string_release_ex(ZCG(cwd), 0);
223
0
    }
224
0
    ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
225
0
  } else {
226
0
    if (ZCG(cwd)) {
227
0
      zend_string_release_ex(ZCG(cwd), 0);
228
0
      ZCG(cwd) = NULL;
229
0
    }
230
0
  }
231
0
  ZCG(cwd_key_len) = 0;
232
0
  ZCG(cwd_check) = true;
233
0
}
234
235
static inline zend_string* accel_getcwd(void)
236
49.7k
{
237
49.7k
  if (ZCG(cwd)) {
238
0
    return ZCG(cwd);
239
49.7k
  } else {
240
49.7k
    char cwd[MAXPATHLEN + 1];
241
242
49.7k
    if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
243
0
      return NULL;
244
0
    }
245
49.7k
    ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
246
49.7k
    ZCG(cwd_key_len) = 0;
247
49.7k
    ZCG(cwd_check) = true;
248
49.7k
    return ZCG(cwd);
249
49.7k
  }
250
49.7k
}
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
10
{
266
10
  int ret = orig_include_path_on_modify(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
267
268
10
  if (ret == SUCCESS) {
269
10
    ZCG(include_path) = new_value;
270
10
    ZCG(include_path_key_len) = 0;
271
10
    ZCG(include_path_check) = true;
272
10
  }
273
10
  return ret;
274
10
}
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
113k
{
346
#ifdef ZEND_WIN32
347
  SHM_UNPROTECT();
348
  INCREMENT(mem_usage);
349
  SHM_PROTECT();
350
#else
351
113k
  struct flock mem_usage_lock;
352
353
113k
  mem_usage_lock.l_type = F_RDLCK;
354
113k
  mem_usage_lock.l_whence = SEEK_SET;
355
113k
  mem_usage_lock.l_start = 1;
356
113k
  mem_usage_lock.l_len = 1;
357
358
113k
  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
113k
#endif
363
113k
  return SUCCESS;
364
113k
}
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
222k
{
392
#ifdef ZEND_WIN32
393
  accel_deactivate_sub();
394
#else
395
222k
  if (lock_file == -1) {
396
0
    return;
397
0
  }
398
399
222k
  struct flock mem_usage_unlock_all;
400
401
222k
  mem_usage_unlock_all.l_type = F_UNLCK;
402
222k
  mem_usage_unlock_all.l_whence = SEEK_SET;
403
222k
  mem_usage_unlock_all.l_start = 0;
404
222k
  mem_usage_unlock_all.l_len = 0;
405
406
222k
  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
222k
#endif
410
222k
}
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
827k
#define STRTAB_INVALID_POS 0
420
421
#define STRTAB_HASH_TO_SLOT(tab, h) \
422
41.9M
  ((zend_string_table_pos_t*)((char*)(tab) + sizeof(*(tab)) + ((h) & (tab)->nTableMask)))
423
#define STRTAB_STR_TO_POS(tab, s) \
424
166k
  ((zend_string_table_pos_t)(((char*)s - (char*)(tab)) / ZEND_STRING_TABLE_POS_ALIGNMENT))
425
#define STRTAB_POS_TO_STR(tab, pos) \
426
3.10M
  ((zend_string*)((char*)(tab) + ((uintptr_t)(pos) * ZEND_STRING_TABLE_POS_ALIGNMENT)))
427
#define STRTAB_COLLISION(s) \
428
894k
  (*((zend_string_table_pos_t*)((char*)s - sizeof(zend_string_table_pos_t))))
429
#define STRTAB_STR_SIZE(s) \
430
67.5k
  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
67.5k
  ((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
14
{
477
14
  ZCSG(interned_strings).saved_top = ZCSG(interned_strings).top;
478
14
}
479
480
static zend_always_inline zend_string *accel_find_interned_string(zend_string *str)
481
43.8M
{
482
43.8M
  zend_ulong   h;
483
43.8M
  zend_string_table_pos_t pos;
484
43.8M
  zend_string *s;
485
486
43.8M
  if (IS_ACCEL_INTERNED(str)) {
487
    /* this is already an interned string */
488
2.27M
    return str;
489
2.27M
  }
490
491
41.6M
  if (!ZCG(counted)) {
492
49.6k
    if (!ZCG(accelerator_enabled) || accel_activate_add() == FAILURE) {
493
0
      return NULL;
494
0
    }
495
49.6k
    ZCG(counted) = true;
496
49.6k
  }
497
498
41.6M
  h = zend_string_hash_val(str);
499
500
  /* check for existing interned string */
501
41.6M
  pos = *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
502
41.6M
  if (EXPECTED(pos != STRTAB_INVALID_POS)) {
503
2.94M
    do {
504
2.94M
      s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
505
2.94M
      if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
506
2.13M
        return s;
507
2.13M
      }
508
809k
      pos = STRTAB_COLLISION(s);
509
809k
    } while (pos != STRTAB_INVALID_POS);
510
2.21M
  }
511
512
39.4M
  return NULL;
513
41.6M
}
514
515
zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str)
516
247k
{
517
247k
  zend_ulong   h;
518
247k
  zend_string_table_pos_t pos, *hash_slot;
519
247k
  zend_string *s;
520
521
247k
  if (UNEXPECTED(file_cache_only)) {
522
0
    return str;
523
0
  }
524
525
247k
  if (IS_ACCEL_INTERNED(str)) {
526
    /* this is already an interned string */
527
4.43k
    return str;
528
4.43k
  }
529
530
243k
  h = zend_string_hash_val(str);
531
532
  /* check for existing interned string */
533
243k
  hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
534
243k
  pos = *hash_slot;
535
243k
  if (EXPECTED(pos != STRTAB_INVALID_POS)) {
536
159k
    do {
537
159k
      s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
538
159k
      if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
539
142k
        goto finish;
540
142k
      }
541
16.7k
      pos = STRTAB_COLLISION(s);
542
16.7k
    } while (pos != STRTAB_INVALID_POS);
543
148k
  }
544
545
101k
  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
33.7k
    zend_accel_error(ACCEL_LOG_WARNING, "Interned string buffer overflow");
548
33.7k
    return str;
549
33.7k
  }
550
551
  /* create new interning string in shared interned strings buffer */
552
67.5k
  ZCSG(interned_strings).nNumOfElements++;
553
67.5k
  s = ZCSG(interned_strings).top;
554
67.5k
  hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
555
67.5k
  STRTAB_COLLISION(s) = *hash_slot;
556
67.5k
  *hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s);
557
67.5k
  GC_SET_REFCOUNT(s, 2);
558
67.5k
  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
67.5k
  ZSTR_H(s) = h;
560
67.5k
  ZSTR_LEN(s) = ZSTR_LEN(str);
561
67.5k
  memcpy(ZSTR_VAL(s), ZSTR_VAL(str), ZSTR_LEN(s) + 1);
562
67.5k
  ZCSG(interned_strings).top = STRTAB_NEXT(s);
563
564
209k
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
209k
  if (ZSTR_HAS_CE_CACHE(str) && !ZSTR_HAS_CE_CACHE(s)) {
568
2.31k
    ZEND_ASSERT(GC_FLAGS(str) & IS_STR_PERMANENT);
569
2.31k
    GC_SET_REFCOUNT(s, GC_REFCOUNT(str));
570
2.31k
    GC_ADD_FLAGS(s, IS_STR_CLASS_NAME_MAP_PTR);
571
2.31k
  }
572
573
209k
  zend_string_release(str);
574
209k
  return s;
575
209k
}
576
577
static zend_string* ZEND_FASTCALL accel_new_interned_string_for_php(zend_string *str)
578
43.7M
{
579
43.7M
  zend_string_hash_val(str);
580
43.7M
  if (ZCG(counted)) {
581
43.7M
    zend_string *ret = accel_find_interned_string(str);
582
583
43.7M
    if (ret) {
584
4.30M
      zend_string_release(str);
585
4.30M
      return ret;
586
4.30M
    }
587
43.7M
  }
588
39.4M
  return str;
589
43.7M
}
590
591
static zend_always_inline zend_string *accel_find_interned_string_ex(zend_ulong h, const char *str, size_t size)
592
4.02k
{
593
4.02k
  zend_string_table_pos_t pos;
594
4.02k
  zend_string *s;
595
596
  /* check for existing interned string */
597
4.02k
  pos = *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
598
4.02k
  if (EXPECTED(pos != STRTAB_INVALID_POS)) {
599
2.15k
    do {
600
2.15k
      s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
601
2.15k
      if (EXPECTED(ZSTR_H(s) == h) && zend_string_equals_cstr(s, str, size)) {
602
1.69k
        return s;
603
1.69k
      }
604
456
      pos = STRTAB_COLLISION(s);
605
456
    } while (pos != STRTAB_INVALID_POS);
606
1.69k
  }
607
2.32k
  return NULL;
608
4.02k
}
609
610
static zend_string* ZEND_FASTCALL accel_init_interned_string_for_php(const char *str, size_t size, bool permanent)
611
1.48M
{
612
1.48M
  if (ZCG(counted)) {
613
4.02k
      zend_ulong h = zend_inline_hash_func(str, size);
614
4.02k
    zend_string *ret = accel_find_interned_string_ex(h, str, size);
615
616
4.02k
    if (!ret) {
617
2.32k
      ret = zend_string_init(str, size, permanent);
618
2.32k
      ZSTR_H(ret) = h;
619
2.32k
    }
620
621
4.02k
    return ret;
622
4.02k
  }
623
624
1.48M
  return zend_string_init(str, size, permanent);
625
1.48M
}
626
627
static inline void accel_copy_permanent_list_types(
628
  zend_new_interned_string_func_t new_interned_string, zend_type type)
629
46.4k
{
630
46.4k
  zend_type *single_type;
631
92.9k
  ZEND_TYPE_FOREACH_MUTABLE(type, single_type) {
632
92.9k
    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
92.9k
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
637
3.27k
      ZEND_TYPE_SET_PTR(*single_type, new_interned_string(ZEND_TYPE_NAME(*single_type)));
638
3.27k
    }
639
46.4k
  } ZEND_TYPE_FOREACH_END();
640
46.4k
}
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
14
{
645
14
  uint32_t j;
646
14
  Bucket *p, *q;
647
14
  HashTable *ht;
648
649
  /* empty string */
650
14
  zend_empty_string = new_interned_string(zend_empty_string);
651
3.59k
  for (j = 0; j < 256; j++) {
652
3.58k
    zend_one_char_string[j] = new_interned_string(ZSTR_CHAR(j));
653
3.58k
  }
654
1.24k
  for (j = 0; j < ZEND_STR_LAST_KNOWN; j++) {
655
1.23k
    zend_known_strings[j] = new_interned_string(zend_known_strings[j]);
656
1.23k
  }
657
658
  /* function table hash keys */
659
19.2k
  ZEND_HASH_MAP_FOREACH_BUCKET(CG(function_table), p) {
660
19.2k
    if (p->key) {
661
9.63k
      p->key = new_interned_string(p->key);
662
9.63k
    }
663
19.2k
    if (Z_FUNC(p->val)->common.function_name) {
664
9.63k
      Z_FUNC(p->val)->common.function_name = new_interned_string(Z_FUNC(p->val)->common.function_name);
665
9.63k
    }
666
19.2k
    if (Z_FUNC(p->val)->common.arg_info) {
667
9.63k
      uint32_t i;
668
9.63k
      uint32_t num_args = Z_FUNC(p->val)->common.num_args + 1;
669
9.63k
      zend_arg_info *arg_info = Z_FUNC(p->val)->common.arg_info - 1;
670
671
9.63k
      if (Z_FUNC(p->val)->common.fn_flags & ZEND_ACC_VARIADIC) {
672
560
        num_args++;
673
560
      }
674
35.8k
      for (i = 0 ; i < num_args; i++) {
675
26.2k
        if (i > 0) {
676
16.5k
          arg_info[i].name = new_interned_string(arg_info[i].name);
677
16.5k
          if (arg_info[i].default_value) {
678
5.34k
            arg_info[i].default_value = new_interned_string(arg_info[i].default_value);
679
5.34k
          }
680
16.5k
        }
681
26.2k
        accel_copy_permanent_list_types(new_interned_string, arg_info[i].type);
682
26.2k
      }
683
9.63k
    }
684
19.2k
  } ZEND_HASH_FOREACH_END();
685
686
  /* class table hash keys, class names, properties, methods, constants, etc */
687
4.64k
  ZEND_HASH_MAP_FOREACH_BUCKET(CG(class_table), p) {
688
4.64k
    zend_class_entry *ce;
689
690
4.64k
    ce = (zend_class_entry*)Z_PTR(p->val);
691
692
4.64k
    if (p->key) {
693
2.31k
      p->key = new_interned_string(p->key);
694
2.31k
    }
695
696
4.64k
    if (ce->name) {
697
2.31k
      ce->name = new_interned_string(ce->name);
698
2.31k
      ZEND_ASSERT(ZSTR_HAS_CE_CACHE(ce->name));
699
2.31k
    }
700
701
15.1k
    ZEND_HASH_MAP_FOREACH_BUCKET(&ce->properties_info, q) {
702
15.1k
      zend_property_info *info;
703
704
15.1k
      info = (zend_property_info*)Z_PTR(q->val);
705
706
15.1k
      if (q->key) {
707
5.27k
        q->key = new_interned_string(q->key);
708
5.27k
      }
709
710
15.1k
      if (info->name) {
711
5.27k
        info->name = new_interned_string(info->name);
712
5.27k
      }
713
15.1k
    } ZEND_HASH_FOREACH_END();
714
715
63.8k
    ZEND_HASH_MAP_FOREACH_BUCKET(&ce->function_table, q) {
716
63.8k
      if (q->key) {
717
29.6k
        q->key = new_interned_string(q->key);
718
29.6k
      }
719
63.8k
      if (Z_FUNC(q->val)->common.function_name) {
720
29.6k
        Z_FUNC(q->val)->common.function_name = new_interned_string(Z_FUNC(q->val)->common.function_name);
721
29.6k
      }
722
63.8k
      if (Z_FUNC(q->val)->common.scope == ce) {
723
13.3k
        uint32_t i;
724
13.3k
        uint32_t num_args = Z_FUNC(q->val)->common.num_args + 1;
725
13.3k
        zend_arg_info *arg_info = Z_FUNC(q->val)->common.arg_info - 1;
726
727
13.3k
        if (Z_FUNC(q->val)->common.fn_flags & ZEND_ACC_VARIADIC) {
728
84
          num_args++;
729
84
        }
730
33.5k
        for (i = 0 ; i < num_args; i++) {
731
20.2k
          if (i > 0) {
732
6.93k
            arg_info[i].name = new_interned_string(arg_info[i].name);
733
6.93k
            if (arg_info[i].default_value) {
734
2.10k
              arg_info[i].default_value = new_interned_string(arg_info[i].default_value);
735
2.10k
            }
736
6.93k
          }
737
20.2k
          accel_copy_permanent_list_types(new_interned_string, arg_info[i].type);
738
20.2k
        }
739
13.3k
      }
740
63.8k
    } ZEND_HASH_FOREACH_END();
741
742
12.2k
    ZEND_HASH_MAP_FOREACH_BUCKET(&ce->constants_table, q) {
743
12.2k
      zend_class_constant* c;
744
745
12.2k
      if (q->key) {
746
3.80k
        q->key = new_interned_string(q->key);
747
3.80k
      }
748
12.2k
      c = (zend_class_constant*)Z_PTR(q->val);
749
12.2k
      if (Z_TYPE(c->value) == IS_STRING) {
750
588
        ZVAL_STR(&c->value, new_interned_string(Z_STR(c->value)));
751
588
      }
752
12.2k
    } ZEND_HASH_FOREACH_END();
753
2.31k
  } ZEND_HASH_FOREACH_END();
754
755
  /* constant hash keys */
756
15.2k
  ZEND_HASH_MAP_FOREACH_BUCKET(EG(zend_constants), p) {
757
15.2k
    zend_constant *c;
758
759
15.2k
    if (p->key) {
760
7.63k
      p->key = new_interned_string(p->key);
761
7.63k
    }
762
15.2k
    c = (zend_constant*)Z_PTR(p->val);
763
15.2k
    if (c->name) {
764
7.63k
      c->name = new_interned_string(c->name);
765
7.63k
    }
766
15.2k
    if (Z_TYPE(c->value) == IS_STRING) {
767
602
      ZVAL_STR(&c->value, new_interned_string(Z_STR(c->value)));
768
602
    }
769
15.2k
  } ZEND_HASH_FOREACH_END();
770
771
  /* auto globals hash keys and names */
772
252
  ZEND_HASH_MAP_FOREACH_BUCKET(CG(auto_globals), p) {
773
252
    zend_auto_global *auto_global;
774
775
252
    auto_global = (zend_auto_global*)Z_PTR(p->val);
776
777
252
    zend_string_addref(auto_global->name);
778
252
    auto_global->name = new_interned_string(auto_global->name);
779
252
    if (p->key) {
780
112
      p->key = new_interned_string(p->key);
781
112
    }
782
252
  } ZEND_HASH_FOREACH_END();
783
784
392
  ZEND_HASH_MAP_FOREACH_BUCKET(&module_registry, p) {
785
392
    if (p->key) {
786
182
      p->key = new_interned_string(p->key);
787
182
    }
788
392
  } ZEND_HASH_FOREACH_END();
789
790
5.01k
  ZEND_HASH_MAP_FOREACH_BUCKET(EG(ini_directives), p) {
791
5.01k
    zend_ini_entry *entry = (zend_ini_entry*)Z_PTR(p->val);
792
793
5.01k
    if (p->key) {
794
2.49k
      p->key = new_interned_string(p->key);
795
2.49k
    }
796
5.01k
    if (entry->name) {
797
2.49k
      entry->name = new_interned_string(entry->name);
798
2.49k
    }
799
5.01k
    if (entry->value) {
800
2.14k
      entry->value = new_interned_string(entry->value);
801
2.14k
    }
802
5.01k
    if (entry->orig_value) {
803
0
      entry->orig_value = new_interned_string(entry->orig_value);
804
0
    }
805
5.01k
  } ZEND_HASH_FOREACH_END();
806
807
14
  ht = php_get_stream_filters_hash_global();
808
196
  ZEND_HASH_MAP_FOREACH_BUCKET(ht, p) {
809
196
    if (p->key) {
810
84
      p->key = new_interned_string(p->key);
811
84
    }
812
196
  } ZEND_HASH_FOREACH_END();
813
814
14
  ht = php_stream_get_url_stream_wrappers_hash_global();
815
196
  ZEND_HASH_MAP_FOREACH_BUCKET(ht, p) {
816
196
    if (p->key) {
817
84
      p->key = new_interned_string(p->key);
818
84
    }
819
196
  } ZEND_HASH_FOREACH_END();
820
821
14
  ht = php_stream_xport_get_hash();
822
140
  ZEND_HASH_MAP_FOREACH_BUCKET(ht, p) {
823
140
    if (p->key) {
824
56
      p->key = new_interned_string(p->key);
825
56
    }
826
140
  } ZEND_HASH_FOREACH_END();
827
14
}
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
14
{
842
14
  HANDLE_BLOCK_INTERRUPTIONS();
843
14
  SHM_UNPROTECT();
844
14
  zend_shared_alloc_lock();
845
846
14
  if (ZCSG(interned_strings).saved_top == NULL) {
847
14
    accel_copy_permanent_strings(accel_new_interned_string);
848
14
  } 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
14
  accel_interned_strings_save_state();
854
855
14
  zend_shared_alloc_unlock();
856
14
  SHM_PROTECT();
857
14
  HANDLE_UNBLOCK_INTERRUPTIONS();
858
14
}
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
58.1k
{
1050
58.1k
  zend_stat_t statbuf = {0};
1051
#ifdef ZEND_WIN32
1052
  accel_time_t res;
1053
#endif
1054
1055
58.1k
  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
58.1k
  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
58.1k
    case ZEND_HANDLE_STREAM:
1103
58.1k
      {
1104
58.1k
        php_stream *stream = (php_stream *)file_handle->handle.stream.handle;
1105
58.1k
        php_stream_statbuf sb;
1106
58.1k
        int ret, er;
1107
1108
58.1k
        if (!stream ||
1109
3
            !stream->ops ||
1110
58.1k
            !stream->ops->stat) {
1111
58.1k
          return 0;
1112
58.1k
        }
1113
1114
3
        er = EG(error_reporting);
1115
3
        EG(error_reporting) = 0;
1116
3
        zend_try {
1117
3
          ret = stream->ops->stat(stream, &sb);
1118
3
        } zend_catch {
1119
0
          ret = -1;
1120
0
        } zend_end_try();
1121
3
        EG(error_reporting) = er;
1122
3
        if (ret != 0) {
1123
0
          return 0;
1124
0
        }
1125
1126
3
        statbuf = sb.sb;
1127
3
      }
1128
0
      break;
1129
1130
0
    default:
1131
0
      return 0;
1132
58.1k
  }
1133
1134
3
  if (size) {
1135
0
    *size = statbuf.st_size;
1136
0
  }
1137
3
  return statbuf.st_mtime;
1138
58.1k
}
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
37.7k
{
1199
37.7k
  if (persistent_script->timestamp == 0) {
1200
0
    return SUCCESS; /* Don't check timestamps of preloaded scripts */
1201
37.7k
  } else if (ZCG(accel_directives).revalidate_freq &&
1202
37.7k
      persistent_script->dynamic_members.revalidate >= ZCG(request_time)) {
1203
37.7k
    return SUCCESS;
1204
37.7k
  } 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
37.7k
}
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
153k
{
1226
153k
  const char *path = ZSTR_VAL(str);
1227
153k
  size_t path_length = ZSTR_LEN(str);
1228
153k
  char *key;
1229
153k
  int key_length;
1230
1231
153k
  ZEND_ASSERT(GC_REFCOUNT(ZCG(key)) == 1);
1232
153k
  ZSTR_LEN(ZCG(key)) = 0;
1233
1234
  /* CWD and include_path don't matter for absolute file names and streams */
1235
153k
  if (IS_ABSOLUTE_PATH(path, path_length)) {
1236
    /* pass */
1237
98.4k
  } else if (UNEXPECTED(php_is_stream_path(path))) {
1238
1.33k
    if (!is_cacheable_stream_path(path)) {
1239
1.33k
      return NULL;
1240
1.33k
    }
1241
    /* pass */
1242
54.2k
  } else if (UNEXPECTED(!ZCG(accel_directives).use_cwd)) {
1243
    /* pass */
1244
54.2k
  } else {
1245
54.2k
    const char *include_path = NULL, *cwd = NULL;
1246
54.2k
    int include_path_len = 0, cwd_len = 0;
1247
54.2k
    zend_string *parent_script = NULL;
1248
54.2k
    size_t parent_script_len = 0;
1249
1250
54.2k
    if (EXPECTED(ZCG(cwd_key_len))) {
1251
4.51k
      cwd = ZCG(cwd_key);
1252
4.51k
      cwd_len = ZCG(cwd_key_len);
1253
49.7k
    } else {
1254
49.7k
      zend_string *cwd_str = accel_getcwd();
1255
1256
49.7k
      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
49.7k
      cwd = ZSTR_VAL(cwd_str);
1262
49.7k
      cwd_len = ZSTR_LEN(cwd_str);
1263
49.7k
      if (ZCG(cwd_check)) {
1264
49.7k
        ZCG(cwd_check) = false;
1265
49.7k
        if (ZCG(accelerator_enabled)) {
1266
1267
49.7k
          zend_string *str = accel_find_interned_string(cwd_str);
1268
49.7k
          if (!str) {
1269
3
            HANDLE_BLOCK_INTERRUPTIONS();
1270
3
            SHM_UNPROTECT();
1271
3
            zend_shared_alloc_lock();
1272
3
            str = accel_new_interned_string(zend_string_copy(cwd_str));
1273
3
            if (str == cwd_str) {
1274
0
              zend_string_release_ex(str, 0);
1275
0
              str = NULL;
1276
0
            }
1277
3
            zend_shared_alloc_unlock();
1278
3
            SHM_PROTECT();
1279
3
            HANDLE_UNBLOCK_INTERRUPTIONS();
1280
3
          }
1281
49.7k
          if (str) {
1282
49.7k
            char buf[32];
1283
49.7k
            char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, STRTAB_STR_TO_POS(&ZCSG(interned_strings), str));
1284
1285
49.7k
            cwd_len = ZCG(cwd_key_len) = buf + sizeof(buf) - 1 - res;
1286
49.7k
            cwd = ZCG(cwd_key);
1287
49.7k
            memcpy(ZCG(cwd_key), res, cwd_len + 1);
1288
49.7k
          } else {
1289
0
            return NULL;
1290
0
          }
1291
49.7k
        } else {
1292
0
          return NULL;
1293
0
        }
1294
49.7k
      }
1295
49.7k
    }
1296
1297
54.2k
    if (EXPECTED(ZCG(include_path_key_len))) {
1298
4.51k
      include_path = ZCG(include_path_key);
1299
4.51k
      include_path_len = ZCG(include_path_key_len);
1300
49.7k
    } else if (!ZCG(include_path) || ZSTR_LEN(ZCG(include_path)) == 0) {
1301
0
      include_path = "";
1302
0
      include_path_len = 0;
1303
49.7k
    } else {
1304
49.7k
      include_path = ZSTR_VAL(ZCG(include_path));
1305
49.7k
      include_path_len = ZSTR_LEN(ZCG(include_path));
1306
1307
49.7k
      if (ZCG(include_path_check)) {
1308
49.7k
        ZCG(include_path_check) = false;
1309
49.7k
        if (ZCG(accelerator_enabled)) {
1310
1311
49.7k
          zend_string *str = accel_find_interned_string(ZCG(include_path));
1312
49.7k
          if (!str) {
1313
1
            HANDLE_BLOCK_INTERRUPTIONS();
1314
1
            SHM_UNPROTECT();
1315
1
            zend_shared_alloc_lock();
1316
1
            str = accel_new_interned_string(zend_string_copy(ZCG(include_path)));
1317
1
            if (str == ZCG(include_path)) {
1318
0
              zend_string_release(str);
1319
0
              str = NULL;
1320
0
            }
1321
1
            zend_shared_alloc_unlock();
1322
1
            SHM_PROTECT();
1323
1
            HANDLE_UNBLOCK_INTERRUPTIONS();
1324
1
          }
1325
49.7k
          if (str) {
1326
49.7k
            char buf[32];
1327
49.7k
            char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, STRTAB_STR_TO_POS(&ZCSG(interned_strings), str));
1328
1329
49.7k
            include_path_len = ZCG(include_path_key_len) = buf + sizeof(buf) - 1 - res;
1330
49.7k
            include_path = ZCG(include_path_key);
1331
49.7k
            memcpy(ZCG(include_path_key), res, include_path_len + 1);
1332
49.7k
          } else {
1333
0
            return NULL;
1334
0
          }
1335
49.7k
        } else {
1336
0
          return NULL;
1337
0
        }
1338
49.7k
      }
1339
49.7k
    }
1340
1341
    /* Calculate key length */
1342
54.2k
    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
54.2k
    key = ZSTR_VAL(ZCG(key));
1352
54.2k
    memcpy(key, path, path_length);
1353
54.2k
    key[path_length] = ':';
1354
54.2k
    key_length = path_length + 1;
1355
54.2k
    memcpy(key + key_length, cwd, cwd_len);
1356
54.2k
    key_length += cwd_len;
1357
1358
54.2k
    if (include_path_len) {
1359
54.2k
      key[key_length] = ':';
1360
54.2k
      key_length += 1;
1361
54.2k
      memcpy(key + key_length, include_path, include_path_len);
1362
54.2k
      key_length += include_path_len;
1363
54.2k
    }
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
54.2k
    if (EXPECTED(EG(current_execute_data)) &&
1370
4.61k
        EXPECTED((parent_script = zend_get_executed_filename_ex()) != NULL)) {
1371
1372
4.61k
      parent_script_len = ZSTR_LEN(parent_script);
1373
50.7k
      while (parent_script_len > 0) {
1374
50.7k
        --parent_script_len;
1375
50.7k
        if (IS_SLASH(ZSTR_VAL(parent_script)[parent_script_len])) {
1376
4.61k
          break;
1377
4.61k
        }
1378
50.7k
      }
1379
1380
4.61k
      if (UNEXPECTED((size_t)(key_length + parent_script_len + 1) >= ZCG_KEY_LEN)) {
1381
0
        return NULL;
1382
0
      }
1383
4.61k
      key[key_length] = ':';
1384
4.61k
      key_length += 1;
1385
4.61k
      memcpy(key + key_length, ZSTR_VAL(parent_script), parent_script_len);
1386
4.61k
      key_length += parent_script_len;
1387
4.61k
    }
1388
54.2k
    key[key_length] = '\0';
1389
54.2k
    ZSTR_H(ZCG(key)) = 0;
1390
54.2k
    ZSTR_LEN(ZCG(key)) = key_length;
1391
54.2k
    return ZCG(key);
1392
54.2k
  }
1393
1394
  /* not use_cwd */
1395
98.4k
  return str;
1396
153k
}
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
12.1k
{
1406
12.1k
  if (persistent_script->corrupted) {
1407
    /* already discarded */
1408
0
    return;
1409
0
  }
1410
1411
12.1k
  persistent_script->corrupted = true;
1412
12.1k
  persistent_script->timestamp = 0;
1413
12.1k
  ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
1414
12.1k
  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
12.1k
}
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
12.1k
{
1427
12.1k
  zend_shared_alloc_lock();
1428
12.1k
  zend_accel_discard_script(persistent_script);
1429
12.1k
  zend_shared_alloc_unlock();
1430
12.1k
}
1431
1432
zend_result zend_accel_invalidate(zend_string *filename, bool force)
1433
13.2k
{
1434
13.2k
  zend_string *realpath;
1435
13.2k
  zend_persistent_script *persistent_script;
1436
13.2k
  zend_bool file_found = true;
1437
1438
13.2k
  if (!ZCG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) {
1439
0
    return FAILURE;
1440
0
  }
1441
1442
13.2k
  realpath = accelerator_orig_zend_resolve_path(filename);
1443
1444
13.2k
  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
13.2k
  if (ZCG(accel_directives).file_cache) {
1452
0
    zend_file_cache_invalidate(realpath);
1453
0
  }
1454
1455
13.2k
  persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath);
1456
13.2k
  if (persistent_script && !persistent_script->corrupted) {
1457
12.1k
    zend_file_handle file_handle;
1458
12.1k
    zend_stream_init_filename_ex(&file_handle, realpath);
1459
12.1k
    file_handle.opened_path = realpath;
1460
1461
12.1k
    if (force ||
1462
0
      !ZCG(accel_directives).validate_timestamps ||
1463
12.1k
      do_validate_timestamps(persistent_script, &file_handle) == FAILURE) {
1464
12.1k
      HANDLE_BLOCK_INTERRUPTIONS();
1465
12.1k
      SHM_UNPROTECT();
1466
12.1k
      zend_accel_lock_discard_script(persistent_script);
1467
12.1k
      SHM_PROTECT();
1468
12.1k
      HANDLE_UNBLOCK_INTERRUPTIONS();
1469
12.1k
    }
1470
1471
12.1k
    file_handle.opened_path = NULL;
1472
12.1k
    zend_destroy_file_handle(&file_handle);
1473
12.1k
    file_found = true;
1474
12.1k
  }
1475
1476
13.2k
  accelerator_shm_read_unlock();
1477
13.2k
  zend_string_release_ex(realpath, 0);
1478
1479
13.2k
  return file_found ? SUCCESS : FAILURE;
1480
13.2k
}
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
12.1k
{
1528
12.1k
  return filename && ZSTR_LEN(filename) >= sizeof(".phar") &&
1529
12.1k
    !memcmp(ZSTR_VAL(filename) + ZSTR_LEN(filename) - (sizeof(".phar")-1), ".phar", sizeof(".phar")-1) &&
1530
0
    !strstr(ZSTR_VAL(filename), "://");
1531
12.1k
}
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
12.1k
{
1596
12.1k
  zend_accel_hash_entry *bucket;
1597
12.1k
  uint32_t memory_used;
1598
12.1k
  uint32_t orig_compiler_options;
1599
1600
12.1k
  orig_compiler_options = CG(compiler_options);
1601
12.1k
  if (ZCG(accel_directives).file_cache) {
1602
0
    CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
1603
0
  }
1604
12.1k
  zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level);
1605
12.1k
  zend_accel_finalize_delayed_early_binding_list(new_persistent_script);
1606
12.1k
  CG(compiler_options) = orig_compiler_options;
1607
1608
  /* exclusive lock */
1609
12.1k
  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
12.1k
  bucket = zend_accel_hash_find_entry(&ZCSG(hash), new_persistent_script->script.filename);
1615
12.1k
  if (bucket) {
1616
12.1k
    zend_persistent_script *existing_persistent_script = (zend_persistent_script *)bucket->data;
1617
1618
12.1k
    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
12.1k
  }
1635
1636
12.1k
  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
12.1k
  zend_shared_alloc_init_xlat_table();
1649
1650
  /* Calculate the required memory size */
1651
12.1k
  memory_used = zend_accel_script_persist_calc(new_persistent_script, 1);
1652
1653
  /* Allocate shared memory */
1654
12.1k
  ZCG(mem) = zend_shared_alloc_aligned(memory_used);
1655
12.1k
  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
12.1k
  bzero_aligned(ZCG(mem), memory_used);
1667
1668
12.1k
  zend_shared_alloc_clear_xlat_table();
1669
1670
  /* Copy into shared memory */
1671
12.1k
  new_persistent_script = zend_accel_script_persist(new_persistent_script, 1);
1672
1673
12.1k
  zend_shared_alloc_destroy_xlat_table();
1674
1675
12.1k
  new_persistent_script->is_phar = is_phar_file(new_persistent_script->script.filename);
1676
1677
  /* Consistency check */
1678
12.1k
  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
12.1k
  bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->script.filename, 0, new_persistent_script);
1690
12.1k
  if (bucket) {
1691
12.1k
    zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", ZSTR_VAL(new_persistent_script->script.filename));
1692
12.1k
    if (key &&
1693
        /* key may contain non-persistent PHAR aliases (see issues #115 and #149) */
1694
12.1k
        !zend_string_starts_with_literal(key, "phar://") &&
1695
12.1k
        !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
12.1k
  }
1712
1713
12.1k
  new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
1714
1715
12.1k
  zend_shared_alloc_unlock();
1716
1717
12.1k
  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
12.1k
  *from_shared_memory = true;
1724
12.1k
  return new_persistent_script;
1725
12.1k
}
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
12.1k
{
1733
12.1k
  int mask = 0;
1734
12.1k
  if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER))) {
1735
0
    mask |= ZEND_AUTOGLOBAL_MASK_SERVER;
1736
0
  }
1737
12.1k
  if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_ENV))) {
1738
0
    mask |= ZEND_AUTOGLOBAL_MASK_ENV;
1739
0
  }
1740
12.1k
  if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_REQUEST))) {
1741
0
    mask |= ZEND_AUTOGLOBAL_MASK_REQUEST;
1742
0
  }
1743
12.1k
  return mask;
1744
12.1k
}
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
71.9k
{
1762
71.9k
  zend_persistent_script *new_persistent_script;
1763
71.9k
  uint32_t orig_functions_count, orig_class_count;
1764
71.9k
  zend_op_array *orig_active_op_array;
1765
71.9k
  zend_op_array *op_array;
1766
71.9k
  bool do_bailout = false;
1767
71.9k
  accel_time_t timestamp = 0;
1768
71.9k
  uint32_t orig_compiler_options = 0;
1769
1770
  /* Try to open file */
1771
71.9k
  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
71.9k
  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
71.9k
  if (ZCG(accel_directives).validate_timestamps ||
1795
13.8k
      ZCG(accel_directives).file_update_protection ||
1796
58.1k
      ZCG(accel_directives).max_file_size > 0) {
1797
58.1k
    size_t size = 0;
1798
1799
    /* Obtain the file timestamps, *before* actually compiling them,
1800
     * otherwise we have a race-condition.
1801
     */
1802
58.1k
    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
58.1k
    if (timestamp == 0) {
1808
58.1k
      *op_array_p = accelerator_orig_compile_file(file_handle, type);
1809
58.1k
      return NULL;
1810
58.1k
    }
1811
1812
    /* check if file is too new (may be it's not written completely yet) */
1813
3
    if (ZCG(accel_directives).file_update_protection &&
1814
3
        ((accel_time_t)(ZCG(request_time) - ZCG(accel_directives).file_update_protection) < timestamp)) {
1815
2
      *op_array_p = accelerator_orig_compile_file(file_handle, type);
1816
2
      return NULL;
1817
2
    }
1818
1819
1
    if (ZCG(accel_directives).max_file_size > 0 && size > (size_t)ZCG(accel_directives).max_file_size) {
1820
0
      SHM_UNPROTECT();
1821
0
      ZCSG(blacklist_misses)++;
1822
0
      SHM_PROTECT();
1823
0
      *op_array_p = accelerator_orig_compile_file(file_handle, type);
1824
0
      return NULL;
1825
0
    }
1826
1
  }
1827
1828
  /* Save the original values for the op_array, function table and class table */
1829
13.8k
  orig_active_op_array = CG(active_op_array);
1830
13.8k
  orig_functions_count = EG(function_table)->nNumUsed;
1831
13.8k
  orig_class_count = EG(class_table)->nNumUsed;
1832
1833
13.8k
  zend_try {
1834
13.8k
    orig_compiler_options = CG(compiler_options);
1835
13.8k
    CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
1836
13.8k
    CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
1837
13.8k
    CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
1838
13.8k
    CG(compiler_options) |= ZEND_COMPILE_IGNORE_OTHER_FILES;
1839
13.8k
    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
13.8k
    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
13.8k
    op_array = *op_array_p = accelerator_orig_compile_file(file_handle, type);
1852
13.8k
    CG(compiler_options) = orig_compiler_options;
1853
13.8k
  } 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
13.8k
  CG(active_op_array) = orig_active_op_array;
1861
1862
13.8k
  if (!op_array) {
1863
    /* compilation failed */
1864
1.63k
    if (do_bailout) {
1865
69
      EG(record_errors) = false;
1866
69
      zend_free_recorded_errors();
1867
69
      zend_bailout();
1868
69
    }
1869
1.56k
    return NULL;
1870
1.63k
  }
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
12.1k
  new_persistent_script = create_persistent_script();
1877
12.1k
  new_persistent_script->script.main_op_array = *op_array;
1878
12.1k
  zend_accel_move_user_functions(CG(function_table), CG(function_table)->nNumUsed - orig_functions_count, &new_persistent_script->script);
1879
12.1k
  zend_accel_move_user_classes(CG(class_table), CG(class_table)->nNumUsed - orig_class_count, &new_persistent_script->script);
1880
12.1k
  zend_accel_build_delayed_early_binding_list(new_persistent_script);
1881
1882
12.1k
  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
12.1k
  if (PG(auto_globals_jit)) {
1887
12.1k
    new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals();
1888
12.1k
  }
1889
1890
12.1k
  if (ZCG(accel_directives).validate_timestamps) {
1891
    /* Obtain the file timestamps, *before* actually compiling them,
1892
     * otherwise we have a race-condition.
1893
     */
1894
1
    new_persistent_script->timestamp = timestamp;
1895
1
    new_persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
1896
1
  }
1897
1898
12.1k
  if (file_handle->opened_path) {
1899
1
    new_persistent_script->script.filename = zend_string_copy(file_handle->opened_path);
1900
12.1k
  } else {
1901
12.1k
    new_persistent_script->script.filename = zend_string_copy(file_handle->filename);
1902
12.1k
  }
1903
12.1k
  zend_string_hash_val(new_persistent_script->script.filename);
1904
1905
  /* Now persistent_script structure is ready in process memory */
1906
12.1k
  return new_persistent_script;
1907
13.8k
}
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
151k
{
2020
151k
  zend_persistent_script *persistent_script = NULL;
2021
151k
  zend_string *key = NULL;
2022
151k
  bool from_shared_memory; /* if the script we've got is stored in SHM */
2023
2024
151k
  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
151k
  } 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
151k
  } 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
151k
  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
151k
  } else {
2065
151k
    if (!ZCG(accel_directives).revalidate_path) {
2066
      /* try to find cached script by key */
2067
151k
      key = accel_make_persistent_key(file_handle->filename);
2068
151k
      if (!key) {
2069
1.33k
        ZCG(cache_opline) = NULL;
2070
1.33k
        ZCG(cache_persistent_script) = NULL;
2071
1.33k
        return accelerator_orig_compile_file(file_handle, type);
2072
1.33k
      }
2073
150k
      persistent_script = zend_accel_hash_find(&ZCSG(hash), key);
2074
150k
    } 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
150k
    if (!persistent_script) {
2081
      /* try to find cached script by full real path */
2082
60.7k
      zend_accel_hash_entry *bucket;
2083
2084
      /* open file to resolve the path */
2085
60.7k
        if (file_handle->type == ZEND_HANDLE_FILENAME
2086
2.64k
         && accelerator_orig_zend_stream_open_function(file_handle) == FAILURE) {
2087
660
        if (!EG(exception)) {
2088
656
          if (type == ZEND_REQUIRE) {
2089
32
            zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
2090
624
          } else {
2091
624
            zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
2092
624
          }
2093
656
        }
2094
660
        return NULL;
2095
660
        }
2096
2097
60.0k
      if (file_handle->opened_path) {
2098
3
        bucket = zend_accel_hash_find_entry(&ZCSG(hash), file_handle->opened_path);
2099
2100
3
        if (bucket) {
2101
0
          persistent_script = (zend_persistent_script *)bucket->data;
2102
2103
0
          if (key && !persistent_script->corrupted) {
2104
0
            HANDLE_BLOCK_INTERRUPTIONS();
2105
0
            SHM_UNPROTECT();
2106
0
            zend_shared_alloc_lock();
2107
0
            zend_accel_add_key(key, bucket);
2108
0
            zend_shared_alloc_unlock();
2109
0
            SHM_PROTECT();
2110
0
            HANDLE_UNBLOCK_INTERRUPTIONS();
2111
0
          }
2112
0
        }
2113
3
      }
2114
60.0k
    }
2115
150k
  }
2116
2117
  /* clear cache */
2118
149k
  ZCG(cache_opline) = NULL;
2119
149k
  ZCG(cache_persistent_script) = NULL;
2120
2121
149k
  if (persistent_script && persistent_script->corrupted) {
2122
13.8k
    persistent_script = NULL;
2123
13.8k
  }
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
149k
  if (!ZCG(counted)) {
2130
63.5k
    if (accel_activate_add() == FAILURE) {
2131
0
      if (ZCG(accel_directives).file_cache) {
2132
0
        return file_cache_compile_file(file_handle, type);
2133
0
      }
2134
0
      return accelerator_orig_compile_file(file_handle, type);
2135
0
    }
2136
63.5k
    ZCG(counted) = true;
2137
63.5k
  }
2138
2139
  /* Revalidate accessibility of cached file */
2140
149k
  if (EXPECTED(persistent_script != NULL) &&
2141
76.0k
      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
149k
  HANDLE_BLOCK_INTERRUPTIONS();
2155
149k
  SHM_UNPROTECT();
2156
2157
  /* If script is found then validate_timestamps if option is enabled */
2158
149k
  if (persistent_script && ZCG(accel_directives).validate_timestamps) {
2159
37.7k
    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
37.7k
  }
2164
2165
  /* Check the second level cache */
2166
149k
  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
149k
  if (!persistent_script) {
2172
71.9k
    uint32_t old_const_num = zend_hash_next_free_element(EG(zend_constants));
2173
71.9k
    zend_op_array *op_array;
2174
2175
    /* Cache miss.. */
2176
71.9k
    ZCSG(misses)++;
2177
2178
    /* No memory left. Behave like without the Accelerator */
2179
71.9k
    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
71.9k
    zend_begin_record_errors();
2189
2190
71.9k
    SHM_PROTECT();
2191
71.9k
    HANDLE_UNBLOCK_INTERRUPTIONS();
2192
71.9k
    persistent_script = opcache_compile_file(file_handle, type, &op_array);
2193
71.9k
    HANDLE_BLOCK_INTERRUPTIONS();
2194
71.9k
    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
71.9k
    from_shared_memory = false;
2200
71.9k
    if (persistent_script) {
2201
12.1k
      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
12.1k
      bool orig_gc_state = gc_enable(false);
2208
12.1k
      persistent_script = cache_script_in_shared_memory(persistent_script, key, &from_shared_memory);
2209
12.1k
      gc_enable(orig_gc_state);
2210
12.1k
    }
2211
2212
    /* Caching is disabled, returning op_array;
2213
     * or something went wrong during compilation, returning NULL
2214
     */
2215
71.9k
    if (!persistent_script) {
2216
56.4k
      SHM_PROTECT();
2217
56.4k
      HANDLE_UNBLOCK_INTERRUPTIONS();
2218
56.4k
      zend_emit_recorded_errors();
2219
56.4k
      zend_free_recorded_errors();
2220
56.4k
      return op_array;
2221
56.4k
    }
2222
15.4k
    if (from_shared_memory) {
2223
      /* Delete immutable arrays moved into SHM */
2224
12.1k
      uint32_t new_const_num = zend_hash_next_free_element(EG(zend_constants));
2225
12.1k
      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
12.1k
    }
2230
15.4k
    persistent_script->dynamic_members.last_used = ZCG(request_time);
2231
15.4k
    SHM_PROTECT();
2232
15.4k
    HANDLE_UNBLOCK_INTERRUPTIONS();
2233
2234
    /* We may have switched to an existing persistent script that was persisted in
2235
     * the meantime. Make sure to use its warnings if available. */
2236
15.4k
    if (ZCG(accel_directives).record_warnings) {
2237
0
      EG(record_errors) = false;
2238
0
      zend_emit_recorded_errors_ex(persistent_script->num_warnings, persistent_script->warnings);
2239
15.4k
    } else {
2240
15.4k
      zend_emit_recorded_errors();
2241
15.4k
    }
2242
15.4k
    zend_free_recorded_errors();
2243
78.0k
  } else {
2244
2245
78.0k
#ifndef ZEND_WIN32
2246
78.0k
    ZCSG(hits)++; /* TBFixed: may lose one hit */
2247
78.0k
    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
78.0k
    if (persistent_script->script.filename) {
2260
76.0k
      if (!EG(current_execute_data) ||
2261
34.8k
          !EG(current_execute_data)->func ||
2262
34.8k
          !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
2263
34.8k
          !EG(current_execute_data)->opline ||
2264
34.8k
          EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
2265
34.8k
          (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
2266
76.0k
           EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
2267
76.0k
        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
43.3k
          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
43.3k
        }
2279
76.0k
      }
2280
76.0k
    }
2281
78.0k
    persistent_script->dynamic_members.last_used = ZCG(request_time);
2282
78.0k
    SHM_PROTECT();
2283
78.0k
    HANDLE_UNBLOCK_INTERRUPTIONS();
2284
2285
78.0k
    zend_emit_recorded_errors_ex(persistent_script->num_warnings, persistent_script->warnings);
2286
78.0k
    from_shared_memory = true;
2287
78.0k
  }
2288
2289
  /* Fetch jit auto globals used in the script before execution */
2290
93.5k
  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
93.5k
  return zend_accel_load_script(persistent_script, from_shared_memory);
2295
149k
}
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
105
{
2299
105
  uint32_t i;
2300
2301
105
  ZEND_ASSERT(ce->ce_flags & ZEND_ACC_IMMUTABLE);
2302
105
  ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
2303
2304
105
  while (entry) {
2305
105
    bool found = true;
2306
105
    bool needs_autoload = false;
2307
2308
105
    if (entry->parent != parent) {
2309
0
      found = false;
2310
105
    } else {
2311
227
      for (i = 0; i < ce->num_traits + ce->num_interfaces; i++) {
2312
122
        if (entry->traits_and_interfaces[i] != traits_and_interfaces[i]) {
2313
0
          found = false;
2314
0
          break;
2315
0
        }
2316
122
      }
2317
105
      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
105
    }
2332
105
    if (found) {
2333
105
      *needs_autoload_ptr = needs_autoload;
2334
105
      return entry;
2335
105
    }
2336
0
    entry = entry->next;
2337
0
  }
2338
2339
0
  return NULL;
2340
105
}
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
331
{
2344
331
  uint32_t i;
2345
331
  bool needs_autoload;
2346
331
  zend_inheritance_cache_entry *entry = ce->inheritance_cache;
2347
2348
331
  while (entry) {
2349
105
    entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload);
2350
105
    if (entry) {
2351
105
      if (!needs_autoload) {
2352
105
        zend_emit_recorded_errors_ex(entry->num_warnings, entry->warnings);
2353
105
        if (ZCSG(map_ptr_last) > CG(map_ptr_last)) {
2354
0
          zend_map_ptr_extend(ZCSG(map_ptr_last));
2355
0
        }
2356
105
        ce = entry->ce;
2357
105
        if (ZSTR_HAS_CE_CACHE(ce->name)) {
2358
103
          ZSTR_SET_CE_CACHE_EX(ce->name, ce, 0);
2359
103
        }
2360
105
        return ce;
2361
105
      }
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
105
  }
2372
2373
226
  return NULL;
2374
331
}
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
217
{
2378
217
  zend_persistent_script dummy;
2379
217
  size_t size;
2380
217
  uint32_t i;
2381
217
  bool needs_autoload;
2382
217
  zend_class_entry *new_ce;
2383
217
  zend_inheritance_cache_entry *entry;
2384
2385
217
  ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_IMMUTABLE));
2386
217
  ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
2387
2388
217
  if (!ZCG(accelerator_enabled) ||
2389
217
      (ZCSG(restart_in_progress) && accel_restart_is_active())) {
2390
0
    return NULL;
2391
0
  }
2392
2393
217
  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
217
  SHM_UNPROTECT();
2402
217
  zend_shared_alloc_lock();
2403
2404
217
  entry = proto->inheritance_cache;
2405
217
  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
217
  zend_shared_alloc_init_xlat_table();
2420
2421
217
  memset(&dummy, 0, sizeof(dummy));
2422
217
  dummy.size = ZEND_ALIGNED_SIZE(
2423
217
    sizeof(zend_inheritance_cache_entry) -
2424
217
    sizeof(void*) +
2425
217
    (sizeof(void*) * (proto->num_traits + proto->num_interfaces)));
2426
217
  if (dependencies) {
2427
0
    dummy.size += ZEND_ALIGNED_SIZE(zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency));
2428
0
  }
2429
217
  ZCG(current_persistent_script) = &dummy;
2430
217
  zend_persist_class_entry_calc(ce);
2431
217
  zend_persist_warnings_calc(EG(num_errors), EG(errors));
2432
217
  size = dummy.size;
2433
2434
217
  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
217
  ZCG(mem) = zend_shared_alloc(size);
2441
217
#endif
2442
2443
217
  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
217
  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
217
  memset(ZCG(mem), 0, size);
2458
217
  entry = (zend_inheritance_cache_entry*)ZCG(mem);
2459
217
  ZCG(mem) = (char*)ZCG(mem) +
2460
217
    ZEND_ALIGNED_SIZE(
2461
217
      (sizeof(zend_inheritance_cache_entry) -
2462
217
       sizeof(void*) +
2463
217
       (sizeof(void*) * (proto->num_traits + proto->num_interfaces))));
2464
217
  entry->parent = parent;
2465
468
  for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
2466
251
    entry->traits_and_interfaces[i] = traits_and_interfaces[i];
2467
251
  }
2468
217
  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
217
#ifdef HAVE_JIT
2490
217
  bool jit_on_old = JIT_G(on);
2491
217
  JIT_G(on) = false;
2492
217
#endif
2493
2494
217
  entry->ce = new_ce = zend_persist_class_entry(ce);
2495
217
  zend_update_parent_ce(new_ce);
2496
2497
217
#ifdef HAVE_JIT
2498
217
  JIT_G(on) = jit_on_old;
2499
217
#endif
2500
2501
217
  entry->num_warnings = EG(num_errors);
2502
217
  entry->warnings = zend_persist_warnings(EG(num_errors), EG(errors));
2503
217
  entry->next = proto->inheritance_cache;
2504
217
  proto->inheritance_cache = entry;
2505
2506
217
  ZCSG(map_ptr_last) = CG(map_ptr_last);
2507
2508
217
  zend_shared_alloc_destroy_xlat_table();
2509
2510
217
  zend_shared_alloc_unlock();
2511
217
  SHM_PROTECT();
2512
2513
  /* Consistency check */
2514
217
  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
217
  zend_map_ptr_extend(ZCSG(map_ptr_last));
2525
2526
217
  return new_ce;
2527
217
}
2528
2529
#ifdef ZEND_WIN32
2530
static zend_result accel_gen_uname_id(void)
2531
{
2532
  PHP_MD5_CTX ctx;
2533
  unsigned char digest[16];
2534
  wchar_t uname[UNLEN + 1];
2535
  DWORD unsize = UNLEN;
2536
2537
  if (!GetUserNameW(uname, &unsize)) {
2538
    return FAILURE;
2539
  }
2540
  PHP_MD5Init(&ctx);
2541
  PHP_MD5Update(&ctx, (void *) uname, (unsize - 1) * sizeof(wchar_t));
2542
  PHP_MD5Update(&ctx, ZCG(accel_directives).cache_id, strlen(ZCG(accel_directives).cache_id));
2543
  PHP_MD5Final(digest, &ctx);
2544
  php_hash_bin2hex(accel_uname_id, digest, sizeof digest);
2545
  return SUCCESS;
2546
}
2547
#endif
2548
2549
/* zend_stream_open_function() replacement for PHP 5.3 and above */
2550
static zend_result persistent_stream_open_function(zend_file_handle *handle)
2551
1.35k
{
2552
1.35k
  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
1.35k
  return accelerator_orig_zend_stream_open_function(handle);
2570
1.35k
}
2571
2572
/* zend_resolve_path() replacement for PHP 5.3 and above */
2573
static zend_string* persistent_zend_resolve_path(zend_string *filename)
2574
5.99k
{
2575
5.99k
  if (!file_cache_only &&
2576
5.99k
      ZCG(accelerator_enabled)) {
2577
2578
    /* check if callback is called from include_once or it's a main request */
2579
5.99k
    if ((!EG(current_execute_data)) ||
2580
5.99k
        (EG(current_execute_data) &&
2581
5.99k
         EG(current_execute_data)->func &&
2582
5.99k
         ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
2583
5.98k
         EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
2584
5.98k
         (EG(current_execute_data)->opline->extended_value == ZEND_INCLUDE_ONCE ||
2585
5.98k
          EG(current_execute_data)->opline->extended_value == ZEND_REQUIRE_ONCE))) {
2586
2587
      /* we are in include_once or FastCGI request */
2588
2.01k
      zend_string *resolved_path;
2589
2.01k
      zend_string *key = NULL;
2590
2591
2.01k
      if (!ZCG(accel_directives).revalidate_path) {
2592
        /* lookup by "not-real" path */
2593
2.01k
        key = accel_make_persistent_key(filename);
2594
2.01k
        if (key) {
2595
2.01k
          zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), key);
2596
2.01k
          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
2.01k
        } else {
2605
0
          ZCG(cache_opline) = NULL;
2606
0
          ZCG(cache_persistent_script) = NULL;
2607
0
          return accelerator_orig_zend_resolve_path(filename);
2608
0
        }
2609
2.01k
      }
2610
2611
      /* find the full real path */
2612
2.01k
      resolved_path = accelerator_orig_zend_resolve_path(filename);
2613
2614
2.01k
      if (resolved_path) {
2615
        /* lookup by real path */
2616
2
        zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path);
2617
2
        if (bucket) {
2618
0
          zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
2619
0
          if (!persistent_script->corrupted) {
2620
0
            if (key) {
2621
              /* add another "key" for the same bucket */
2622
0
              HANDLE_BLOCK_INTERRUPTIONS();
2623
0
              SHM_UNPROTECT();
2624
0
              zend_shared_alloc_lock();
2625
0
              zend_accel_add_key(key, bucket);
2626
0
              zend_shared_alloc_unlock();
2627
0
              SHM_PROTECT();
2628
0
              HANDLE_UNBLOCK_INTERRUPTIONS();
2629
0
            } else {
2630
0
              ZSTR_LEN(ZCG(key)) = 0;
2631
0
            }
2632
0
            ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
2633
0
            ZCG(cache_persistent_script) = persistent_script;
2634
0
            return resolved_path;
2635
0
          }
2636
0
        }
2637
2
      }
2638
2639
2.01k
      ZCG(cache_opline) = NULL;
2640
2.01k
      ZCG(cache_persistent_script) = NULL;
2641
2.01k
      return resolved_path;
2642
2.01k
    }
2643
5.99k
  }
2644
3.97k
  ZCG(cache_opline) = NULL;
2645
3.97k
  ZCG(cache_persistent_script) = NULL;
2646
3.97k
  return accelerator_orig_zend_resolve_path(filename);
2647
5.99k
}
2648
2649
static void zend_reset_cache_vars(void)
2650
14
{
2651
14
  ZSMMG(memory_exhausted) = false;
2652
14
  ZCSG(hits) = 0;
2653
14
  ZCSG(misses) = 0;
2654
14
  ZCSG(blacklist_misses) = 0;
2655
14
  ZSMMG(wasted_shared_memory) = 0;
2656
14
  ZCSG(restart_pending) = false;
2657
14
  ZCSG(force_restart_time) = 0;
2658
14
  ZCSG(map_ptr_last) = CG(map_ptr_last);
2659
14
  ZCSG(map_ptr_static_last) = zend_map_ptr_static_last;
2660
14
}
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
222k
{
2677
222k
  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
222k
  ZCG(auto_globals_mask) = 0;
2684
222k
  ZCG(request_time) = (time_t)sapi_get_request_time();
2685
222k
  ZCG(cache_opline) = NULL;
2686
222k
  ZCG(cache_persistent_script) = NULL;
2687
222k
  ZCG(include_path_key_len) = 0;
2688
222k
  ZCG(include_path_check) = true;
2689
2690
222k
  ZCG(cwd) = NULL;
2691
222k
  ZCG(cwd_key_len) = 0;
2692
222k
  ZCG(cwd_check) = true;
2693
2694
222k
  if (file_cache_only) {
2695
0
    ZCG(accelerator_enabled) = false;
2696
0
    return SUCCESS;
2697
0
  }
2698
2699
222k
#ifndef ZEND_WIN32
2700
222k
  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
222k
  } else {
2718
222k
    ZCG(root_hash) = 0;
2719
222k
  }
2720
222k
#endif
2721
2722
222k
  HANDLE_BLOCK_INTERRUPTIONS();
2723
222k
  SHM_UNPROTECT();
2724
2725
222k
  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
222k
  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
222k
  ZCG(accelerator_enabled) = ZCSG(accelerator_enabled);
2786
2787
222k
  SHM_PROTECT();
2788
222k
  HANDLE_UNBLOCK_INTERRUPTIONS();
2789
2790
222k
  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
222k
  } 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
222k
#ifdef HAVE_JIT
2806
222k
  zend_jit_activate();
2807
222k
#endif
2808
2809
222k
#ifdef PRELOAD_SUPPORT
2810
222k
  if (ZCSG(preload_script)) {
2811
0
    preload_activate();
2812
0
  }
2813
222k
#endif
2814
2815
222k
  return SUCCESS;
2816
222k
}
2817
2818
#ifdef HAVE_JIT
2819
void accel_deactivate(void)
2820
222k
{
2821
222k
  zend_jit_deactivate();
2822
222k
}
2823
#endif
2824
2825
zend_result accel_post_deactivate(void)
2826
222k
{
2827
222k
  if (ZCG(cwd)) {
2828
49.7k
    zend_string_release_ex(ZCG(cwd), 0);
2829
49.7k
    ZCG(cwd) = NULL;
2830
49.7k
  }
2831
2832
222k
  if (!ZCG(enabled) || !accel_startup_ok) {
2833
0
    return SUCCESS;
2834
0
  }
2835
2836
222k
  zend_shared_alloc_safe_unlock(); /* be sure we didn't leave cache locked */
2837
222k
  accel_unlock_all();
2838
222k
  ZCG(counted) = false;
2839
2840
222k
  return SUCCESS;
2841
222k
}
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
14
{
2878
14
  return strcmp(sapi_module.name, "cli") == 0
2879
14
    || strcmp(sapi_module.name, "phpdbg") == 0;
2880
14
}
2881
2882
static zend_result zend_accel_init_shm(void)
2883
14
{
2884
14
  int i;
2885
14
  size_t accel_shared_globals_size;
2886
2887
14
  zend_shared_alloc_lock();
2888
2889
14
  if (ZCG(accel_directives).interned_strings_buffer) {
2890
14
    accel_shared_globals_size = sizeof(zend_accel_shared_globals) + ZCG(accel_directives).interned_strings_buffer * 1024 * 1024;
2891
14
  } 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
14
  accel_shared_globals = zend_shared_alloc(accel_shared_globals_size);
2898
14
  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
14
  memset(accel_shared_globals, 0, sizeof(zend_accel_shared_globals));
2906
14
  ZSMMG(app_shared_globals) = accel_shared_globals;
2907
2908
14
  zend_accel_hash_init(&ZCSG(hash), ZCG(accel_directives).max_accelerated_files);
2909
2910
14
  if (ZCG(accel_directives).interned_strings_buffer) {
2911
14
    uint32_t hash_size;
2912
2913
    /* must be a power of two */
2914
14
    hash_size = ZCG(accel_directives).interned_strings_buffer * (32 * 1024);
2915
14
    hash_size |= (hash_size >> 1);
2916
14
    hash_size |= (hash_size >> 2);
2917
14
    hash_size |= (hash_size >> 4);
2918
14
    hash_size |= (hash_size >> 8);
2919
14
    hash_size |= (hash_size >> 16);
2920
2921
14
    ZCSG(interned_strings).nTableMask =
2922
14
      hash_size * sizeof(zend_string_table_pos_t);
2923
14
    ZCSG(interned_strings).nNumOfElements = 0;
2924
14
    ZCSG(interned_strings).start =
2925
14
      (zend_string*)((char*)&ZCSG(interned_strings) +
2926
14
        sizeof(zend_string_table) +
2927
14
        ((hash_size + 1) * sizeof(zend_string_table_pos_t))) +
2928
14
        8;
2929
14
    ZEND_ASSERT(((uintptr_t)ZCSG(interned_strings).start & 0x7) == 0); /* should be 8 byte aligned */
2930
2931
14
    ZCSG(interned_strings).top =
2932
14
      ZCSG(interned_strings).start;
2933
14
    ZCSG(interned_strings).end =
2934
14
      (zend_string*)((char*)(accel_shared_globals + 1) + /* table data is stored after accel_shared_globals */
2935
14
        ZCG(accel_directives).interned_strings_buffer * 1024 * 1024);
2936
14
    ZEND_ASSERT(((uintptr_t)ZCSG(interned_strings).end - (uintptr_t)&ZCSG(interned_strings)) / ZEND_STRING_TABLE_POS_ALIGNMENT < ZEND_STRING_TABLE_POS_MAX);
2937
14
    ZCSG(interned_strings).saved_top = NULL;
2938
2939
14
    memset((char*)&ZCSG(interned_strings) + sizeof(zend_string_table),
2940
14
      STRTAB_INVALID_POS,
2941
14
      (char*)ZCSG(interned_strings).start -
2942
14
        ((char*)&ZCSG(interned_strings) + sizeof(zend_string_table)));
2943
14
  } 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
14
  zend_interned_strings_set_request_storage_handlers(
2950
14
    accel_new_interned_string_for_php,
2951
14
    accel_init_interned_string_for_php,
2952
14
    accel_init_interned_string_for_php);
2953
2954
14
  zend_reset_cache_vars();
2955
2956
14
  ZCSG(oom_restarts) = 0;
2957
14
  ZCSG(hash_restarts) = 0;
2958
14
  ZCSG(manual_restarts) = 0;
2959
2960
14
  ZCSG(accelerator_enabled) = true;
2961
14
  ZCSG(start_time) = zend_accel_get_time();
2962
14
  ZCSG(last_restart_time) = 0;
2963
14
  ZCSG(restart_in_progress) = false;
2964
2965
42
  for (i = 0; i < -HT_MIN_MASK; i++) {
2966
28
    ZCSG(uninitialized_bucket)[i] = HT_INVALID_IDX;
2967
28
  }
2968
2969
14
  zend_shared_alloc_unlock();
2970
2971
14
  return SUCCESS;
2972
14
}
2973
2974
static void accel_globals_ctor(zend_accel_globals *accel_globals)
2975
14
{
2976
14
  memset(accel_globals, 0, sizeof(zend_accel_globals));
2977
14
  accel_globals->key = zend_string_alloc(ZCG_KEY_LEN, true);
2978
14
  GC_MAKE_PERSISTENT_LOCAL(accel_globals->key);
2979
14
}
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
14
{
3193
14
  zend_register_extension(&opcache_extension_entry, NULL);
3194
14
}
3195
3196
static int accel_startup(zend_extension *extension)
3197
14
{
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
14
  accel_globals_ctor(&accel_globals);
3202
14
#endif
3203
3204
14
#ifdef HAVE_JIT
3205
14
  zend_jit_init();
3206
14
#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
14
  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
14
#ifdef HAVE_HUGE_CODE_PAGES
3224
14
  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
14
#endif
3232
3233
14
  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
14
  if (ZCG(enabled) == 0) {
3240
0
    return SUCCESS ;
3241
0
  }
3242
3243
14
  orig_post_startup_cb = zend_post_startup_cb;
3244
14
  zend_post_startup_cb = accel_post_startup;
3245
3246
  /* Prevent unloading */
3247
14
  extension->handle = 0;
3248
3249
14
  return SUCCESS;
3250
14
}
3251
3252
static zend_result accel_post_startup(void)
3253
14
{
3254
14
  zend_function *func;
3255
14
  zend_ini_entry *ini_entry;
3256
3257
14
  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
14
  file_cache_only = ZCG(accel_directives).file_cache_only;
3270
14
  if (!file_cache_only) {
3271
14
    size_t shm_size = ZCG(accel_directives).memory_consumption;
3272
14
#ifdef HAVE_JIT
3273
14
    size_t jit_size = 0;
3274
14
    bool reattached = false;
3275
3276
14
    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
14
    switch (zend_shared_alloc_startup(shm_size, jit_size)) {
3291
#else
3292
    switch (zend_shared_alloc_startup(shm_size, 0)) {
3293
#endif
3294
14
      case ALLOC_SUCCESS:
3295
14
        if (zend_accel_init_shm() == FAILURE) {
3296
0
          accel_startup_ok = false;
3297
0
          return FAILURE;
3298
0
        }
3299
14
        break;
3300
14
      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
14
    }
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
14
    ZCG(last_restart_time) = ZCSG(last_restart_time);
3342
3343
14
    zend_shared_alloc_lock();
3344
14
#ifdef HAVE_JIT
3345
14
    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
14
#endif
3357
14
    zend_shared_alloc_save_state();
3358
14
    zend_shared_alloc_unlock();
3359
3360
14
    SHM_PROTECT();
3361
14
  } 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
14
  int file_cache_access_mode = 0;
3375
3376
14
  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
14
  } else {
3392
    /* opcache.file_cache isn't read only, so ensure the directory is writable */
3393
14
#ifndef ZEND_WIN32
3394
14
    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
14
  }
3399
3400
14
  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
14
  accelerator_orig_compile_file = zend_compile_file;
3426
14
  zend_compile_file = persistent_compile_file;
3427
3428
  /* Override stream opener function (to eliminate open() call caused by
3429
   * include/require statements ) */
3430
14
  accelerator_orig_zend_stream_open_function = zend_stream_open_function;
3431
14
  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
14
  accelerator_orig_zend_resolve_path = zend_resolve_path;
3436
14
  zend_resolve_path = persistent_zend_resolve_path;
3437
3438
  /* Override chdir() function */
3439
14
  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
14
  ZCG(cwd) = NULL;
3445
14
  ZCG(include_path) = NULL;
3446
3447
  /* Override "include_path" modifier callback */
3448
14
  if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
3449
14
    ZCG(include_path) = ini_entry->value;
3450
14
    orig_include_path_on_modify = ini_entry->on_modify;
3451
14
    ini_entry->on_modify = accel_include_path_on_modify;
3452
14
  }
3453
3454
14
  accel_startup_ok = true;
3455
3456
  /* Override file_exists(), is_file() and is_readable() */
3457
14
  zend_accel_override_file_functions();
3458
3459
  /* Load black list */
3460
14
  accel_blacklist.entries = NULL;
3461
14
  if (ZCG(enabled) && accel_startup_ok &&
3462
14
      ZCG(accel_directives).user_blacklist_filename &&
3463
14
      *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
14
  if (!file_cache_only && ZCG(accel_directives).interned_strings_buffer) {
3469
14
    accel_use_shm_interned_strings();
3470
14
  }
3471
3472
14
  if (accel_finish_startup() != SUCCESS) {
3473
0
    return FAILURE;
3474
0
  }
3475
3476
14
  if (ZCG(enabled) && accel_startup_ok) {
3477
    /* Override inheritance cache callbaks */
3478
14
    accelerator_orig_inheritance_cache_get = zend_inheritance_cache_get;
3479
14
    accelerator_orig_inheritance_cache_add = zend_inheritance_cache_add;
3480
14
    zend_inheritance_cache_get = zend_accel_inheritance_cache_get;
3481
14
    zend_inheritance_cache_add = zend_accel_inheritance_cache_add;
3482
14
  }
3483
3484
14
  return SUCCESS;
3485
14
}
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
13.2k
{
3601
13.2k
  if (ZCG(counted)) {
3602
    /* counted means we are holding read lock for SHM, so that nothing bad can happen */
3603
13.2k
    return SUCCESS;
3604
13.2k
  } 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
13.2k
}
3620
3621
/* must be called ONLY after SUCCESSFUL accelerator_shm_read_lock */
3622
void accelerator_shm_read_unlock(void)
3623
13.2k
{
3624
13.2k
  if (!ZCG(counted)) {
3625
    /* counted is false - meaning we had to readlock manually, release readlock now */
3626
0
    accel_deactivate_now();
3627
0
  }
3628
13.2k
}
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
      zend_exception_restore();
4667
0
      if (UNEXPECTED(EG(exception))) {
4668
0
        if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
4669
0
          zend_user_exception_handler();
4670
0
        }
4671
0
        if (EG(exception)) {
4672
0
          ret = zend_exception_error(EG(exception), E_ERROR);
4673
0
          if (ret == FAILURE) {
4674
0
            CG(unclean_shutdown) = true;
4675
0
          }
4676
0
        }
4677
0
      }
4678
0
      destroy_op_array(op_array);
4679
0
      efree_size(op_array, sizeof(zend_op_array));
4680
0
    } else {
4681
0
      if (EG(exception)) {
4682
0
        zend_exception_error(EG(exception), E_ERROR);
4683
0
      }
4684
4685
0
      CG(unclean_shutdown) = true;
4686
0
      ret = FAILURE;
4687
0
    }
4688
0
  } zend_catch {
4689
0
    ret = FAILURE;
4690
0
  } zend_end_try();
4691
4692
0
  PG(open_basedir) = orig_open_basedir;
4693
0
  accelerator_orig_compile_file = preload_orig_compile_file;
4694
0
  ZCG(enabled) = true;
4695
4696
0
  zend_destroy_file_handle(&file_handle);
4697
4698
0
  if (ret == SUCCESS) {
4699
0
    zend_persistent_script *script;
4700
0
    int ping_auto_globals_mask;
4701
0
    int i;
4702
4703
0
    if (PG(auto_globals_jit)) {
4704
0
      ping_auto_globals_mask = zend_accel_get_auto_globals();
4705
0
    } else {
4706
0
      ping_auto_globals_mask = 0;
4707
0
    }
4708
4709
0
    if (EG(zend_constants)) {
4710
      /* Remember __COMPILER_HALT_OFFSET__(s). Do this early,
4711
       * as zend_shutdown_executor_values() destroys constants. */
4712
0
      ZEND_HASH_MAP_FOREACH_PTR(preload_scripts, script) {
4713
0
        zend_execute_data *orig_execute_data = EG(current_execute_data);
4714
0
        zend_execute_data fake_execute_data;
4715
0
        zval *offset;
4716
4717
0
        memset(&fake_execute_data, 0, sizeof(fake_execute_data));
4718
0
        fake_execute_data.func = (zend_function*)&script->script.main_op_array;
4719
0
        EG(current_execute_data) = &fake_execute_data;
4720
0
        if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
4721
0
          script->compiler_halt_offset = Z_LVAL_P(offset);
4722
0
        }
4723
0
        EG(current_execute_data) = orig_execute_data;
4724
0
      } ZEND_HASH_FOREACH_END();
4725
0
    }
4726
4727
    /* Cleanup executor */
4728
0
    EG(flags) |= EG_FLAGS_IN_SHUTDOWN;
4729
4730
0
    php_call_shutdown_functions();
4731
0
    zend_call_destructors();
4732
0
    php_output_end_all();
4733
0
    php_free_shutdown_functions();
4734
4735
    /* Release stored values to avoid dangling pointers */
4736
0
    zend_shutdown_executor_values(/* fast_shutdown */ false);
4737
4738
    /* On ZTS we execute `executor_globals_ctor` which reset the freelist and p5s pointers, while on NTS we don't.
4739
     * We have to clean up the memory before the actual request takes place to avoid a memory leak. */
4740
#ifdef ZTS
4741
    zend_shutdown_strtod();
4742
#endif
4743
4744
    /* We don't want to preload constants.
4745
     * Check that  zend_shutdown_executor_values() also destroys constants. */
4746
0
    ZEND_ASSERT(zend_hash_num_elements(EG(zend_constants)) == EG(persistent_constants_count));
4747
4748
0
    zend_hash_init(&EG(symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0);
4749
4750
0
    CG(map_ptr_last) = orig_map_ptr_last;
4751
4752
0
    if (EG(full_tables_cleanup)) {
4753
0
      zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading is not compatible with dl() function.");
4754
0
      ret = FAILURE;
4755
0
      goto finish;
4756
0
    }
4757
4758
    /* Inheritance errors may be thrown during linking */
4759
0
    zend_try {
4760
0
      preload_link();
4761
0
    } zend_catch {
4762
0
      CG(map_ptr_last) = orig_map_ptr_last;
4763
0
      ret = FAILURE;
4764
0
      goto finish;
4765
0
    } zend_end_try();
4766
4767
0
    preload_remove_empty_includes();
4768
4769
0
    script = create_persistent_script();
4770
0
    script->ping_auto_globals_mask = ping_auto_globals_mask;
4771
4772
    /* Store all functions and classes in a single pseudo-file */
4773
0
    CG(compiled_filename) = ZSTR_INIT_LITERAL("$PRELOAD$", 0);
4774
#if ZEND_USE_ABS_CONST_ADDR
4775
    init_op_array(&script->script.main_op_array, ZEND_USER_FUNCTION, 1);
4776
#else
4777
0
    init_op_array(&script->script.main_op_array, ZEND_USER_FUNCTION, 2);
4778
0
#endif
4779
0
    script->script.main_op_array.fn_flags |= ZEND_ACC_DONE_PASS_TWO;
4780
0
    script->script.main_op_array.last = 1;
4781
0
    script->script.main_op_array.last_literal = 1;
4782
0
    script->script.main_op_array.T = ZEND_OBSERVER_ENABLED;
4783
#if ZEND_USE_ABS_CONST_ADDR
4784
    script->script.main_op_array.literals = (zval*)emalloc(sizeof(zval));
4785
#else
4786
0
    script->script.main_op_array.literals = (zval*)(script->script.main_op_array.opcodes + 1);
4787
0
#endif
4788
0
    ZVAL_NULL(script->script.main_op_array.literals);
4789
0
    memset(script->script.main_op_array.opcodes, 0, sizeof(zend_op));
4790
0
    script->script.main_op_array.opcodes[0].opcode = ZEND_RETURN;
4791
0
    script->script.main_op_array.opcodes[0].op1_type = IS_CONST;
4792
0
    script->script.main_op_array.opcodes[0].op1.constant = 0;
4793
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);
4794
0
    zend_vm_set_opcode_handler(script->script.main_op_array.opcodes);
4795
4796
0
    script->script.filename = CG(compiled_filename);
4797
0
    CG(compiled_filename) = NULL;
4798
4799
0
    preload_move_user_functions(CG(function_table), &script->script.function_table);
4800
0
    preload_move_user_classes(CG(class_table), &script->script.class_table);
4801
4802
0
    zend_hash_sort_ex(&script->script.class_table, preload_sort_classes, NULL, 0);
4803
4804
0
    preload_optimize(script);
4805
4806
0
    zend_shared_alloc_init_xlat_table();
4807
4808
0
    HANDLE_BLOCK_INTERRUPTIONS();
4809
0
    SHM_UNPROTECT();
4810
4811
0
    ZCSG(preload_script) = preload_script_in_shared_memory(script);
4812
4813
0
    SHM_PROTECT();
4814
0
    HANDLE_UNBLOCK_INTERRUPTIONS();
4815
4816
0
    preload_load(orig_map_ptr_static_last);
4817
4818
    /* Update persistent counts, as shutdown will discard anything past
4819
     * that, and these tables are aliases to global ones at this point. */
4820
0
    EG(persistent_functions_count) = EG(function_table)->nNumUsed;
4821
0
    EG(persistent_classes_count)   = EG(class_table)->nNumUsed;
4822
0
    EG(persistent_constants_count) = EG(zend_constants)->nNumUsed;
4823
4824
    /* Store individual scripts with unlinked classes */
4825
0
    HANDLE_BLOCK_INTERRUPTIONS();
4826
0
    SHM_UNPROTECT();
4827
4828
0
    i = 0;
4829
0
    ZCSG(saved_scripts) = zend_shared_alloc((zend_hash_num_elements(preload_scripts) + 1) * sizeof(void*));
4830
0
    ZEND_HASH_MAP_FOREACH_PTR(preload_scripts, script) {
4831
0
      if (zend_hash_num_elements(&script->script.class_table) > 1) {
4832
0
        zend_hash_sort_ex(&script->script.class_table, preload_sort_classes, NULL, 0);
4833
0
      }
4834
0
      ZCSG(saved_scripts)[i++] = preload_script_in_shared_memory(script);
4835
0
    } ZEND_HASH_FOREACH_END();
4836
0
    ZCSG(saved_scripts)[i] = NULL;
4837
4838
0
#if HAVE_JIT
4839
    /* During persisting, the JIT may trigger and fill in the call graph.
4840
     * The call graph info is allocated on the arena which will be gone after preloading.
4841
     * To prevent invalid accesses during normal requests, the arena data should be cleared.
4842
     * This has to be done after all scripts have been persisted because shared op arrays between
4843
     * scripts can change the call graph. */
4844
0
    accel_reset_arena_info(ZCSG(preload_script));
4845
0
    for (zend_persistent_script **scripts = ZCSG(saved_scripts); *scripts; scripts++) {
4846
0
      accel_reset_arena_info(*scripts);
4847
0
    }
4848
0
#endif
4849
4850
0
    zend_shared_alloc_save_state();
4851
0
    accel_interned_strings_save_state();
4852
4853
0
    SHM_PROTECT();
4854
0
    HANDLE_UNBLOCK_INTERRUPTIONS();
4855
4856
0
    zend_shared_alloc_destroy_xlat_table();
4857
0
  } else {
4858
0
    CG(map_ptr_last) = orig_map_ptr_last;
4859
0
  }
4860
4861
0
finish:
4862
0
  CG(compiler_options) = orig_compiler_options;
4863
0
  zend_hash_destroy(preload_scripts);
4864
0
  efree(preload_scripts);
4865
0
  preload_scripts = NULL;
4866
4867
0
  return ret;
4868
0
}
4869
4870
static size_t preload_ub_write(const char *str, size_t str_length)
4871
0
{
4872
0
  return fwrite(str, 1, str_length, stdout);
4873
0
}
4874
4875
static void preload_flush(void *server_context)
4876
0
{
4877
0
  fflush(stdout);
4878
0
}
4879
4880
static int preload_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s)
4881
0
{
4882
0
  return 0;
4883
0
}
4884
4885
static int preload_send_headers(sapi_headers_struct *sapi_headers)
4886
0
{
4887
0
  return SAPI_HEADER_SENT_SUCCESSFULLY;
4888
0
}
4889
4890
static void preload_send_header(sapi_header_struct *sapi_header, void *server_context)
4891
0
{
4892
0
}
4893
4894
static zend_result accel_finish_startup_preload(bool in_child)
4895
0
{
4896
0
  zend_result ret = SUCCESS;
4897
0
  int orig_error_reporting;
4898
4899
0
  int (*orig_activate)(void) = sapi_module.activate;
4900
0
  int (*orig_deactivate)(void) = sapi_module.deactivate;
4901
0
  void (*orig_register_server_variables)(zval *track_vars_array) = sapi_module.register_server_variables;
4902
0
  int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers) = sapi_module.header_handler;
4903
0
  int (*orig_send_headers)(sapi_headers_struct *sapi_headers) = sapi_module.send_headers;
4904
0
  void (*orig_send_header)(sapi_header_struct *sapi_header, void *server_context)= sapi_module.send_header;
4905
0
  char *(*orig_getenv)(const char *name, size_t name_len) = sapi_module.getenv;
4906
0
  size_t (*orig_ub_write)(const char *str, size_t str_length) = sapi_module.ub_write;
4907
0
  void (*orig_flush)(void *server_context) = sapi_module.flush;
4908
0
#ifdef ZEND_SIGNALS
4909
0
  bool old_reset_signals = SIGG(reset);
4910
0
#endif
4911
4912
0
  ZCG(preloading) = true;
4913
4914
0
  sapi_module.activate = NULL;
4915
0
  sapi_module.deactivate = NULL;
4916
0
  sapi_module.register_server_variables = NULL;
4917
0
  sapi_module.header_handler = preload_header_handler;
4918
0
  sapi_module.send_headers = preload_send_headers;
4919
0
  sapi_module.send_header = preload_send_header;
4920
0
  sapi_module.getenv = NULL;
4921
0
  sapi_module.ub_write = preload_ub_write;
4922
0
  sapi_module.flush = preload_flush;
4923
4924
0
  zend_interned_strings_switch_storage(1);
4925
4926
0
#ifdef ZEND_SIGNALS
4927
0
  SIGG(reset) = false;
4928
0
#endif
4929
4930
0
  orig_error_reporting = EG(error_reporting);
4931
0
  EG(error_reporting) = 0;
4932
4933
0
  const zend_result rc = php_request_startup();
4934
4935
0
  EG(error_reporting) = orig_error_reporting;
4936
4937
0
  if (rc == SUCCESS) {
4938
0
    bool orig_report_memleaks;
4939
4940
    /* don't send headers */
4941
0
    SG(headers_sent) = true;
4942
0
    SG(request_info).no_headers = true;
4943
0
    php_output_set_status(0);
4944
4945
0
    ZCG(auto_globals_mask) = 0;
4946
0
    ZCG(request_time) = (time_t)sapi_get_request_time();
4947
0
    ZCG(cache_opline) = NULL;
4948
0
    ZCG(cache_persistent_script) = NULL;
4949
0
    ZCG(include_path_key_len) = 0;
4950
0
    ZCG(include_path_check) = true;
4951
4952
0
    ZCG(cwd) = NULL;
4953
0
    ZCG(cwd_key_len) = 0;
4954
0
    ZCG(cwd_check) = true;
4955
4956
0
    if (accel_preload(ZCG(accel_directives).preload, in_child) != SUCCESS) {
4957
0
      ret = FAILURE;
4958
0
    }
4959
0
    preload_flush(NULL);
4960
4961
0
    orig_report_memleaks = PG(report_memleaks);
4962
0
    PG(report_memleaks) = false;
4963
0
#ifdef ZEND_SIGNALS
4964
    /* We may not have registered signal handlers due to SIGG(reset)=0, so
4965
     * also disable the check that they are registered. */
4966
0
    SIGG(check) = false;
4967
0
#endif
4968
0
    php_request_shutdown(NULL); /* calls zend_shared_alloc_unlock(); */
4969
0
    EG(class_table) = NULL;
4970
0
    EG(function_table) = NULL;
4971
0
    PG(report_memleaks) = orig_report_memleaks;
4972
#ifdef ZTS
4973
    /* Reset the virtual CWD state back to the original state created by virtual_cwd_startup().
4974
     * This is necessary because the normal startup code assumes the CWD state is active. */
4975
    virtual_cwd_activate();
4976
#endif
4977
0
  } else {
4978
0
    zend_shared_alloc_unlock();
4979
0
    ret = FAILURE;
4980
0
  }
4981
0
#ifdef ZEND_SIGNALS
4982
0
  SIGG(reset) = old_reset_signals;
4983
0
#endif
4984
4985
0
  sapi_module.activate = orig_activate;
4986
0
  sapi_module.deactivate = orig_deactivate;
4987
0
  sapi_module.register_server_variables = orig_register_server_variables;
4988
0
  sapi_module.header_handler = orig_header_handler;
4989
0
  sapi_module.send_headers = orig_send_headers;
4990
0
  sapi_module.send_header = orig_send_header;
4991
0
  sapi_module.getenv = orig_getenv;
4992
0
  sapi_module.ub_write = orig_ub_write;
4993
0
  sapi_module.flush = orig_flush;
4994
4995
0
  ZCG(preloading) = false;
4996
4997
0
  sapi_activate();
4998
4999
0
  return ret;
5000
0
}
5001
5002
static zend_result accel_finish_startup_preload_subprocess(pid_t *pid)
5003
0
{
5004
0
  uid_t euid = geteuid();
5005
0
  if (euid != 0) {
5006
0
    if (ZCG(accel_directives).preload_user
5007
0
     && *ZCG(accel_directives).preload_user) {
5008
0
      zend_accel_error(ACCEL_LOG_WARNING, "\"opcache.preload_user\" is ignored because the current user is not \"root\"");
5009
0
    }
5010
5011
0
    *pid = -1;
5012
0
    return SUCCESS;
5013
0
  }
5014
5015
0
  if (!ZCG(accel_directives).preload_user
5016
0
   || !*ZCG(accel_directives).preload_user) {
5017
5018
0
    bool sapi_requires_preload_user = !(strcmp(sapi_module.name, "cli") == 0
5019
0
      || strcmp(sapi_module.name, "phpdbg") == 0);
5020
5021
0
    if (!sapi_requires_preload_user) {
5022
0
      *pid = -1;
5023
0
      return SUCCESS;
5024
0
    }
5025
5026
0
    zend_shared_alloc_unlock();
5027
0
    zend_accel_error_noreturn(ACCEL_LOG_FATAL, "\"opcache.preload\" requires \"opcache.preload_user\" when running under uid 0");
5028
0
    return FAILURE;
5029
0
  }
5030
5031
0
  struct passwd *pw = getpwnam(ZCG(accel_directives).preload_user);
5032
0
  if (pw == NULL) {
5033
0
    zend_shared_alloc_unlock();
5034
0
    zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to getpwnam(\"%s\")", ZCG(accel_directives).preload_user);
5035
0
    return FAILURE;
5036
0
  }
5037
5038
0
  if (pw->pw_uid == euid) {
5039
0
    *pid = -1;
5040
0
    return SUCCESS;
5041
0
  }
5042
5043
0
  *pid = fork();
5044
0
  if (*pid == -1) {
5045
0
    zend_shared_alloc_unlock();
5046
0
    zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to fork()");
5047
0
    return FAILURE;
5048
0
  }
5049
5050
0
  if (*pid == 0) { /* children */
5051
0
    if (setgid(pw->pw_gid) < 0) {
5052
0
      zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setgid(%d)", pw->pw_gid);
5053
0
      exit(1);
5054
0
    }
5055
0
    if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
5056
0
      zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to initgroups(\"%s\", %d)", pw->pw_name, pw->pw_uid);
5057
0
      exit(1);
5058
0
    }
5059
0
    if (setuid(pw->pw_uid) < 0) {
5060
0
      zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid);
5061
0
      exit(1);
5062
0
    }
5063
0
    php_child_init();
5064
0
  }
5065
5066
0
  return SUCCESS;
5067
0
}
5068
#endif /* ZEND_WIN32 */
5069
5070
static zend_result accel_finish_startup(void)
5071
14
{
5072
14
  if (!ZCG(enabled) || !accel_startup_ok) {
5073
0
    return SUCCESS;
5074
0
  }
5075
5076
14
  if (!(ZCG(accel_directives).preload && *ZCG(accel_directives).preload)) {
5077
14
    return SUCCESS;
5078
14
  }
5079
5080
#ifdef ZEND_WIN32
5081
  zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Preloading is not supported on Windows");
5082
  return FAILURE;
5083
#else /* ZEND_WIN32 */
5084
5085
0
  if (UNEXPECTED(file_cache_only)) {
5086
0
    zend_accel_error(ACCEL_LOG_WARNING, "Preloading doesn't work in \"file_cache_only\" mode");
5087
0
    return SUCCESS;
5088
0
  }
5089
5090
  /* exclusive lock */
5091
0
  zend_shared_alloc_lock();
5092
5093
0
  if (ZCSG(preload_script)) {
5094
    /* Preloading was done in another process */
5095
0
    preload_load(zend_map_ptr_static_last);
5096
0
    zend_shared_alloc_unlock();
5097
0
    return SUCCESS;
5098
0
  }
5099
5100
5101
0
  pid_t pid;
5102
0
  if (accel_finish_startup_preload_subprocess(&pid) == FAILURE) {
5103
0
    zend_shared_alloc_unlock();
5104
0
    return FAILURE;
5105
0
  }
5106
5107
0
  if (pid == -1) { /* no subprocess was needed */
5108
    /* The called function unlocks the shared alloc lock */
5109
0
    return accel_finish_startup_preload(false);
5110
0
  } else if (pid == 0) { /* subprocess */
5111
0
    const zend_result ret = accel_finish_startup_preload(true);
5112
5113
0
    exit(ret == SUCCESS ? 0 : 1);
5114
0
  } else { /* parent */
5115
0
# ifdef HAVE_SIGPROCMASK
5116
    /* Interrupting the waitpid() call below with a signal would cause the
5117
     * process to exit. This is fine when the signal disposition is set to
5118
     * terminate the process, but not otherwise.
5119
     * When running the apache2handler, preloading is performed in the
5120
     * control process. SIGUSR1 and SIGHUP are used to tell the control
5121
     * process to restart children. Exiting when these signals are received
5122
     * would unexpectedly shutdown the server instead of restarting it.
5123
     * Block the USR1 and HUP signals from being delivered during the
5124
     * syscall when running the apache2handler SAPI, as these are not
5125
     * supposed to terminate the process. See GH-20051. */
5126
0
    bool is_apache2handler = strcmp(sapi_module.name, "apache2handler") == 0;
5127
0
    sigset_t set, oldset;
5128
0
    if (is_apache2handler) {
5129
0
      if (sigemptyset(&set)
5130
0
          || sigaddset(&set, SIGUSR1)
5131
0
          || sigaddset(&set, SIGHUP)) {
5132
0
        ZEND_UNREACHABLE();
5133
0
      }
5134
0
      if (sigprocmask(SIG_BLOCK, &set, &oldset)) {
5135
0
        ZEND_UNREACHABLE();
5136
0
      }
5137
0
    }
5138
0
# endif
5139
5140
0
    int status;
5141
0
    if (waitpid(pid, &status, 0) < 0) {
5142
0
      zend_shared_alloc_unlock();
5143
0
      zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
5144
0
    }
5145
5146
0
# ifdef HAVE_SIGPROCMASK
5147
0
    if (is_apache2handler) {
5148
0
      if (sigprocmask(SIG_SETMASK, &oldset, NULL)) {
5149
0
        ZEND_UNREACHABLE();
5150
0
      }
5151
0
    }
5152
0
# endif
5153
5154
0
    if (ZCSG(preload_script)) {
5155
0
      preload_load(zend_map_ptr_static_last);
5156
0
    }
5157
5158
0
    zend_shared_alloc_unlock();
5159
5160
0
    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
5161
0
      return SUCCESS;
5162
0
    } else {
5163
0
      return FAILURE;
5164
0
    }
5165
0
  }
5166
0
#endif /* ZEND_WIN32 */
5167
0
}
5168
5169
222k
static void accel_activate(void) {
5170
222k
  if (ZCG(preloaded_internal_run_time_cache)) {
5171
0
    memset(ZCG(preloaded_internal_run_time_cache), 0, ZCG(preloaded_internal_run_time_cache_size));
5172
0
  }
5173
222k
}
5174
5175
static zend_extension opcache_extension_entry = {
5176
  ACCELERATOR_PRODUCT_NAME,               /* name */
5177
  PHP_VERSION,              /* version */
5178
  "Zend Technologies",          /* author */
5179
  "http://www.zend.com/",         /* URL */
5180
  "Copyright (c)",            /* copyright */
5181
  accel_startup,                /* startup */
5182
  NULL,                 /* shutdown */
5183
  accel_activate,             /* per-script activation */
5184
#ifdef HAVE_JIT
5185
  accel_deactivate,                       /* per-script deactivation */
5186
#else
5187
  NULL,                 /* per-script deactivation */
5188
#endif
5189
  NULL,                 /* message handler */
5190
  NULL,                 /* op_array handler */
5191
  NULL,                 /* extended statement handler */
5192
  NULL,                 /* extended fcall begin handler */
5193
  NULL,                 /* extended fcall end handler */
5194
  NULL,                 /* op_array ctor */
5195
  NULL,                 /* op_array dtor */
5196
  STANDARD_ZEND_EXTENSION_PROPERTIES
5197
};