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