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