Coverage Report

Created: 2025-11-16 06:23

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