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