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