Coverage Report

Created: 2026-09-14 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/opcache/zend_file_cache.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend OPcache                                                         |
4
   +----------------------------------------------------------------------+
5
   | Copyright © The PHP Group and Contributors.                          |
6
   +----------------------------------------------------------------------+
7
   | This source file is subject to the Modified BSD License that is      |
8
   | bundled with this package in the file LICENSE, and is available      |
9
   | through the World Wide Web at <https://www.php.net/license/>.        |
10
   |                                                                      |
11
   | SPDX-License-Identifier: BSD-3-Clause                                |
12
   +----------------------------------------------------------------------+
13
   | Authors: Dmitry Stogov <dmitry@php.net>                              |
14
   +----------------------------------------------------------------------+
15
*/
16
17
#include "zend.h"
18
#include "zend_virtual_cwd.h"
19
#include "zend_compile.h"
20
#include "zend_vm.h"
21
#include "zend_interfaces.h"
22
#include "zend_attributes.h"
23
#include "zend_system_id.h"
24
#include "zend_enum.h"
25
#include "zend_partial.h"
26
27
#include "php.h"
28
#ifdef ZEND_WIN32
29
#include "ext/standard/md5.h"
30
#endif
31
#include "ext/standard/php_filestat.h"
32
33
#include "ZendAccelerator.h"
34
#include "zend_file_cache.h"
35
#include "zend_shared_alloc.h"
36
#include "zend_accelerator_util_funcs.h"
37
#include "zend_accelerator_hash.h"
38
39
#ifdef HAVE_JIT
40
#include "jit/zend_jit.h"
41
#endif
42
43
#include <sys/types.h>
44
#include <sys/stat.h>
45
#include <fcntl.h>
46
47
#ifdef HAVE_UNISTD_H
48
#include <unistd.h>
49
#endif
50
51
#ifdef HAVE_SYS_UIO_H
52
# include <sys/uio.h>
53
#endif
54
55
#ifdef HAVE_SYS_FILE_H
56
# include <sys/file.h>
57
#endif
58
59
#if __has_feature(memory_sanitizer)
60
# include <sanitizer/msan_interface.h>
61
#endif
62
63
#ifndef ZEND_WIN32
64
0
#define zend_file_cache_unlink unlink
65
0
#define zend_file_cache_open open
66
#else
67
#define zend_file_cache_unlink php_win32_ioutil_unlink
68
#define zend_file_cache_open php_win32_ioutil_open
69
#endif
70
71
#ifdef ZEND_WIN32
72
# define LOCK_SH 0
73
# define LOCK_EX 1
74
# define LOCK_UN 2
75
static int zend_file_cache_flock(int fd, int op)
76
{
77
  OVERLAPPED offset = {0, 0, {{0}}, NULL};
78
  if (op == LOCK_EX) {
79
    if (LockFileEx((HANDLE)_get_osfhandle(fd),
80
                   LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &offset) == TRUE) {
81
      return 0;
82
    }
83
  } else if (op == LOCK_SH) {
84
    if (LockFileEx((HANDLE)_get_osfhandle(fd),
85
                   0, 0, 1, 0, &offset) == TRUE) {
86
      return 0;
87
    }
88
  } else if (op == LOCK_UN) {
89
    if (UnlockFileEx((HANDLE)_get_osfhandle(fd),
90
                     0, 1, 0, &offset) == TRUE) {
91
      return 0;
92
    }
93
  }
94
  return -1;
95
}
96
#elif defined(HAVE_FLOCK)
97
0
# define zend_file_cache_flock flock
98
#else
99
# define LOCK_SH 0
100
# define LOCK_EX 1
101
# define LOCK_UN 2
102
static int zend_file_cache_flock(int fd, int type)
103
{
104
  return 0;
105
}
106
#endif
107
108
#ifndef O_BINARY
109
0
#  define O_BINARY 0
110
#endif
111
112
0
#define SUFFIX ".bin"
113
114
#define IS_SERIALIZED_INTERNED(ptr) \
115
0
  ((size_t)(ptr) & Z_UL(1))
116
117
/* Allowing == on the upper bound accounts for a potential empty allocation at the end of the
118
 * memory region. This can also happen for a return-type-only arg_info, where &arg_info[1] is
119
 * stored, which may point to the end of the region. */
120
#define IS_SERIALIZED(ptr) \
121
0
  ((char*)(ptr) <= (char*)script->size)
122
#define IS_UNSERIALIZED(ptr) \
123
0
  (((char*)(ptr) >= (char*)script->mem && (char*)(ptr) <= (char*)script->mem + script->size) || \
124
0
   IS_ACCEL_INTERNED(ptr))
125
0
#define SERIALIZE_PTR(ptr) do { \
126
0
    if (ptr) { \
127
0
      ZEND_ASSERT(IS_UNSERIALIZED(ptr)); \
128
0
      (ptr) = (void*)((char*)(ptr) - (char*)script->mem); \
129
0
    } \
130
0
  } while (0)
131
0
#define UNSERIALIZE_PTR(ptr) do { \
132
0
    if (ptr) { \
133
0
      ZEND_ASSERT(IS_SERIALIZED(ptr)); \
134
0
      (ptr) = (void*)((char*)buf + (size_t)(ptr)); \
135
0
    } \
136
0
  } while (0)
137
138
0
#define SERIALIZE_STR(ptr) do { \
139
0
    if (ptr) { \
140
0
      if (IS_ACCEL_INTERNED(ptr)) { \
141
0
        (ptr) = zend_file_cache_serialize_interned((zend_string*)(ptr), info); \
142
0
      } else { \
143
0
        ZEND_ASSERT(IS_UNSERIALIZED(ptr)); \
144
0
        (ptr) = (void*)((char*)(ptr) - (char*)script->mem); \
145
0
      } \
146
0
    } \
147
0
  } while (0)
148
0
#define UNSERIALIZE_STR(ptr) do { \
149
0
    if (ptr) { \
150
0
      if (IS_SERIALIZED_INTERNED(ptr)) { \
151
0
        (ptr) = (void*)zend_file_cache_unserialize_interned((zend_string*)(ptr), !script->corrupted); \
152
0
      } else { \
153
0
        ZEND_ASSERT(IS_SERIALIZED(ptr)); \
154
0
        (ptr) = (void*)((char*)buf + (size_t)(ptr)); \
155
0
        /* script->corrupted shows if the script in SHM or not */ \
156
0
        if (EXPECTED(!script->corrupted)) { \
157
0
          GC_ADD_FLAGS(ptr, IS_STR_INTERNED | IS_STR_PERMANENT); \
158
0
        } else { \
159
0
          GC_ADD_FLAGS(ptr, IS_STR_INTERNED); \
160
0
          GC_DEL_FLAGS(ptr, IS_STR_PERMANENT); \
161
0
        } \
162
0
        GC_DEL_FLAGS(ptr, IS_STR_CLASS_NAME_MAP_PTR); \
163
0
      } \
164
0
    } \
165
0
  } while (0)
166
167
0
#define SERIALIZE_ATTRIBUTES(attributes) do { \
168
0
  if ((attributes) && !IS_SERIALIZED(attributes)) { \
169
0
    HashTable *ht; \
170
0
    SERIALIZE_PTR(attributes); \
171
0
    ht = (attributes); \
172
0
    UNSERIALIZE_PTR(ht); \
173
0
    zend_file_cache_serialize_hash(ht, script, info, buf, zend_file_cache_serialize_attribute); \
174
0
  } \
175
0
} while (0)
176
177
0
#define UNSERIALIZE_ATTRIBUTES(attributes) do { \
178
0
  if ((attributes) && !IS_UNSERIALIZED(attributes)) { \
179
0
    HashTable *ht; \
180
0
    UNSERIALIZE_PTR(attributes); \
181
0
    ht = (attributes); \
182
0
    zend_file_cache_unserialize_hash(ht, script, buf, zend_file_cache_unserialize_attribute, NULL); \
183
0
  } \
184
0
} while (0)
185
186
0
#define HOOKED_ITERATOR_PLACEHOLDER ((void*)1)
187
188
static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
189
  {HT_INVALID_IDX, HT_INVALID_IDX};
190
191
typedef struct _zend_file_cache_metainfo {
192
  char         magic[8];
193
  char         system_id[32];
194
  size_t       mem_size;
195
  size_t       str_size;
196
  size_t       script_offset;
197
  accel_time_t timestamp;
198
  uint32_t     checksum;
199
} zend_file_cache_metainfo;
200
201
static int zend_file_cache_mkdir(char *filename, size_t start)
202
0
{
203
0
  char *s = filename + start;
204
205
0
  while (*s) {
206
0
    if (IS_SLASH(*s)) {
207
0
      char old = *s;
208
0
      *s = '\000';
209
0
#ifndef ZEND_WIN32
210
0
      if (mkdir(filename, S_IRWXU) < 0 && errno != EEXIST) {
211
#else
212
      if (php_win32_ioutil_mkdir(filename, 0700) < 0 && errno != EEXIST) {
213
#endif
214
0
        *s = old;
215
0
        return FAILURE;
216
0
      }
217
0
      *s = old;
218
0
    }
219
0
    s++;
220
0
  }
221
0
  return SUCCESS;
222
0
}
223
224
typedef void (*serialize_callback_t)(zval                     *zv,
225
                                     zend_persistent_script   *script,
226
                                     zend_file_cache_metainfo *info,
227
                                     void                     *buf);
228
229
typedef void (*unserialize_callback_t)(zval                    *zv,
230
                                       zend_persistent_script  *script,
231
                                       void                    *buf);
232
233
static void zend_file_cache_serialize_zval(zval                     *zv,
234
                                           zend_persistent_script   *script,
235
                                           zend_file_cache_metainfo *info,
236
                                           void                     *buf);
237
static void zend_file_cache_unserialize_zval(zval                    *zv,
238
                                             zend_persistent_script  *script,
239
                                             void                    *buf);
240
241
static void zend_file_cache_serialize_func(zval                     *zv,
242
                                           zend_persistent_script   *script,
243
                                           zend_file_cache_metainfo *info,
244
                                           void                     *buf);
245
246
static void zend_file_cache_unserialize_func(zval                    *zv,
247
                                             zend_persistent_script  *script,
248
                                             void                    *buf);
249
250
static void zend_file_cache_serialize_attribute(zval                     *zv,
251
                                                zend_persistent_script   *script,
252
                                                zend_file_cache_metainfo *info,
253
                                                void                     *buf);
254
255
static void zend_file_cache_unserialize_attribute(zval *zv, zend_persistent_script *script, void *buf);
256
257
static void *zend_file_cache_serialize_interned(zend_string              *str,
258
                                                zend_file_cache_metainfo *info)
259
0
{
260
0
  size_t len;
261
0
  void *ret;
262
263
  /* check if the same interned string was already stored */
264
0
  ret = zend_shared_alloc_get_xlat_entry(str);
265
0
  if (ret) {
266
0
    return ret;
267
0
  }
268
269
0
  len = ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(ZSTR_LEN(str)));
270
0
  ret = (void*)(info->str_size | Z_UL(1));
271
0
  zend_shared_alloc_register_xlat_entry(str, ret);
272
273
0
  zend_string *s = (zend_string*)ZCG(mem);
274
0
  if (info->str_size + len > ZSTR_LEN(s)) {
275
0
    size_t new_len = info->str_size + len;
276
0
    s = zend_string_realloc(
277
0
      s,
278
0
      ((_ZSTR_HEADER_SIZE + 1 + new_len + 4095) & ~0xfff) - (_ZSTR_HEADER_SIZE + 1),
279
0
      0);
280
0
    ZCG(mem) = (void*)s;
281
0
  }
282
283
0
  zend_string *new_str = (zend_string *) (ZSTR_VAL(s) + info->str_size);
284
0
  memcpy(new_str, str, len);
285
0
  GC_ADD_FLAGS(new_str, IS_STR_INTERNED);
286
0
  GC_DEL_FLAGS(new_str, IS_STR_PERMANENT|IS_STR_CLASS_NAME_MAP_PTR);
287
0
  info->str_size += len;
288
0
  return ret;
289
0
}
290
291
static void *zend_file_cache_unserialize_interned(zend_string *str, bool in_shm)
292
0
{
293
0
  str = (zend_string*)((char*)ZCG(mem) + ((size_t)(str) & ~Z_UL(1)));
294
0
  if (!in_shm) {
295
0
    return str;
296
0
  }
297
298
0
  zend_string *ret = accel_new_interned_string(str);
299
0
  if (ret == str) {
300
    /* We have to create new SHM allocated string */
301
0
    size_t size = _ZSTR_STRUCT_SIZE(ZSTR_LEN(str));
302
0
    ret = zend_shared_alloc(size);
303
0
    if (!ret) {
304
0
      zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
305
0
      LONGJMP(*EG(bailout), FAILURE);
306
0
    }
307
0
    memcpy(ret, str, size);
308
    /* String wasn't interned but we will use it as interned anyway */
309
0
    GC_SET_REFCOUNT(ret, 1);
310
0
    GC_TYPE_INFO(ret) = GC_STRING | ((IS_STR_INTERNED | IS_STR_PERSISTENT | IS_STR_PERMANENT) << GC_FLAGS_SHIFT);
311
0
  }
312
0
  return ret;
313
0
}
314
315
static void zend_file_cache_serialize_hash(HashTable                *ht,
316
                                           zend_persistent_script   *script,
317
                                           zend_file_cache_metainfo *info,
318
                                           void                     *buf,
319
                                           serialize_callback_t      func)
320
0
{
321
0
  if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
322
0
    ht->arData = NULL;
323
0
    return;
324
0
  }
325
0
  if (IS_SERIALIZED(ht->arData)) {
326
0
    return;
327
0
  }
328
0
  if (HT_IS_PACKED(ht)) {
329
0
    zval *p, *end;
330
331
0
    SERIALIZE_PTR(ht->arPacked);
332
0
    p = ht->arPacked;
333
0
    UNSERIALIZE_PTR(p);
334
0
    end = p + ht->nNumUsed;
335
0
    while (p < end) {
336
0
      if (Z_TYPE_P(p) != IS_UNDEF) {
337
0
        func(p, script, info, buf);
338
0
      }
339
0
      p++;
340
0
    }
341
0
  } else {
342
0
    Bucket *p, *end;
343
344
0
    SERIALIZE_PTR(ht->arData);
345
0
    p = ht->arData;
346
0
    UNSERIALIZE_PTR(p);
347
0
    end = p + ht->nNumUsed;
348
0
    while (p < end) {
349
0
      if (Z_TYPE(p->val) != IS_UNDEF) {
350
0
        SERIALIZE_STR(p->key);
351
0
        func(&p->val, script, info, buf);
352
0
      }
353
0
      p++;
354
0
    }
355
0
  }
356
0
}
357
358
static void zend_file_cache_serialize_ast(zend_ast                 *ast,
359
                                          zend_persistent_script   *script,
360
                                          zend_file_cache_metainfo *info,
361
                                          void                     *buf)
362
0
{
363
0
  uint32_t i;
364
0
  zend_ast *tmp;
365
366
0
  if (ast->kind == ZEND_AST_ZVAL || ast->kind == ZEND_AST_CONSTANT) {
367
0
    zend_file_cache_serialize_zval(&((zend_ast_zval*)ast)->val, script, info, buf);
368
0
  } else if (zend_ast_is_list(ast)) {
369
0
    zend_ast_list *list = zend_ast_get_list(ast);
370
0
    for (i = 0; i < list->children; i++) {
371
0
      if (list->child[i] && !IS_SERIALIZED(list->child[i])) {
372
0
        SERIALIZE_PTR(list->child[i]);
373
0
        tmp = list->child[i];
374
0
        UNSERIALIZE_PTR(tmp);
375
0
        zend_file_cache_serialize_ast(tmp, script, info, buf);
376
0
      }
377
0
    }
378
0
  } else if (ast->kind == ZEND_AST_OP_ARRAY) {
379
0
    zval z;
380
0
    ZVAL_PTR(&z, zend_ast_get_op_array(ast)->op_array);
381
0
    zend_file_cache_serialize_func(&z, script, info, buf);
382
0
    zend_ast_get_op_array(ast)->op_array = Z_PTR(z);
383
0
  } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) {
384
0
    zend_ast_fcc *fcc = (zend_ast_fcc*)ast;
385
0
    ZEND_MAP_PTR_INIT(fcc->fptr, NULL);
386
    /* Will be reset if needed during unserialize */
387
0
    fcc->attr |= ZEND_PARTIAL_CACHEABLE_IN_SHM;
388
0
    SERIALIZE_STR(fcc->filename);
389
0
    SERIALIZE_STR(fcc->name);
390
0
    if (!IS_SERIALIZED(fcc->args)) {
391
0
      SERIALIZE_PTR(fcc->args);
392
0
      tmp = fcc->args;
393
0
      UNSERIALIZE_PTR(tmp);
394
0
      zend_file_cache_serialize_ast(tmp, script, info, buf);
395
0
    }
396
0
  } else if (zend_ast_is_decl(ast)) {
397
    /* Not implemented. */
398
0
    ZEND_UNREACHABLE();
399
0
  } else {
400
0
    uint32_t children = zend_ast_get_num_children(ast);
401
0
    for (i = 0; i < children; i++) {
402
0
      if (ast->child[i] && !IS_SERIALIZED(ast->child[i])) {
403
0
        SERIALIZE_PTR(ast->child[i]);
404
0
        tmp = ast->child[i];
405
0
        UNSERIALIZE_PTR(tmp);
406
0
        zend_file_cache_serialize_ast(tmp, script, info, buf);
407
0
      }
408
0
    }
409
0
  }
410
0
}
411
412
static void zend_file_cache_serialize_zval(zval                     *zv,
413
                                           zend_persistent_script   *script,
414
                                           zend_file_cache_metainfo *info,
415
                                           void                     *buf)
416
0
{
417
0
  switch (Z_TYPE_P(zv)) {
418
0
    case IS_STRING:
419
0
      if (!IS_SERIALIZED(Z_STR_P(zv))) {
420
0
        SERIALIZE_STR(Z_STR_P(zv));
421
0
      }
422
0
      break;
423
0
    case IS_ARRAY:
424
0
      if (!IS_SERIALIZED(Z_ARR_P(zv))) {
425
0
        HashTable *ht;
426
427
0
        SERIALIZE_PTR(Z_ARR_P(zv));
428
0
        ht = Z_ARR_P(zv);
429
0
        UNSERIALIZE_PTR(ht);
430
0
        zend_file_cache_serialize_hash(ht, script, info, buf, zend_file_cache_serialize_zval);
431
0
      }
432
0
      break;
433
0
    case IS_CONSTANT_AST:
434
0
      if (!IS_SERIALIZED(Z_AST_P(zv))) {
435
0
        zend_ast_ref *ast;
436
437
0
        SERIALIZE_PTR(Z_AST_P(zv));
438
0
        ast = Z_AST_P(zv);
439
0
        UNSERIALIZE_PTR(ast);
440
0
        zend_file_cache_serialize_ast(GC_AST(ast), script, info, buf);
441
0
      }
442
0
      break;
443
0
    case IS_INDIRECT:
444
      /* Used by static properties. */
445
0
      SERIALIZE_PTR(Z_INDIRECT_P(zv));
446
0
      break;
447
0
    case IS_PTR:
448
      /* Used by attributes on constants, will be handled separately */
449
0
      break;
450
0
    default:
451
0
      ZEND_ASSERT(Z_TYPE_P(zv) < IS_STRING);
452
0
      break;
453
0
  }
454
0
}
455
456
static void zend_file_cache_serialize_attribute(zval                     *zv,
457
                                                zend_persistent_script   *script,
458
                                                zend_file_cache_metainfo *info,
459
                                                void                     *buf)
460
0
{
461
0
  zend_attribute *attr = Z_PTR_P(zv);
462
0
  uint32_t i;
463
464
0
  SERIALIZE_PTR(Z_PTR_P(zv));
465
0
  attr = Z_PTR_P(zv);
466
0
  UNSERIALIZE_PTR(attr);
467
468
0
  SERIALIZE_STR(attr->name);
469
0
  SERIALIZE_STR(attr->lcname);
470
0
  SERIALIZE_STR(attr->validation_error);
471
472
0
  for (i = 0; i < attr->argc; i++) {
473
0
    SERIALIZE_STR(attr->args[i].name);
474
0
    zend_file_cache_serialize_zval(&attr->args[i].value, script, info, buf);
475
0
  }
476
0
}
477
478
static void zend_file_cache_serialize_type(
479
    zend_type *type, zend_persistent_script *script, zend_file_cache_metainfo *info, void *buf)
480
0
{
481
0
  if (ZEND_TYPE_HAS_LIST(*type)) {
482
0
    zend_type_list *list = ZEND_TYPE_LIST(*type);
483
0
    SERIALIZE_PTR(list);
484
0
    ZEND_TYPE_SET_PTR(*type, list);
485
0
    UNSERIALIZE_PTR(list);
486
487
0
    zend_type *list_type;
488
0
    ZEND_TYPE_LIST_FOREACH_MUTABLE(list, list_type) {
489
0
      zend_file_cache_serialize_type(list_type, script, info, buf);
490
0
    } ZEND_TYPE_LIST_FOREACH_END();
491
0
  } else if (ZEND_TYPE_HAS_NAME(*type)) {
492
0
    zend_string *type_name = ZEND_TYPE_NAME(*type);
493
0
    SERIALIZE_STR(type_name);
494
0
    ZEND_TYPE_SET_PTR(*type, type_name);
495
0
  }
496
0
}
497
498
static void zend_file_cache_serialize_op_array(zend_op_array            *op_array,
499
                                               zend_persistent_script   *script,
500
                                               zend_file_cache_metainfo *info,
501
                                               void                     *buf)
502
0
{
503
0
  ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, NULL);
504
0
  ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
505
506
  /* Check whether this op_array has already been serialized. */
507
0
  if (IS_SERIALIZED(op_array->opcodes)) {
508
0
    ZEND_ASSERT(op_array->scope && "Only method op_arrays should be shared");
509
0
    return;
510
0
  }
511
512
0
  if (op_array->scope) {
513
0
    if (UNEXPECTED(zend_shared_alloc_get_xlat_entry(op_array->opcodes))) {
514
0
      op_array->refcount = (uint32_t*)(intptr_t)-1;
515
0
      SERIALIZE_PTR(op_array->static_variables);
516
0
      SERIALIZE_PTR(op_array->literals);
517
0
      SERIALIZE_PTR(op_array->opcodes);
518
0
      SERIALIZE_PTR(op_array->arg_info);
519
0
      SERIALIZE_PTR(op_array->vars);
520
0
      SERIALIZE_STR(op_array->function_name);
521
0
      SERIALIZE_STR(op_array->filename);
522
0
      SERIALIZE_PTR(op_array->live_range);
523
0
      SERIALIZE_PTR(op_array->scope);
524
0
      SERIALIZE_STR(op_array->doc_comment);
525
0
      SERIALIZE_ATTRIBUTES(op_array->attributes);
526
0
      SERIALIZE_PTR(op_array->try_catch_array);
527
0
      SERIALIZE_PTR(op_array->prototype);
528
0
      SERIALIZE_PTR(op_array->prop_info);
529
0
      return;
530
0
    }
531
0
    zend_shared_alloc_register_xlat_entry(op_array->opcodes, op_array->opcodes);
532
0
  }
533
534
0
  if (op_array->static_variables) {
535
0
    HashTable *ht;
536
537
0
    SERIALIZE_PTR(op_array->static_variables);
538
0
    ht = op_array->static_variables;
539
0
    UNSERIALIZE_PTR(ht);
540
0
    zend_file_cache_serialize_hash(ht, script, info, buf, zend_file_cache_serialize_zval);
541
0
  }
542
543
0
  if (op_array->literals) {
544
0
    zval *p, *end;
545
546
0
    SERIALIZE_PTR(op_array->literals);
547
0
    p = op_array->literals;
548
0
    UNSERIALIZE_PTR(p);
549
0
    end = p + op_array->last_literal;
550
0
    while (p < end) {
551
0
      zend_file_cache_serialize_zval(p, script, info, buf);
552
0
      p++;
553
0
    }
554
0
  }
555
556
0
  {
557
0
    zend_op *opline, *end;
558
559
0
#if !ZEND_USE_ABS_CONST_ADDR
560
0
    zval *literals = op_array->literals;
561
0
    UNSERIALIZE_PTR(literals);
562
0
#endif
563
564
0
    SERIALIZE_PTR(op_array->opcodes);
565
0
    opline = op_array->opcodes;
566
0
    UNSERIALIZE_PTR(opline);
567
0
    end = opline + op_array->last;
568
0
    while (opline < end) {
569
0
      if (opline->opcode == ZEND_OP_DATA
570
0
        && (opline-1)->opcode == ZEND_DECLARE_ATTRIBUTED_CONST
571
0
      ) {
572
0
        zval *literal = RT_CONSTANT(opline, opline->op1);
573
0
        SERIALIZE_ATTRIBUTES(Z_PTR_P(literal));
574
0
      }
575
576
#if ZEND_USE_ABS_CONST_ADDR
577
      if (opline->op1_type == IS_CONST) {
578
        SERIALIZE_PTR(opline->op1.zv);
579
      }
580
      if (opline->op2_type == IS_CONST) {
581
        SERIALIZE_PTR(opline->op2.zv);
582
583
        /* See GH-17733. Reset Z_EXTRA_P(op2) of ZEND_INIT_FCALL, which
584
         * is an offset into the global function table, to avoid calling
585
         * incorrect functions when environment changes. This, and the
586
         * equivalent code below, can be removed once proper system ID
587
         * validation is implemented. */
588
        if (opline->opcode == ZEND_INIT_FCALL) {
589
          zval *op2 = opline->op2.zv;
590
          UNSERIALIZE_PTR(op2);
591
          Z_EXTRA_P(op2) = 0;
592
          ZEND_VM_SET_OPCODE_HANDLER(opline);
593
        }
594
      }
595
#else
596
0
      if (opline->op1_type == IS_CONST) {
597
0
        opline->op1.constant = RT_CONSTANT(opline, opline->op1) - literals;
598
0
      }
599
0
      if (opline->op2_type == IS_CONST) {
600
0
        zval *op2 = RT_CONSTANT(opline, opline->op2);
601
0
        opline->op2.constant = op2 - literals;
602
603
        /* See GH-17733 and comment above. */
604
0
        if (opline->opcode == ZEND_INIT_FCALL) {
605
0
          Z_EXTRA_P(op2) = 0;
606
0
          ZEND_VM_SET_OPCODE_HANDLER(opline);
607
0
        }
608
0
      }
609
0
#endif
610
#if ZEND_USE_ABS_JMP_ADDR
611
      switch (opline->opcode) {
612
        case ZEND_JMP:
613
        case ZEND_FAST_CALL:
614
          SERIALIZE_PTR(opline->op1.jmp_addr);
615
          break;
616
        case ZEND_JMPZ:
617
        case ZEND_JMPNZ:
618
        case ZEND_JMPZ_EX:
619
        case ZEND_JMPNZ_EX:
620
        case ZEND_JMP_SET:
621
        case ZEND_COALESCE:
622
        case ZEND_FE_RESET_R:
623
        case ZEND_FE_RESET_RW:
624
        case ZEND_ASSERT_CHECK:
625
        case ZEND_JMP_NULL:
626
        case ZEND_BIND_INIT_STATIC_OR_JMP:
627
        case ZEND_JMP_FRAMELESS:
628
          SERIALIZE_PTR(opline->op2.jmp_addr);
629
          break;
630
        case ZEND_CATCH:
631
          if (!(opline->extended_value & ZEND_LAST_CATCH)) {
632
            SERIALIZE_PTR(opline->op2.jmp_addr);
633
          }
634
          break;
635
        case ZEND_FE_FETCH_R:
636
        case ZEND_FE_FETCH_RW:
637
        case ZEND_SWITCH_LONG:
638
        case ZEND_SWITCH_STRING:
639
        case ZEND_MATCH:
640
          /* relative extended_value don't have to be changed */
641
          break;
642
      }
643
#endif
644
645
0
      if (opline->opcode == ZEND_CALLABLE_CONVERT_PARTIAL) {
646
        /* Will be reset if needed during unserialize */
647
0
        opline->extended_value |= ZEND_PARTIAL_CACHEABLE_IN_SHM;
648
0
      }
649
650
0
      zend_serialize_opcode_handler(opline);
651
0
      opline++;
652
0
    }
653
654
0
    if (op_array->arg_info) {
655
0
      zend_arg_info *p, *end;
656
0
      SERIALIZE_PTR(op_array->arg_info);
657
0
      p = op_array->arg_info;
658
0
      UNSERIALIZE_PTR(p);
659
0
      end = p + op_array->num_args;
660
0
      if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
661
0
        p--;
662
0
      }
663
0
      if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
664
0
        end++;
665
0
      }
666
0
      while (p < end) {
667
0
        if (!IS_SERIALIZED(p->name)) {
668
0
          SERIALIZE_STR(p->name);
669
0
        }
670
0
        zend_file_cache_serialize_type(&p->type, script, info, buf);
671
0
        SERIALIZE_STR(p->doc_comment);
672
0
        p++;
673
0
      }
674
0
    }
675
676
0
    if (op_array->vars) {
677
0
      zend_string **p, **end;
678
679
0
      SERIALIZE_PTR(op_array->vars);
680
0
      p = op_array->vars;
681
0
      UNSERIALIZE_PTR(p);
682
0
      end = p + op_array->last_var;
683
0
      while (p < end) {
684
0
        if (!IS_SERIALIZED(*p)) {
685
0
          SERIALIZE_STR(*p);
686
0
        }
687
0
        p++;
688
0
      }
689
0
    }
690
691
0
    if (op_array->num_dynamic_func_defs) {
692
0
      zend_op_array **defs;
693
0
      SERIALIZE_PTR(op_array->dynamic_func_defs);
694
0
      defs = op_array->dynamic_func_defs;
695
0
      UNSERIALIZE_PTR(defs);
696
0
      for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
697
0
        zend_op_array *def;
698
0
        SERIALIZE_PTR(defs[i]);
699
0
        def = defs[i];
700
0
        UNSERIALIZE_PTR(def);
701
0
        zend_file_cache_serialize_op_array(def, script, info, buf);
702
0
      }
703
0
    }
704
705
0
    SERIALIZE_STR(op_array->function_name);
706
0
    SERIALIZE_STR(op_array->filename);
707
0
    SERIALIZE_PTR(op_array->live_range);
708
0
    SERIALIZE_PTR(op_array->scope);
709
0
    SERIALIZE_STR(op_array->doc_comment);
710
0
    SERIALIZE_ATTRIBUTES(op_array->attributes);
711
0
    SERIALIZE_PTR(op_array->try_catch_array);
712
0
    SERIALIZE_PTR(op_array->prototype);
713
0
    SERIALIZE_PTR(op_array->prop_info);
714
0
  }
715
0
}
716
717
static void zend_file_cache_serialize_func(zval                     *zv,
718
                                           zend_persistent_script   *script,
719
                                           zend_file_cache_metainfo *info,
720
                                           void                     *buf)
721
0
{
722
0
  zend_function *func;
723
0
  SERIALIZE_PTR(Z_PTR_P(zv));
724
0
  func = Z_PTR_P(zv);
725
0
  UNSERIALIZE_PTR(func);
726
0
  ZEND_ASSERT(func->type == ZEND_USER_FUNCTION);
727
0
  zend_file_cache_serialize_op_array(&func->op_array, script, info, buf);
728
0
}
729
730
static void zend_file_cache_serialize_prop_info(zval                     *zv,
731
                                                zend_persistent_script   *script,
732
                                                zend_file_cache_metainfo *info,
733
                                                void                     *buf)
734
0
{
735
0
  if (!IS_SERIALIZED(Z_PTR_P(zv))) {
736
0
    zend_property_info *prop;
737
738
0
    SERIALIZE_PTR(Z_PTR_P(zv));
739
0
    prop = Z_PTR_P(zv);
740
0
    UNSERIALIZE_PTR(prop);
741
742
0
    ZEND_ASSERT(prop->ce != NULL && prop->name != NULL);
743
0
    if (!IS_SERIALIZED(prop->ce)) {
744
0
      SERIALIZE_PTR(prop->ce);
745
0
      SERIALIZE_STR(prop->name);
746
0
      if (prop->doc_comment) {
747
0
        SERIALIZE_STR(prop->doc_comment);
748
0
      }
749
0
      SERIALIZE_ATTRIBUTES(prop->attributes);
750
0
      SERIALIZE_PTR(prop->prototype);
751
0
      if (prop->hooks) {
752
0
        SERIALIZE_PTR(prop->hooks);
753
0
        zend_function **hooks = prop->hooks;
754
0
        UNSERIALIZE_PTR(hooks);
755
0
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
756
0
          if (hooks[i]) {
757
0
            SERIALIZE_PTR(hooks[i]);
758
0
            zend_function *hook = hooks[i];
759
0
            UNSERIALIZE_PTR(hook);
760
0
            zend_file_cache_serialize_op_array(&hook->op_array, script, info, buf);
761
0
          }
762
0
        }
763
0
      }
764
0
      zend_file_cache_serialize_type(&prop->type, script, info, buf);
765
0
    }
766
0
  }
767
0
}
768
769
static void zend_file_cache_serialize_class_constant(zval                     *zv,
770
                                                     zend_persistent_script   *script,
771
                                                     zend_file_cache_metainfo *info,
772
                                                     void                     *buf)
773
0
{
774
0
  if (!IS_SERIALIZED(Z_PTR_P(zv))) {
775
0
    zend_class_constant *c;
776
777
0
    SERIALIZE_PTR(Z_PTR_P(zv));
778
0
    c = Z_PTR_P(zv);
779
0
    UNSERIALIZE_PTR(c);
780
781
0
    ZEND_ASSERT(c->ce != NULL);
782
0
    if (!IS_SERIALIZED(c->ce)) {
783
0
      SERIALIZE_PTR(c->ce);
784
785
0
      zend_file_cache_serialize_zval(&c->value, script, info, buf);
786
0
      if (c->doc_comment) {
787
0
        SERIALIZE_STR(c->doc_comment);
788
0
      }
789
790
0
      SERIALIZE_ATTRIBUTES(c->attributes);
791
0
      zend_file_cache_serialize_type(&c->type, script, info, buf);
792
0
    }
793
0
  }
794
0
}
795
796
static void zend_file_cache_serialize_class(zval                     *zv,
797
                                            zend_persistent_script   *script,
798
                                            zend_file_cache_metainfo *info,
799
                                            void                     *buf)
800
0
{
801
0
  zend_class_entry *ce;
802
803
0
  SERIALIZE_PTR(Z_PTR_P(zv));
804
0
  ce = Z_PTR_P(zv);
805
0
  UNSERIALIZE_PTR(ce);
806
807
0
  SERIALIZE_STR(ce->name);
808
0
  if (ce->parent) {
809
0
    if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
810
0
      SERIALIZE_STR(ce->parent_name);
811
0
    } else {
812
0
      SERIALIZE_PTR(ce->parent);
813
0
    }
814
0
  }
815
0
  zend_file_cache_serialize_hash(&ce->function_table, script, info, buf, zend_file_cache_serialize_func);
816
0
  if (ce->default_properties_table) {
817
0
    zval *p, *end;
818
819
0
    SERIALIZE_PTR(ce->default_properties_table);
820
0
    p = ce->default_properties_table;
821
0
    UNSERIALIZE_PTR(p);
822
0
    end = p + ce->default_properties_count;
823
0
    while (p < end) {
824
0
      zend_file_cache_serialize_zval(p, script, info, buf);
825
0
      p++;
826
0
    }
827
0
  }
828
0
  if (ce->default_static_members_table) {
829
0
    zval *p, *end;
830
831
0
    SERIALIZE_PTR(ce->default_static_members_table);
832
0
    p = ce->default_static_members_table;
833
0
    UNSERIALIZE_PTR(p);
834
835
0
    end = p + ce->default_static_members_count;
836
0
    while (p < end) {
837
0
      zend_file_cache_serialize_zval(p, script, info, buf);
838
0
      p++;
839
0
    }
840
0
  }
841
0
  zend_file_cache_serialize_hash(&ce->constants_table, script, info, buf, zend_file_cache_serialize_class_constant);
842
0
  SERIALIZE_STR(ce->info.user.filename);
843
0
  SERIALIZE_STR(ce->doc_comment);
844
0
  SERIALIZE_ATTRIBUTES(ce->attributes);
845
0
  zend_file_cache_serialize_hash(&ce->properties_info, script, info, buf, zend_file_cache_serialize_prop_info);
846
847
0
  if (ce->properties_info_table) {
848
0
    uint32_t i;
849
0
    zend_property_info **table;
850
851
0
    SERIALIZE_PTR(ce->properties_info_table);
852
0
    table = ce->properties_info_table;
853
0
    UNSERIALIZE_PTR(table);
854
855
0
    for (i = 0; i < ce->default_properties_count; i++) {
856
0
      SERIALIZE_PTR(table[i]);
857
0
    }
858
0
  }
859
860
0
  if (ce->num_interfaces) {
861
0
    uint32_t i;
862
0
    zend_class_name *interface_names;
863
864
0
    ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
865
866
0
    SERIALIZE_PTR(ce->interface_names);
867
0
    interface_names = ce->interface_names;
868
0
    UNSERIALIZE_PTR(interface_names);
869
870
0
    for (i = 0; i < ce->num_interfaces; i++) {
871
0
      SERIALIZE_STR(interface_names[i].name);
872
0
      SERIALIZE_STR(interface_names[i].lc_name);
873
0
    }
874
0
  }
875
876
0
  if (ce->num_traits) {
877
0
    uint32_t i;
878
0
    zend_class_name *trait_names;
879
880
0
    SERIALIZE_PTR(ce->trait_names);
881
0
    trait_names = ce->trait_names;
882
0
    UNSERIALIZE_PTR(trait_names);
883
884
0
    for (i = 0; i < ce->num_traits; i++) {
885
0
      SERIALIZE_STR(trait_names[i].name);
886
0
      SERIALIZE_STR(trait_names[i].lc_name);
887
0
    }
888
889
0
    if (ce->trait_aliases) {
890
0
      zend_trait_alias **p, *q;
891
892
0
      SERIALIZE_PTR(ce->trait_aliases);
893
0
      p = ce->trait_aliases;
894
0
      UNSERIALIZE_PTR(p);
895
896
0
      while (*p) {
897
0
        SERIALIZE_PTR(*p);
898
0
        q = *p;
899
0
        UNSERIALIZE_PTR(q);
900
901
0
        if (q->trait_method.method_name) {
902
0
          SERIALIZE_STR(q->trait_method.method_name);
903
0
        }
904
0
        if (q->trait_method.class_name) {
905
0
          SERIALIZE_STR(q->trait_method.class_name);
906
0
        }
907
908
0
        if (q->alias) {
909
0
          SERIALIZE_STR(q->alias);
910
0
        }
911
0
        p++;
912
0
      }
913
0
    }
914
915
0
    if (ce->trait_precedences) {
916
0
      zend_trait_precedence **p, *q;
917
0
      uint32_t j;
918
919
0
      SERIALIZE_PTR(ce->trait_precedences);
920
0
      p = ce->trait_precedences;
921
0
      UNSERIALIZE_PTR(p);
922
923
0
      while (*p) {
924
0
        SERIALIZE_PTR(*p);
925
0
        q = *p;
926
0
        UNSERIALIZE_PTR(q);
927
928
0
        if (q->trait_method.method_name) {
929
0
          SERIALIZE_STR(q->trait_method.method_name);
930
0
        }
931
0
        if (q->trait_method.class_name) {
932
0
          SERIALIZE_STR(q->trait_method.class_name);
933
0
        }
934
935
0
        for (j = 0; j < q->num_excludes; j++) {
936
0
          SERIALIZE_STR(q->exclude_class_names[j]);
937
0
        }
938
0
        p++;
939
0
      }
940
0
    }
941
0
  }
942
943
0
  SERIALIZE_PTR(ce->constructor);
944
0
  SERIALIZE_PTR(ce->destructor);
945
0
  SERIALIZE_PTR(ce->clone);
946
0
  SERIALIZE_PTR(ce->__get);
947
0
  SERIALIZE_PTR(ce->__set);
948
0
  SERIALIZE_PTR(ce->__call);
949
0
  SERIALIZE_PTR(ce->__serialize);
950
0
  SERIALIZE_PTR(ce->__unserialize);
951
0
  SERIALIZE_PTR(ce->__isset);
952
0
  SERIALIZE_PTR(ce->__unset);
953
0
  SERIALIZE_PTR(ce->__tostring);
954
0
  SERIALIZE_PTR(ce->__callstatic);
955
0
  SERIALIZE_PTR(ce->__debugInfo);
956
957
0
  if (ce->iterator_funcs_ptr) {
958
0
    SERIALIZE_PTR(ce->iterator_funcs_ptr->zf_new_iterator);
959
0
    SERIALIZE_PTR(ce->iterator_funcs_ptr->zf_rewind);
960
0
    SERIALIZE_PTR(ce->iterator_funcs_ptr->zf_valid);
961
0
    SERIALIZE_PTR(ce->iterator_funcs_ptr->zf_key);
962
0
    SERIALIZE_PTR(ce->iterator_funcs_ptr->zf_current);
963
0
    SERIALIZE_PTR(ce->iterator_funcs_ptr->zf_next);
964
0
    SERIALIZE_PTR(ce->iterator_funcs_ptr);
965
0
  }
966
967
0
  if (ce->arrayaccess_funcs_ptr) {
968
0
    SERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetget);
969
0
    SERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetexists);
970
0
    SERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetset);
971
0
    SERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetunset);
972
0
    SERIALIZE_PTR(ce->arrayaccess_funcs_ptr);
973
0
  }
974
975
0
  ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
976
0
  ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
977
978
0
  ce->inheritance_cache = NULL;
979
980
0
  if (ce->get_iterator) {
981
0
    ZEND_ASSERT(ce->get_iterator == zend_hooked_object_get_iterator);
982
0
    ce->get_iterator = HOOKED_ITERATOR_PLACEHOLDER;
983
0
  }
984
0
}
985
986
static void zend_file_cache_serialize_warnings(
987
    zend_persistent_script *script, zend_file_cache_metainfo *info, void *buf)
988
0
{
989
0
  if (script->warnings) {
990
0
    zend_error_info **warnings;
991
0
    SERIALIZE_PTR(script->warnings);
992
0
    warnings = script->warnings;
993
0
    UNSERIALIZE_PTR(warnings);
994
995
0
    for (uint32_t i = 0; i < script->num_warnings; i++) {
996
0
      zend_error_info *warning;
997
0
      SERIALIZE_PTR(warnings[i]);
998
0
      warning = warnings[i];
999
0
      UNSERIALIZE_PTR(warning);
1000
0
      SERIALIZE_STR(warning->filename);
1001
0
      SERIALIZE_STR(warning->message);
1002
0
    }
1003
0
  }
1004
0
}
1005
1006
static void zend_file_cache_serialize_early_bindings(
1007
    zend_persistent_script *script, zend_file_cache_metainfo *info, void *buf)
1008
0
{
1009
0
  if (script->early_bindings) {
1010
0
    SERIALIZE_PTR(script->early_bindings);
1011
0
    zend_early_binding *early_bindings = script->early_bindings;
1012
0
    UNSERIALIZE_PTR(early_bindings);
1013
0
    for (uint32_t i = 0; i < script->num_early_bindings; i++) {
1014
0
      SERIALIZE_STR(early_bindings[i].lcname);
1015
0
      SERIALIZE_STR(early_bindings[i].rtd_key);
1016
0
      SERIALIZE_STR(early_bindings[i].lc_parent_name);
1017
0
    }
1018
0
  }
1019
0
}
1020
1021
static void zend_file_cache_serialize(zend_persistent_script   *script,
1022
                                      zend_file_cache_metainfo *info,
1023
                                      void                     *buf)
1024
0
{
1025
0
  zend_persistent_script *new_script;
1026
1027
0
  memcpy(info->magic, "OPCACHE", 8);
1028
0
  memcpy(info->system_id, zend_system_id, 32);
1029
0
  info->mem_size = script->size;
1030
0
  info->str_size = 0;
1031
0
  info->script_offset = (char*)script - (char*)script->mem;
1032
0
  info->timestamp = script->timestamp;
1033
1034
0
  memcpy(buf, script->mem, script->size);
1035
1036
0
  new_script = (zend_persistent_script*)((char*)buf + info->script_offset);
1037
0
  SERIALIZE_STR(new_script->script.filename);
1038
1039
0
  zend_file_cache_serialize_hash(&new_script->script.class_table, script, info, buf, zend_file_cache_serialize_class);
1040
0
  zend_file_cache_serialize_hash(&new_script->script.function_table, script, info, buf, zend_file_cache_serialize_func);
1041
0
  zend_file_cache_serialize_op_array(&new_script->script.main_op_array, script, info, buf);
1042
0
  zend_file_cache_serialize_warnings(new_script, info, buf);
1043
0
  zend_file_cache_serialize_early_bindings(new_script, info, buf);
1044
1045
0
  new_script->mem = NULL;
1046
0
}
1047
1048
static char *zend_file_cache_get_bin_file_path(zend_string *script_path)
1049
0
{
1050
0
  size_t len;
1051
0
  char *filename;
1052
1053
0
#ifndef ZEND_WIN32
1054
0
  len = strlen(ZCG(accel_directives).file_cache);
1055
0
  filename = emalloc(len + 33 + ZSTR_LEN(script_path) + sizeof(SUFFIX));
1056
0
  memcpy(filename, ZCG(accel_directives).file_cache, len);
1057
0
  filename[len] = '/';
1058
0
  memcpy(filename + len + 1, zend_system_id, 32);
1059
0
  memcpy(filename + len + 33, ZSTR_VAL(script_path), ZSTR_LEN(script_path));
1060
0
  memcpy(filename + len + 33 + ZSTR_LEN(script_path), SUFFIX, sizeof(SUFFIX));
1061
#else
1062
  len = strlen(ZCG(accel_directives).file_cache);
1063
1064
  filename = emalloc(len + 33 + 33 + ZSTR_LEN(script_path) + sizeof(SUFFIX));
1065
1066
  memcpy(filename, ZCG(accel_directives).file_cache, len);
1067
  filename[len] = '\\';
1068
  memcpy(filename + 1 + len, accel_uname_id, 32);
1069
  len += 1 + 32;
1070
  filename[len] = '\\';
1071
1072
  memcpy(filename + len + 1, zend_system_id, 32);
1073
1074
  if (ZSTR_LEN(script_path) >= 7 && ':' == ZSTR_VAL(script_path)[4] && '/' == ZSTR_VAL(script_path)[5]  && '/' == ZSTR_VAL(script_path)[6]) {
1075
    /* phar:// or file:// */
1076
    *(filename + len + 33) = '\\';
1077
    memcpy(filename + len + 34, ZSTR_VAL(script_path), 4);
1078
    if (ZSTR_LEN(script_path) - 7 >= 2 && ':' == ZSTR_VAL(script_path)[8]) {
1079
      *(filename + len + 38) = '\\';
1080
      *(filename + len + 39) = ZSTR_VAL(script_path)[7];
1081
      memcpy(filename + len + 40, ZSTR_VAL(script_path) + 9, ZSTR_LEN(script_path) - 9);
1082
      memcpy(filename + len + 40 + ZSTR_LEN(script_path) - 9, SUFFIX, sizeof(SUFFIX));
1083
    } else {
1084
      memcpy(filename + len + 38, ZSTR_VAL(script_path) + 7, ZSTR_LEN(script_path) - 7);
1085
      memcpy(filename + len + 38 + ZSTR_LEN(script_path) - 7, SUFFIX, sizeof(SUFFIX));
1086
    }
1087
  } else if (ZSTR_LEN(script_path) >= 2 && ':' == ZSTR_VAL(script_path)[1]) {
1088
    /* local fs */
1089
    *(filename + len + 33) = '\\';
1090
    *(filename + len + 34) = ZSTR_VAL(script_path)[0];
1091
    memcpy(filename + len + 35, ZSTR_VAL(script_path) + 2, ZSTR_LEN(script_path) - 2);
1092
    memcpy(filename + len + 35 + ZSTR_LEN(script_path) - 2, SUFFIX, sizeof(SUFFIX));
1093
  } else {
1094
    /* network path */
1095
    memcpy(filename + len + 33, ZSTR_VAL(script_path), ZSTR_LEN(script_path));
1096
    memcpy(filename + len + 33 + ZSTR_LEN(script_path), SUFFIX, sizeof(SUFFIX));
1097
  }
1098
#endif
1099
1100
0
  return filename;
1101
0
}
1102
1103
/**
1104
 * Helper function for zend_file_cache_script_store().
1105
 *
1106
 * @return true on success, false on error and errno is set to indicate the cause of the error
1107
 */
1108
static bool zend_file_cache_script_write(int fd, const zend_persistent_script *script, const zend_file_cache_metainfo *info, const void *buf, const zend_string *s)
1109
0
{
1110
0
  ssize_t written;
1111
0
  const ssize_t total_size = (ssize_t)(sizeof(*info) + script->size + info->str_size);
1112
1113
0
#ifdef HAVE_SYS_UIO_H
1114
0
  const struct iovec vec[] = {
1115
0
    { .iov_base = (void *)info, .iov_len = sizeof(*info) },
1116
0
    { .iov_base = (void *)buf, .iov_len = script->size },
1117
0
    { .iov_base = (void *)ZSTR_VAL(s), .iov_len = info->str_size },
1118
0
  };
1119
1120
0
  written = writev(fd, vec, sizeof(vec) / sizeof(vec[0]));
1121
0
  if (EXPECTED(written == total_size)) {
1122
0
    return true;
1123
0
  }
1124
1125
0
  errno = written == -1 ? errno : EAGAIN;
1126
0
  return false;
1127
#else
1128
  if (UNEXPECTED(ZEND_LONG_MAX < (zend_long)total_size)) {
1129
# ifdef EFBIG
1130
    errno = EFBIG;
1131
# else
1132
    errno = ERANGE;
1133
# endif
1134
    return false;
1135
  }
1136
1137
  written = write(fd, info, sizeof(*info));
1138
  if (UNEXPECTED(written != sizeof(*info))) {
1139
    errno = written == -1 ? errno : EAGAIN;
1140
    return false;
1141
  }
1142
1143
  written = write(fd, buf, script->size);
1144
  if (UNEXPECTED(written != script->size)) {
1145
    errno = written == -1 ? errno : EAGAIN;
1146
    return false;
1147
  }
1148
1149
  written = write(fd, ZSTR_VAL(s), info->str_size);
1150
  if (UNEXPECTED(written != info->str_size)) {
1151
    errno = written == -1 ? errno : EAGAIN;
1152
    return false;
1153
  }
1154
1155
  return true;
1156
#endif
1157
0
}
1158
1159
int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm)
1160
0
{
1161
0
  int fd;
1162
0
  char *filename;
1163
0
  zend_file_cache_metainfo info;
1164
0
  void *mem, *buf;
1165
1166
0
#ifdef HAVE_JIT
1167
  /* FIXME: dump jited codes out to file cache? */
1168
0
  if (JIT_G(on)) {
1169
0
    return FAILURE;
1170
0
  }
1171
0
#endif
1172
1173
0
  if (ZCG(accel_directives).file_cache_read_only) {
1174
0
    return FAILURE;
1175
0
  }
1176
1177
0
  filename = zend_file_cache_get_bin_file_path(script->script.filename);
1178
1179
0
  if (zend_file_cache_mkdir(filename, strlen(ZCG(accel_directives).file_cache)) != SUCCESS) {
1180
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot create directory for file '%s', %s\n", filename, strerror(errno));
1181
0
    efree(filename);
1182
0
    return FAILURE;
1183
0
  }
1184
1185
0
  fd = zend_file_cache_open(filename, O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
1186
0
  if (fd < 0) {
1187
0
    if (errno != EEXIST) {
1188
0
      zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot create file '%s', %s\n", filename, strerror(errno));
1189
0
    }
1190
0
    efree(filename);
1191
0
    return FAILURE;
1192
0
  }
1193
1194
0
  if (zend_file_cache_flock(fd, LOCK_EX) != 0) {
1195
0
    close(fd);
1196
0
    efree(filename);
1197
0
    return FAILURE;
1198
0
  }
1199
1200
0
#if defined(__AVX__) || defined(__SSE2__)
1201
  /* Align to 64-byte boundary */
1202
0
  mem = emalloc(script->size + 64);
1203
0
  buf = (void*)(((uintptr_t)mem + 63L) & ~63L);
1204
#else
1205
  mem = buf = emalloc(script->size);
1206
#endif
1207
1208
0
  ZCG(mem) = zend_string_alloc(4096 - (_ZSTR_HEADER_SIZE + 1), 0);
1209
1210
0
  zend_shared_alloc_init_xlat_table();
1211
0
  if (!in_shm) {
1212
0
    script->corrupted = true; /* used to check if script restored to SHM or process memory */
1213
0
  }
1214
0
  zend_file_cache_serialize(script, &info, buf);
1215
0
  if (!in_shm) {
1216
0
    script->corrupted = false;
1217
0
  }
1218
0
  zend_shared_alloc_destroy_xlat_table();
1219
1220
0
  zend_string *const s = (zend_string*)ZCG(mem);
1221
1222
#if __has_feature(memory_sanitizer)
1223
  /* The buffer may contain uninitialized regions. However, the uninitialized parts will not be
1224
   * used when reading the cache. We should probably still try to get things fully initialized
1225
   * for reproducibility, but for now ignore this issue. */
1226
  __msan_unpoison(&info, sizeof(info));
1227
  __msan_unpoison(buf, script->size);
1228
#endif
1229
1230
0
  info.checksum = zend_adler32(ADLER32_INIT, buf, script->size);
1231
0
  info.checksum = zend_adler32(info.checksum, (unsigned char*)ZSTR_VAL(s), info.str_size);
1232
1233
0
  if (!zend_file_cache_script_write(fd, script, &info, buf, s)) {
1234
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot write to file '%s': %s\n", filename, strerror(errno));
1235
0
    zend_string_release_ex(s, 0);
1236
0
    close(fd);
1237
0
    efree(mem);
1238
0
    zend_file_cache_unlink(filename);
1239
0
    efree(filename);
1240
0
    return FAILURE;
1241
0
  }
1242
1243
0
  zend_string_release_ex(s, 0);
1244
0
  efree(mem);
1245
0
  if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
1246
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s': %s\n", filename, strerror(errno));
1247
0
  }
1248
0
  close(fd);
1249
0
  efree(filename);
1250
1251
0
  return SUCCESS;
1252
0
}
1253
1254
static void zend_file_cache_unserialize_hash(HashTable               *ht,
1255
                                             zend_persistent_script  *script,
1256
                                             void                    *buf,
1257
                                             unserialize_callback_t   func,
1258
                                             dtor_func_t              dtor)
1259
0
{
1260
0
  ht->pDestructor = dtor;
1261
0
  if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
1262
0
    if (EXPECTED(!file_cache_only)) {
1263
0
      HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
1264
0
    } else {
1265
0
      HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
1266
0
    }
1267
0
    return;
1268
0
  }
1269
0
  if (IS_UNSERIALIZED(ht->arData)) {
1270
0
    return;
1271
0
  }
1272
0
  UNSERIALIZE_PTR(ht->arData);
1273
0
  if (HT_IS_PACKED(ht)) {
1274
0
    zval *p, *end;
1275
1276
0
    p = ht->arPacked;
1277
0
    end = p + ht->nNumUsed;
1278
0
    while (p < end) {
1279
0
      if (Z_TYPE_P(p) != IS_UNDEF) {
1280
0
        func(p, script, buf);
1281
0
      }
1282
0
      p++;
1283
0
    }
1284
0
  } else {
1285
0
    Bucket *p, *end;
1286
1287
0
    p = ht->arData;
1288
0
    end = p + ht->nNumUsed;
1289
0
    while (p < end) {
1290
0
      if (Z_TYPE(p->val) != IS_UNDEF) {
1291
0
        UNSERIALIZE_STR(p->key);
1292
0
        func(&p->val, script, buf);
1293
0
      }
1294
0
      p++;
1295
0
    }
1296
0
  }
1297
0
}
1298
1299
static void zend_file_cache_unserialize_ast(zend_ast                *ast,
1300
                                            zend_persistent_script  *script,
1301
                                            void                    *buf)
1302
0
{
1303
0
  uint32_t i;
1304
1305
0
  if (ast->kind == ZEND_AST_ZVAL || ast->kind == ZEND_AST_CONSTANT) {
1306
0
    zend_file_cache_unserialize_zval(&((zend_ast_zval*)ast)->val, script, buf);
1307
0
  } else if (zend_ast_is_list(ast)) {
1308
0
    zend_ast_list *list = zend_ast_get_list(ast);
1309
0
    for (i = 0; i < list->children; i++) {
1310
0
      if (list->child[i] && !IS_UNSERIALIZED(list->child[i])) {
1311
0
        UNSERIALIZE_PTR(list->child[i]);
1312
0
        zend_file_cache_unserialize_ast(list->child[i], script, buf);
1313
0
      }
1314
0
    }
1315
0
  } else if (ast->kind == ZEND_AST_OP_ARRAY) {
1316
0
    zval z;
1317
0
    ZVAL_PTR(&z, zend_ast_get_op_array(ast)->op_array);
1318
0
    zend_file_cache_unserialize_func(&z, script, buf);
1319
0
    zend_ast_get_op_array(ast)->op_array = Z_PTR(z);
1320
0
  } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) {
1321
0
    zend_ast_fcc *fcc = (zend_ast_fcc*)ast;
1322
0
    if (script->corrupted) {
1323
0
      fcc->attr &= ~ZEND_PARTIAL_CACHEABLE_IN_SHM;
1324
0
    } else {
1325
0
      ZEND_MAP_PTR_NEW(fcc->fptr);
1326
0
    }
1327
0
    UNSERIALIZE_STR(fcc->filename);
1328
0
    UNSERIALIZE_STR(fcc->name);
1329
0
    if (!IS_UNSERIALIZED(fcc->args)) {
1330
0
      UNSERIALIZE_PTR(fcc->args);
1331
0
      zend_file_cache_unserialize_ast(fcc->args, script, buf);
1332
0
    }
1333
0
  } else if (zend_ast_is_decl(ast)) {
1334
    /* Not implemented. */
1335
0
    ZEND_UNREACHABLE();
1336
0
  } else {
1337
0
    uint32_t children = zend_ast_get_num_children(ast);
1338
0
    for (i = 0; i < children; i++) {
1339
0
      if (ast->child[i] && !IS_UNSERIALIZED(ast->child[i])) {
1340
0
        UNSERIALIZE_PTR(ast->child[i]);
1341
0
        zend_file_cache_unserialize_ast(ast->child[i], script, buf);
1342
0
      }
1343
0
    }
1344
0
  }
1345
0
}
1346
1347
static void zend_file_cache_unserialize_zval(zval                    *zv,
1348
                                             zend_persistent_script  *script,
1349
                                             void                    *buf)
1350
0
{
1351
0
  switch (Z_TYPE_P(zv)) {
1352
0
    case IS_STRING:
1353
      /* We can't use !IS_UNSERIALIZED here, because that does not recognize unserialized
1354
       * interned strings in non-shm mode. */
1355
0
      if (IS_SERIALIZED(Z_STR_P(zv)) || IS_SERIALIZED_INTERNED(Z_STR_P(zv))) {
1356
0
        UNSERIALIZE_STR(Z_STR_P(zv));
1357
0
      }
1358
0
      break;
1359
0
    case IS_ARRAY:
1360
0
      if (!IS_UNSERIALIZED(Z_ARR_P(zv))) {
1361
0
        HashTable *ht;
1362
1363
0
        UNSERIALIZE_PTR(Z_ARR_P(zv));
1364
0
        ht = Z_ARR_P(zv);
1365
0
        zend_file_cache_unserialize_hash(ht,
1366
0
            script, buf, zend_file_cache_unserialize_zval, ZVAL_PTR_DTOR);
1367
0
      }
1368
0
      break;
1369
0
    case IS_CONSTANT_AST:
1370
0
      if (!IS_UNSERIALIZED(Z_AST_P(zv))) {
1371
0
        UNSERIALIZE_PTR(Z_AST_P(zv));
1372
0
        zend_file_cache_unserialize_ast(Z_ASTVAL_P(zv), script, buf);
1373
0
      }
1374
0
      break;
1375
0
    case IS_INDIRECT:
1376
      /* Used by static properties. */
1377
0
      UNSERIALIZE_PTR(Z_INDIRECT_P(zv));
1378
0
      break;
1379
0
    case IS_PTR:
1380
      /* Used by attributes on constants, will be handled separately */
1381
0
      break;
1382
0
    default:
1383
0
      ZEND_ASSERT(Z_TYPE_P(zv) < IS_STRING);
1384
0
      break;
1385
0
  }
1386
0
}
1387
1388
static void zend_file_cache_unserialize_attribute(zval *zv, zend_persistent_script *script, void *buf)
1389
0
{
1390
0
  zend_attribute *attr;
1391
0
  uint32_t i;
1392
1393
0
  UNSERIALIZE_PTR(Z_PTR_P(zv));
1394
0
  attr = Z_PTR_P(zv);
1395
1396
0
  UNSERIALIZE_STR(attr->name);
1397
0
  UNSERIALIZE_STR(attr->lcname);
1398
0
  UNSERIALIZE_STR(attr->validation_error);
1399
1400
0
  for (i = 0; i < attr->argc; i++) {
1401
0
    UNSERIALIZE_STR(attr->args[i].name);
1402
0
    zend_file_cache_unserialize_zval(&attr->args[i].value, script, buf);
1403
0
  }
1404
0
}
1405
1406
static void zend_file_cache_unserialize_type(
1407
    zend_type *type, zend_class_entry *scope, zend_persistent_script *script, void *buf)
1408
0
{
1409
0
  if (ZEND_TYPE_HAS_LIST(*type)) {
1410
0
    zend_type_list *list = ZEND_TYPE_LIST(*type);
1411
0
    UNSERIALIZE_PTR(list);
1412
0
    ZEND_TYPE_SET_PTR(*type, list);
1413
1414
0
    zend_type *list_type;
1415
0
    ZEND_TYPE_LIST_FOREACH_MUTABLE(list, list_type) {
1416
0
      zend_file_cache_unserialize_type(list_type, scope, script, buf);
1417
0
    } ZEND_TYPE_LIST_FOREACH_END();
1418
0
  } else if (ZEND_TYPE_HAS_NAME(*type)) {
1419
0
    zend_string *type_name = ZEND_TYPE_NAME(*type);
1420
0
    UNSERIALIZE_STR(type_name);
1421
0
    ZEND_TYPE_SET_PTR(*type, type_name);
1422
0
    if (!script->corrupted) {
1423
0
      zend_accel_get_class_name_map_ptr(type_name);
1424
0
    } else {
1425
0
      zend_alloc_ce_cache(type_name);
1426
0
    }
1427
0
  }
1428
0
}
1429
1430
static void zend_file_cache_unserialize_op_array(zend_op_array           *op_array,
1431
                                                 zend_persistent_script  *script,
1432
                                                 void                    *buf)
1433
0
{
1434
0
  if (!script->corrupted) {
1435
0
    if (op_array != &script->script.main_op_array) {
1436
0
      op_array->fn_flags |= ZEND_ACC_IMMUTABLE;
1437
0
      ZEND_MAP_PTR_NEW(op_array->run_time_cache);
1438
0
    } else {
1439
0
      ZEND_ASSERT(!(op_array->fn_flags & ZEND_ACC_IMMUTABLE));
1440
0
      ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
1441
0
    }
1442
0
    if (op_array->static_variables) {
1443
0
      ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
1444
0
    }
1445
0
  } else {
1446
0
    op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
1447
0
    ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, NULL);
1448
0
    ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
1449
0
  }
1450
1451
  /* Check whether this op_array has already been unserialized. */
1452
0
  if (IS_UNSERIALIZED(op_array->opcodes)) {
1453
0
    ZEND_ASSERT(op_array->scope && "Only method op_arrays should be shared");
1454
0
    return;
1455
0
  }
1456
1457
0
  if (op_array->refcount) {
1458
0
    op_array->refcount = NULL;
1459
0
    UNSERIALIZE_PTR(op_array->static_variables);
1460
0
    UNSERIALIZE_PTR(op_array->literals);
1461
0
    UNSERIALIZE_PTR(op_array->opcodes);
1462
0
    UNSERIALIZE_PTR(op_array->arg_info);
1463
0
    UNSERIALIZE_PTR(op_array->vars);
1464
0
    UNSERIALIZE_STR(op_array->function_name);
1465
0
    UNSERIALIZE_STR(op_array->filename);
1466
0
    UNSERIALIZE_PTR(op_array->live_range);
1467
0
    UNSERIALIZE_PTR(op_array->scope);
1468
0
    UNSERIALIZE_STR(op_array->doc_comment);
1469
0
    UNSERIALIZE_ATTRIBUTES(op_array->attributes);
1470
0
    UNSERIALIZE_PTR(op_array->try_catch_array);
1471
0
    UNSERIALIZE_PTR(op_array->prototype);
1472
0
    UNSERIALIZE_PTR(op_array->prop_info);
1473
0
    return;
1474
0
  }
1475
1476
0
  if (op_array->static_variables) {
1477
0
    HashTable *ht;
1478
1479
0
    UNSERIALIZE_PTR(op_array->static_variables);
1480
0
    ht = op_array->static_variables;
1481
0
    zend_file_cache_unserialize_hash(ht,
1482
0
        script, buf, zend_file_cache_unserialize_zval, ZVAL_PTR_DTOR);
1483
0
  }
1484
1485
0
  if (op_array->literals) {
1486
0
    zval *p, *end;
1487
1488
0
    UNSERIALIZE_PTR(op_array->literals);
1489
0
    p = op_array->literals;
1490
0
    end = p + op_array->last_literal;
1491
0
    while (p < end) {
1492
0
      zend_file_cache_unserialize_zval(p, script, buf);
1493
0
      p++;
1494
0
    }
1495
0
  }
1496
1497
0
  {
1498
0
    zend_op *opline, *end;
1499
1500
0
    UNSERIALIZE_PTR(op_array->opcodes);
1501
0
    opline = op_array->opcodes;
1502
0
    end = opline + op_array->last;
1503
0
    while (opline < end) {
1504
#if ZEND_USE_ABS_CONST_ADDR
1505
      if (opline->op1_type == IS_CONST) {
1506
        UNSERIALIZE_PTR(opline->op1.zv);
1507
      }
1508
      if (opline->op2_type == IS_CONST) {
1509
        UNSERIALIZE_PTR(opline->op2.zv);
1510
      }
1511
#else
1512
0
      if (opline->op1_type == IS_CONST) {
1513
0
        ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op1);
1514
0
      }
1515
0
      if (opline->op2_type == IS_CONST) {
1516
0
        ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2);
1517
0
      }
1518
0
#endif
1519
#if ZEND_USE_ABS_JMP_ADDR
1520
      switch (opline->opcode) {
1521
        case ZEND_JMP:
1522
        case ZEND_FAST_CALL:
1523
          UNSERIALIZE_PTR(opline->op1.jmp_addr);
1524
          break;
1525
        case ZEND_JMPZ:
1526
        case ZEND_JMPNZ:
1527
        case ZEND_JMPZ_EX:
1528
        case ZEND_JMPNZ_EX:
1529
        case ZEND_JMP_SET:
1530
        case ZEND_COALESCE:
1531
        case ZEND_FE_RESET_R:
1532
        case ZEND_FE_RESET_RW:
1533
        case ZEND_ASSERT_CHECK:
1534
        case ZEND_JMP_NULL:
1535
        case ZEND_BIND_INIT_STATIC_OR_JMP:
1536
        case ZEND_JMP_FRAMELESS:
1537
          UNSERIALIZE_PTR(opline->op2.jmp_addr);
1538
          break;
1539
        case ZEND_CATCH:
1540
          if (!(opline->extended_value & ZEND_LAST_CATCH)) {
1541
            UNSERIALIZE_PTR(opline->op2.jmp_addr);
1542
          }
1543
          break;
1544
        case ZEND_FE_FETCH_R:
1545
        case ZEND_FE_FETCH_RW:
1546
        case ZEND_SWITCH_LONG:
1547
        case ZEND_SWITCH_STRING:
1548
          /* relative extended_value don't have to be changed */
1549
          break;
1550
      }
1551
#endif
1552
1553
0
      if (opline->opcode == ZEND_OP_DATA
1554
0
        && (opline-1)->opcode == ZEND_DECLARE_ATTRIBUTED_CONST
1555
0
      ) {
1556
0
        zval *literal = RT_CONSTANT(opline, opline->op1);
1557
0
        UNSERIALIZE_ATTRIBUTES(Z_PTR_P(literal));
1558
0
      }
1559
1560
0
      if (opline->opcode == ZEND_CALLABLE_CONVERT_PARTIAL) {
1561
0
        if (script->corrupted) {
1562
0
          opline->extended_value &= ~ZEND_PARTIAL_CACHEABLE_IN_SHM;
1563
0
        }
1564
0
      }
1565
1566
0
      zend_deserialize_opcode_handler(opline);
1567
0
      opline++;
1568
0
    }
1569
1570
0
    UNSERIALIZE_PTR(op_array->scope);
1571
1572
0
    if (op_array->arg_info) {
1573
0
      zend_arg_info *p, *end;
1574
0
      UNSERIALIZE_PTR(op_array->arg_info);
1575
0
      p = op_array->arg_info;
1576
0
      end = p + op_array->num_args;
1577
0
      if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
1578
0
        p--;
1579
0
      }
1580
0
      if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
1581
0
        end++;
1582
0
      }
1583
0
      while (p < end) {
1584
0
        if (!IS_UNSERIALIZED(p->name)) {
1585
0
          UNSERIALIZE_STR(p->name);
1586
0
        }
1587
0
        zend_file_cache_unserialize_type(&p->type, (op_array->fn_flags & ZEND_ACC_CLOSURE) ? NULL : op_array->scope, script, buf);
1588
0
        UNSERIALIZE_STR(p->doc_comment);
1589
0
        p++;
1590
0
      }
1591
0
    }
1592
1593
0
    if (op_array->vars) {
1594
0
      zend_string **p, **end;
1595
1596
0
      UNSERIALIZE_PTR(op_array->vars);
1597
0
      p = op_array->vars;
1598
0
      end = p + op_array->last_var;
1599
0
      while (p < end) {
1600
0
        if (!IS_UNSERIALIZED(*p)) {
1601
0
          UNSERIALIZE_STR(*p);
1602
0
        }
1603
0
        p++;
1604
0
      }
1605
0
    }
1606
1607
0
    if (op_array->num_dynamic_func_defs) {
1608
0
      UNSERIALIZE_PTR(op_array->dynamic_func_defs);
1609
0
      for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
1610
0
        UNSERIALIZE_PTR(op_array->dynamic_func_defs[i]);
1611
0
        zend_file_cache_unserialize_op_array(op_array->dynamic_func_defs[i], script, buf);
1612
0
      }
1613
0
    }
1614
1615
0
    UNSERIALIZE_STR(op_array->function_name);
1616
0
    UNSERIALIZE_STR(op_array->filename);
1617
0
    UNSERIALIZE_PTR(op_array->live_range);
1618
0
    UNSERIALIZE_STR(op_array->doc_comment);
1619
0
    UNSERIALIZE_ATTRIBUTES(op_array->attributes);
1620
0
    UNSERIALIZE_PTR(op_array->try_catch_array);
1621
0
    UNSERIALIZE_PTR(op_array->prototype);
1622
0
    UNSERIALIZE_PTR(op_array->prop_info);
1623
0
  }
1624
0
}
1625
1626
static void zend_file_cache_unserialize_func(zval                    *zv,
1627
                                             zend_persistent_script  *script,
1628
                                             void                    *buf)
1629
0
{
1630
0
  zend_function *func;
1631
0
  UNSERIALIZE_PTR(Z_PTR_P(zv));
1632
0
  func = Z_PTR_P(zv);
1633
0
  ZEND_ASSERT(func->type == ZEND_USER_FUNCTION);
1634
0
  zend_file_cache_unserialize_op_array(&func->op_array, script, buf);
1635
0
}
1636
1637
static void zend_file_cache_unserialize_prop_info(zval                    *zv,
1638
                                                  zend_persistent_script  *script,
1639
                                                  void                    *buf)
1640
0
{
1641
0
  if (!IS_UNSERIALIZED(Z_PTR_P(zv))) {
1642
0
    zend_property_info *prop;
1643
1644
0
    UNSERIALIZE_PTR(Z_PTR_P(zv));
1645
0
    prop = Z_PTR_P(zv);
1646
1647
0
    ZEND_ASSERT(prop->ce != NULL && prop->name != NULL);
1648
0
    if (!IS_UNSERIALIZED(prop->ce)) {
1649
0
      UNSERIALIZE_PTR(prop->ce);
1650
0
      UNSERIALIZE_STR(prop->name);
1651
0
      if (prop->doc_comment) {
1652
0
        UNSERIALIZE_STR(prop->doc_comment);
1653
0
      }
1654
0
      UNSERIALIZE_ATTRIBUTES(prop->attributes);
1655
0
      UNSERIALIZE_PTR(prop->prototype);
1656
0
      if (prop->hooks) {
1657
0
        UNSERIALIZE_PTR(prop->hooks);
1658
0
        for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1659
0
          if (prop->hooks[i]) {
1660
0
            UNSERIALIZE_PTR(prop->hooks[i]);
1661
0
            zend_file_cache_unserialize_op_array(&prop->hooks[i]->op_array, script, buf);
1662
0
          }
1663
0
        }
1664
0
      }
1665
0
      zend_file_cache_unserialize_type(&prop->type, prop->ce, script, buf);
1666
0
    }
1667
0
  }
1668
0
}
1669
1670
static void zend_file_cache_unserialize_class_constant(zval                    *zv,
1671
                                                       zend_persistent_script  *script,
1672
                                                       void                    *buf)
1673
0
{
1674
0
  if (!IS_UNSERIALIZED(Z_PTR_P(zv))) {
1675
0
    zend_class_constant *c;
1676
1677
0
    UNSERIALIZE_PTR(Z_PTR_P(zv));
1678
0
    c = Z_PTR_P(zv);
1679
1680
0
    ZEND_ASSERT(c->ce != NULL);
1681
0
    if (!IS_UNSERIALIZED(c->ce)) {
1682
0
      UNSERIALIZE_PTR(c->ce);
1683
1684
0
      zend_file_cache_unserialize_zval(&c->value, script, buf);
1685
1686
0
      if (c->doc_comment) {
1687
0
        UNSERIALIZE_STR(c->doc_comment);
1688
0
      }
1689
0
      UNSERIALIZE_ATTRIBUTES(c->attributes);
1690
0
      zend_file_cache_unserialize_type(&c->type, c->ce, script, buf);
1691
0
    }
1692
0
  }
1693
0
}
1694
1695
static void zend_file_cache_unserialize_class(zval                    *zv,
1696
                                              zend_persistent_script  *script,
1697
                                              void                    *buf)
1698
0
{
1699
0
  zend_class_entry *ce;
1700
1701
0
  UNSERIALIZE_PTR(Z_PTR_P(zv));
1702
0
  ce = Z_PTR_P(zv);
1703
1704
0
  UNSERIALIZE_STR(ce->name);
1705
0
  if (!(ce->ce_flags & ZEND_ACC_ANON_CLASS)) {
1706
0
    if (!script->corrupted) {
1707
0
      zend_accel_get_class_name_map_ptr(ce->name);
1708
0
    } else {
1709
0
      zend_alloc_ce_cache(ce->name);
1710
0
    }
1711
0
  }
1712
0
  if (ce->parent) {
1713
0
    if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
1714
0
      UNSERIALIZE_STR(ce->parent_name);
1715
0
    } else {
1716
0
      UNSERIALIZE_PTR(ce->parent);
1717
0
    }
1718
0
  }
1719
0
  zend_file_cache_unserialize_hash(&ce->function_table,
1720
0
      script, buf, zend_file_cache_unserialize_func, ZEND_FUNCTION_DTOR);
1721
0
  if (ce->default_properties_table) {
1722
0
    zval *p, *end;
1723
1724
0
    UNSERIALIZE_PTR(ce->default_properties_table);
1725
0
    p = ce->default_properties_table;
1726
0
    end = p + ce->default_properties_count;
1727
0
    while (p < end) {
1728
0
      zend_file_cache_unserialize_zval(p, script, buf);
1729
0
      p++;
1730
0
    }
1731
0
  }
1732
0
  if (ce->default_static_members_table) {
1733
0
    zval *p, *end;
1734
0
    UNSERIALIZE_PTR(ce->default_static_members_table);
1735
0
    p = ce->default_static_members_table;
1736
0
    end = p + ce->default_static_members_count;
1737
0
    while (p < end) {
1738
0
      zend_file_cache_unserialize_zval(p, script, buf);
1739
0
      p++;
1740
0
    }
1741
0
  }
1742
0
  zend_file_cache_unserialize_hash(&ce->constants_table,
1743
0
      script, buf, zend_file_cache_unserialize_class_constant, NULL);
1744
0
  UNSERIALIZE_STR(ce->info.user.filename);
1745
0
  UNSERIALIZE_STR(ce->doc_comment);
1746
0
  UNSERIALIZE_ATTRIBUTES(ce->attributes);
1747
0
  zend_file_cache_unserialize_hash(&ce->properties_info,
1748
0
      script, buf, zend_file_cache_unserialize_prop_info, NULL);
1749
1750
0
  if (ce->properties_info_table) {
1751
0
    uint32_t i;
1752
0
    UNSERIALIZE_PTR(ce->properties_info_table);
1753
1754
0
    for (i = 0; i < ce->default_properties_count; i++) {
1755
0
      UNSERIALIZE_PTR(ce->properties_info_table[i]);
1756
0
    }
1757
0
  }
1758
1759
0
  if (ce->num_interfaces) {
1760
0
    uint32_t i;
1761
1762
0
    ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
1763
0
    UNSERIALIZE_PTR(ce->interface_names);
1764
1765
0
    for (i = 0; i < ce->num_interfaces; i++) {
1766
0
      UNSERIALIZE_STR(ce->interface_names[i].name);
1767
0
      UNSERIALIZE_STR(ce->interface_names[i].lc_name);
1768
0
    }
1769
0
  }
1770
1771
0
  if (ce->num_traits) {
1772
0
    uint32_t i;
1773
1774
0
    UNSERIALIZE_PTR(ce->trait_names);
1775
1776
0
    for (i = 0; i < ce->num_traits; i++) {
1777
0
      UNSERIALIZE_STR(ce->trait_names[i].name);
1778
0
      UNSERIALIZE_STR(ce->trait_names[i].lc_name);
1779
0
    }
1780
1781
0
    if (ce->trait_aliases) {
1782
0
      zend_trait_alias **p, *q;
1783
1784
0
      UNSERIALIZE_PTR(ce->trait_aliases);
1785
0
      p = ce->trait_aliases;
1786
1787
0
      while (*p) {
1788
0
        UNSERIALIZE_PTR(*p);
1789
0
        q = *p;
1790
1791
0
        if (q->trait_method.method_name) {
1792
0
          UNSERIALIZE_STR(q->trait_method.method_name);
1793
0
        }
1794
0
        if (q->trait_method.class_name) {
1795
0
          UNSERIALIZE_STR(q->trait_method.class_name);
1796
0
        }
1797
1798
0
        if (q->alias) {
1799
0
          UNSERIALIZE_STR(q->alias);
1800
0
        }
1801
0
        p++;
1802
0
      }
1803
0
    }
1804
1805
0
    if (ce->trait_precedences) {
1806
0
      zend_trait_precedence **p, *q;
1807
0
      uint32_t j;
1808
1809
0
      UNSERIALIZE_PTR(ce->trait_precedences);
1810
0
      p = ce->trait_precedences;
1811
1812
0
      while (*p) {
1813
0
        UNSERIALIZE_PTR(*p);
1814
0
        q = *p;
1815
1816
0
        if (q->trait_method.method_name) {
1817
0
          UNSERIALIZE_STR(q->trait_method.method_name);
1818
0
        }
1819
0
        if (q->trait_method.class_name) {
1820
0
          UNSERIALIZE_STR(q->trait_method.class_name);
1821
0
        }
1822
1823
0
        for (j = 0; j < q->num_excludes; j++) {
1824
0
          UNSERIALIZE_STR(q->exclude_class_names[j]);
1825
0
        }
1826
0
        p++;
1827
0
      }
1828
0
    }
1829
0
  }
1830
1831
0
  UNSERIALIZE_PTR(ce->constructor);
1832
0
  UNSERIALIZE_PTR(ce->destructor);
1833
0
  UNSERIALIZE_PTR(ce->clone);
1834
0
  UNSERIALIZE_PTR(ce->__get);
1835
0
  UNSERIALIZE_PTR(ce->__set);
1836
0
  UNSERIALIZE_PTR(ce->__call);
1837
0
  UNSERIALIZE_PTR(ce->__serialize);
1838
0
  UNSERIALIZE_PTR(ce->__unserialize);
1839
0
  UNSERIALIZE_PTR(ce->__isset);
1840
0
  UNSERIALIZE_PTR(ce->__unset);
1841
0
  UNSERIALIZE_PTR(ce->__tostring);
1842
0
  UNSERIALIZE_PTR(ce->__callstatic);
1843
0
  UNSERIALIZE_PTR(ce->__debugInfo);
1844
1845
0
  if (ce->iterator_funcs_ptr) {
1846
0
    UNSERIALIZE_PTR(ce->iterator_funcs_ptr);
1847
0
    UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_new_iterator);
1848
0
    UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_rewind);
1849
0
    UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_valid);
1850
0
    UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_key);
1851
0
    UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_current);
1852
0
    UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_next);
1853
0
  }
1854
0
  if (ce->arrayaccess_funcs_ptr) {
1855
0
    UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr);
1856
0
    UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetget);
1857
0
    UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetexists);
1858
0
    UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetset);
1859
0
    UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetunset);
1860
0
  }
1861
1862
0
  if (!(script->corrupted)) {
1863
0
    ce->ce_flags |= ZEND_ACC_IMMUTABLE;
1864
0
    ce->ce_flags &= ~ZEND_ACC_FILE_CACHED;
1865
0
    ZEND_MAP_PTR_NEW(ce->mutable_data);
1866
0
    if (ce->default_static_members_count) {
1867
0
      ZEND_MAP_PTR_NEW(ce->static_members_table);
1868
0
    }
1869
0
  } else {
1870
0
    ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
1871
0
    ce->ce_flags |= ZEND_ACC_FILE_CACHED;
1872
0
    ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
1873
0
    ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
1874
0
  }
1875
1876
0
  if (ce->get_iterator) {
1877
0
    ZEND_ASSERT(ce->get_iterator == HOOKED_ITERATOR_PLACEHOLDER);
1878
0
    ce->get_iterator = zend_hooked_object_get_iterator;
1879
0
  }
1880
1881
  // Memory addresses of object handlers are not stable. They can change due to ASLR or order of linking dynamic. To
1882
  // avoid pointing to invalid memory we relink default_object_handlers here.
1883
0
  ce->default_object_handlers = ce->ce_flags & ZEND_ACC_ENUM ? &zend_enum_object_handlers : &std_object_handlers;
1884
0
}
1885
1886
static void zend_file_cache_unserialize_warnings(zend_persistent_script *script, void *buf)
1887
0
{
1888
0
  if (script->warnings) {
1889
0
    UNSERIALIZE_PTR(script->warnings);
1890
0
    for (uint32_t i = 0; i < script->num_warnings; i++) {
1891
0
      UNSERIALIZE_PTR(script->warnings[i]);
1892
0
      UNSERIALIZE_STR(script->warnings[i]->filename);
1893
0
      UNSERIALIZE_STR(script->warnings[i]->message);
1894
0
    }
1895
0
  }
1896
0
}
1897
1898
static void zend_file_cache_unserialize_early_bindings(zend_persistent_script *script, void *buf)
1899
0
{
1900
0
  if (script->early_bindings) {
1901
0
    UNSERIALIZE_PTR(script->early_bindings);
1902
0
    for (uint32_t i = 0; i < script->num_early_bindings; i++) {
1903
0
      UNSERIALIZE_STR(script->early_bindings[i].lcname);
1904
0
      UNSERIALIZE_STR(script->early_bindings[i].rtd_key);
1905
0
      UNSERIALIZE_STR(script->early_bindings[i].lc_parent_name);
1906
0
    }
1907
0
  }
1908
0
}
1909
1910
static void zend_file_cache_unserialize(zend_persistent_script  *script,
1911
                                        void                    *buf)
1912
0
{
1913
0
  script->mem = buf;
1914
1915
0
  UNSERIALIZE_STR(script->script.filename);
1916
1917
0
  zend_file_cache_unserialize_hash(&script->script.class_table,
1918
0
      script, buf, zend_file_cache_unserialize_class, ZEND_CLASS_DTOR);
1919
0
  zend_file_cache_unserialize_hash(&script->script.function_table,
1920
0
      script, buf, zend_file_cache_unserialize_func, ZEND_FUNCTION_DTOR);
1921
0
  zend_file_cache_unserialize_op_array(&script->script.main_op_array, script, buf);
1922
0
  zend_file_cache_unserialize_warnings(script, buf);
1923
0
  zend_file_cache_unserialize_early_bindings(script, buf);
1924
0
}
1925
1926
static zend_persistent_script file_cache_validate_success_script;
1927
1928
zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handle)
1929
0
{
1930
0
  return zend_file_cache_script_load_ex(file_handle, false);
1931
0
}
1932
1933
zend_persistent_script *zend_file_cache_script_load_ex(zend_file_handle *file_handle, bool validate_only)
1934
0
{
1935
0
  zend_string *full_path = file_handle->opened_path;
1936
0
  int fd;
1937
0
  char *filename;
1938
0
  zend_persistent_script *script;
1939
0
  zend_file_cache_metainfo info;
1940
0
  zend_accel_hash_entry *bucket;
1941
0
  void *mem, *checkpoint, *buf;
1942
0
  bool cache_it = true;
1943
0
  unsigned int actual_checksum;
1944
0
  bool ok;
1945
1946
0
  if (!full_path) {
1947
0
    return NULL;
1948
0
  }
1949
0
  filename = zend_file_cache_get_bin_file_path(full_path);
1950
1951
0
  fd = zend_file_cache_open(filename, O_RDONLY | O_BINARY);
1952
0
  if (fd < 0) {
1953
0
    efree(filename);
1954
0
    return NULL;
1955
0
  }
1956
1957
0
  if (zend_file_cache_flock(fd, LOCK_SH) != 0) {
1958
0
    close(fd);
1959
0
    efree(filename);
1960
0
    return NULL;
1961
0
  }
1962
1963
0
  if (read(fd, &info, sizeof(info)) != sizeof(info)) {
1964
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (info)\n", filename);
1965
0
    zend_file_cache_flock(fd, LOCK_UN);
1966
0
    close(fd);
1967
0
    if (!ZCG(accel_directives).file_cache_read_only) {
1968
0
      zend_file_cache_unlink(filename);
1969
0
    }
1970
0
    efree(filename);
1971
0
    return NULL;
1972
0
  }
1973
1974
  /* verify header */
1975
0
  if (memcmp(info.magic, "OPCACHE", 8) != 0) {
1976
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (wrong header)\n", filename);
1977
0
    zend_file_cache_flock(fd, LOCK_UN);
1978
0
    close(fd);
1979
0
    if (!ZCG(accel_directives).file_cache_read_only) {
1980
0
      zend_file_cache_unlink(filename);
1981
0
    }
1982
0
    efree(filename);
1983
0
    return NULL;
1984
0
  }
1985
0
  if (memcmp(info.system_id, zend_system_id, 32) != 0) {
1986
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (wrong \"system_id\")\n", filename);
1987
0
    zend_file_cache_flock(fd, LOCK_UN);
1988
0
    close(fd);
1989
0
    if (!ZCG(accel_directives).file_cache_read_only) {
1990
0
      zend_file_cache_unlink(filename);
1991
0
    }
1992
0
    efree(filename);
1993
0
    return NULL;
1994
0
  }
1995
1996
  /* verify timestamp */
1997
0
  if (ZCG(accel_directives).validate_timestamps &&
1998
0
      zend_get_file_handle_timestamp(file_handle, NULL) != info.timestamp) {
1999
0
    if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
2000
0
      zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
2001
0
    }
2002
0
    close(fd);
2003
0
    if (!ZCG(accel_directives).file_cache_read_only) {
2004
0
      zend_file_cache_unlink(filename);
2005
0
    }
2006
0
    efree(filename);
2007
0
    return NULL;
2008
0
  }
2009
2010
  /* return here if validating */
2011
0
  if (validate_only) {
2012
0
    if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
2013
0
      zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
2014
0
    }
2015
0
    close(fd);
2016
0
    efree(filename);
2017
0
    return &file_cache_validate_success_script;
2018
0
  }
2019
2020
0
  checkpoint = zend_arena_checkpoint(CG(arena));
2021
0
#if defined(__AVX__) || defined(__SSE2__)
2022
  /* Align to 64-byte boundary */
2023
0
  mem = zend_arena_alloc(&CG(arena), info.mem_size + info.str_size + 64);
2024
0
  mem = (void*)(((uintptr_t)mem + 63L) & ~63L);
2025
#else
2026
  mem = zend_arena_alloc(&CG(arena), info.mem_size + info.str_size);
2027
#endif
2028
2029
0
  if (read(fd, mem, info.mem_size + info.str_size) != (ssize_t)(info.mem_size + info.str_size)) {
2030
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (mem)\n", filename);
2031
0
    zend_file_cache_flock(fd, LOCK_UN);
2032
0
    close(fd);
2033
0
    if (!ZCG(accel_directives).file_cache_read_only) {
2034
0
      zend_file_cache_unlink(filename);
2035
0
    }
2036
0
    zend_arena_release(&CG(arena), checkpoint);
2037
0
    efree(filename);
2038
0
    return NULL;
2039
0
  }
2040
0
  if (zend_file_cache_flock(fd, LOCK_UN) != 0) {
2041
0
    zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename);
2042
0
  }
2043
0
  close(fd);
2044
2045
  /* verify checksum */
2046
0
  if (ZCG(accel_directives).file_cache_consistency_checks &&
2047
0
      (actual_checksum = zend_adler32(ADLER32_INIT, mem, info.mem_size + info.str_size)) != info.checksum) {
2048
0
    zend_accel_error(ACCEL_LOG_WARNING, "corrupted file '%s' excepted checksum: 0x%08x actual checksum: 0x%08x\n", filename, info.checksum, actual_checksum);
2049
0
    if (!ZCG(accel_directives).file_cache_read_only) {
2050
0
      zend_file_cache_unlink(filename);
2051
0
    }
2052
0
    zend_arena_release(&CG(arena), checkpoint);
2053
0
    efree(filename);
2054
0
    return NULL;
2055
0
  }
2056
2057
0
  if (!file_cache_only &&
2058
0
      !ZCSG(restart_in_progress) &&
2059
0
      !ZCSG(restart_pending) &&
2060
0
    !ZSMMG(memory_exhausted) &&
2061
0
      accelerator_shm_read_lock() == SUCCESS) {
2062
    /* exclusive lock */
2063
0
    zend_shared_alloc_lock();
2064
2065
    /* Check if we still need to put the file into the cache (may be it was
2066
     * already stored by another process. This final check is done under
2067
     * exclusive lock) */
2068
0
    bucket = zend_accel_hash_find_entry(&ZCSG(hash), full_path);
2069
0
    if (bucket) {
2070
0
      script = (zend_persistent_script *)bucket->data;
2071
0
      if (!script->corrupted) {
2072
0
        zend_shared_alloc_unlock();
2073
0
        zend_arena_release(&CG(arena), checkpoint);
2074
0
        efree(filename);
2075
0
        return script;
2076
0
      }
2077
0
    }
2078
2079
0
    if (zend_accel_hash_is_full(&ZCSG(hash))) {
2080
0
      zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
2081
0
      ZSMMG(memory_exhausted) = 1;
2082
0
      zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
2083
0
      zend_shared_alloc_unlock();
2084
0
      goto use_process_mem;
2085
0
    }
2086
2087
0
    buf = zend_shared_alloc_aligned(info.mem_size);
2088
2089
0
    if (!buf) {
2090
0
      zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
2091
0
      zend_shared_alloc_unlock();
2092
0
      goto use_process_mem;
2093
0
    }
2094
0
    memcpy(buf, mem, info.mem_size);
2095
0
    zend_map_ptr_extend(ZCSG(map_ptr_last));
2096
0
  } else {
2097
0
use_process_mem:
2098
0
    buf = mem;
2099
0
    cache_it = false;
2100
0
  }
2101
2102
0
  ZCG(mem) = ((char*)mem + info.mem_size);
2103
0
  script = (zend_persistent_script*)((char*)buf + info.script_offset);
2104
0
  script->corrupted = !cache_it; /* used to check if script restored to SHM or process memory */
2105
2106
0
  ok = true;
2107
0
  zend_try {
2108
0
    zend_file_cache_unserialize(script, buf);
2109
0
  } zend_catch {
2110
0
    ok = false;
2111
0
  } zend_end_try();
2112
0
  if (!ok) {
2113
0
    if (cache_it) {
2114
0
      zend_shared_alloc_unlock();
2115
0
      goto use_process_mem;
2116
0
    } else {
2117
0
      zend_arena_release(&CG(arena), checkpoint);
2118
0
      efree(filename);
2119
0
      return NULL;
2120
0
    }
2121
0
  }
2122
2123
0
  script->corrupted = false;
2124
2125
0
  if (cache_it) {
2126
0
    ZCSG(map_ptr_last) = CG(map_ptr_last);
2127
0
    script->dynamic_members.last_used = ZCG(request_time);
2128
2129
0
    zend_accel_hash_update(&ZCSG(hash), script->script.filename, 0, script);
2130
2131
0
    zend_shared_alloc_unlock();
2132
0
    zend_accel_error(ACCEL_LOG_INFO, "File cached script loaded into memory '%s'", ZSTR_VAL(script->script.filename));
2133
2134
0
    zend_arena_release(&CG(arena), checkpoint);
2135
0
  }
2136
0
  efree(filename);
2137
2138
0
  return script;
2139
0
}
2140
2141
void zend_file_cache_invalidate(zend_string *full_path)
2142
0
{
2143
0
  if (ZCG(accel_directives).file_cache_read_only) {
2144
0
    return;
2145
0
  }
2146
2147
0
  char *filename;
2148
2149
0
  filename = zend_file_cache_get_bin_file_path(full_path);
2150
2151
0
  zend_file_cache_unlink(filename);
2152
  efree(filename);
2153
0
}