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