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