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