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