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