xref: /php-src/ext/opcache/zend_file_cache.c (revision f2e199e8)
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