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: Andi Gutmans <andi@php.net> |
16 | Zeev Suraski <zeev@php.net> |
17 | Stanislav Malyshev <stas@zend.com> |
18 | Dmitry Stogov <dmitry@php.net> |
19 +----------------------------------------------------------------------+
20 */
21
22 #include "zend.h"
23 #include "ZendAccelerator.h"
24 #include "zend_persist.h"
25 #include "zend_extensions.h"
26 #include "zend_shared_alloc.h"
27 #include "zend_vm.h"
28 #include "zend_constants.h"
29 #include "zend_operators.h"
30 #include "zend_interfaces.h"
31 #include "zend_attributes.h"
32
33 #ifdef HAVE_JIT
34 # include "Optimizer/zend_func_info.h"
35 # include "jit/zend_jit.h"
36 #endif
37
38 #define zend_set_str_gc_flags(str) do { \
39 GC_SET_REFCOUNT(str, 2); \
40 uint32_t flags = GC_STRING | (ZSTR_IS_VALID_UTF8(str) ? IS_STR_VALID_UTF8 : 0); \
41 if (file_cache_only \
42 || (ZCG(current_persistent_script) && ZCG(current_persistent_script)->corrupted)) { \
43 GC_TYPE_INFO(str) = GC_STRING | (IS_STR_INTERNED << GC_FLAGS_SHIFT); \
44 flags |= (IS_STR_INTERNED << GC_FLAGS_SHIFT); \
45 } else { \
46 flags |= ((IS_STR_INTERNED | IS_STR_PERMANENT) << GC_FLAGS_SHIFT); \
47 } \
48 GC_TYPE_INFO(str) = flags; \
49 } while (0)
50
51 #define zend_accel_store_string(str) do { \
52 zend_string *new_str = zend_shared_alloc_get_xlat_entry(str); \
53 if (new_str) { \
54 zend_string_release_ex(str, 0); \
55 str = new_str; \
56 } else { \
57 new_str = zend_shared_memdup_put((void*)str, _ZSTR_STRUCT_SIZE(ZSTR_LEN(str))); \
58 zend_string_release_ex(str, 0); \
59 str = new_str; \
60 zend_string_hash_val(str); \
61 zend_set_str_gc_flags(str); \
62 } \
63 } while (0)
64 #define zend_accel_memdup_string(str) do { \
65 zend_string *new_str = zend_shared_alloc_get_xlat_entry(str); \
66 if (new_str) { \
67 str = new_str; \
68 } else { \
69 new_str = zend_shared_memdup_put((void*)str, _ZSTR_STRUCT_SIZE(ZSTR_LEN(str))); \
70 str = new_str; \
71 zend_string_hash_val(str); \
72 zend_set_str_gc_flags(str); \
73 } \
74 } while (0)
75 #define zend_accel_store_interned_string(str) do { \
76 if (!IS_ACCEL_INTERNED(str)) { \
77 zend_accel_store_string(str); \
78 } \
79 } while (0)
80 #define zend_accel_memdup_interned_string(str) do { \
81 if (!IS_ACCEL_INTERNED(str)) { \
82 zend_accel_memdup_string(str); \
83 } \
84 } while (0)
85
86 typedef void (*zend_persist_func_t)(zval*);
87
88 static void zend_persist_zval(zval *z);
89 static void zend_persist_op_array(zval *zv);
90
91 static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
92 {HT_INVALID_IDX, HT_INVALID_IDX};
93
zend_hash_persist(HashTable * ht)94 static void zend_hash_persist(HashTable *ht)
95 {
96 uint32_t idx, nIndex;
97 Bucket *p;
98
99 HT_FLAGS(ht) |= HASH_FLAG_STATIC_KEYS;
100 ht->pDestructor = NULL;
101 ht->nInternalPointer = 0;
102
103 if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
104 if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
105 HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
106 } else {
107 HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
108 }
109 return;
110 }
111 if (ht->nNumUsed == 0) {
112 efree(HT_GET_DATA_ADDR(ht));
113 ht->nTableMask = HT_MIN_MASK;
114 if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
115 HT_SET_DATA_ADDR(ht, &ZCSG(uninitialized_bucket));
116 } else {
117 HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
118 }
119 HT_FLAGS(ht) |= HASH_FLAG_UNINITIALIZED;
120 return;
121 }
122 if (HT_IS_PACKED(ht)) {
123 void *data = HT_GET_DATA_ADDR(ht);
124 if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) {
125 data = zend_shared_memdup(data, HT_PACKED_USED_SIZE(ht));
126 } else {
127 data = zend_shared_memdup_free(data, HT_PACKED_USED_SIZE(ht));
128 }
129 HT_SET_DATA_ADDR(ht, data);
130 } else if (ht->nNumUsed > HT_MIN_SIZE && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
131 /* compact table */
132 void *old_data = HT_GET_DATA_ADDR(ht);
133 Bucket *old_buckets = ht->arData;
134 uint32_t hash_size;
135
136 hash_size = (uint32_t)(-(int32_t)ht->nTableMask);
137 while (hash_size >> 2 > ht->nNumUsed) {
138 hash_size >>= 1;
139 }
140 ht->nTableMask = (uint32_t)(-(int32_t)hash_size);
141 ZEND_ASSERT(((uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
142 HT_SET_DATA_ADDR(ht, ZCG(mem));
143 ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE((hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket))));
144 HT_HASH_RESET(ht);
145 memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket));
146 if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
147 efree(old_data);
148 }
149
150 /* rehash */
151 for (idx = 0; idx < ht->nNumUsed; idx++) {
152 p = ht->arData + idx;
153 if (Z_TYPE(p->val) == IS_UNDEF) continue;
154 nIndex = p->h | ht->nTableMask;
155 Z_NEXT(p->val) = HT_HASH(ht, nIndex);
156 HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
157 }
158 } else {
159 void *data = ZCG(mem);
160 void *old_data = HT_GET_DATA_ADDR(ht);
161
162 ZEND_ASSERT(((uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
163 ZCG(mem) = (void*)((char*)data + ZEND_ALIGNED_SIZE(HT_USED_SIZE(ht)));
164 memcpy(data, old_data, HT_USED_SIZE(ht));
165 if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
166 efree(old_data);
167 }
168 HT_SET_DATA_ADDR(ht, data);
169 }
170 }
171
zend_persist_ast(zend_ast * ast)172 static zend_ast *zend_persist_ast(zend_ast *ast)
173 {
174 uint32_t i;
175 zend_ast *node;
176
177 if (ast->kind == ZEND_AST_ZVAL || ast->kind == ZEND_AST_CONSTANT) {
178 zend_ast_zval *copy = zend_shared_memdup(ast, sizeof(zend_ast_zval));
179 zend_persist_zval(©->val);
180 node = (zend_ast *) copy;
181 } else if (zend_ast_is_list(ast)) {
182 zend_ast_list *list = zend_ast_get_list(ast);
183 zend_ast_list *copy = zend_shared_memdup(ast,
184 sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * list->children);
185 for (i = 0; i < list->children; i++) {
186 if (copy->child[i]) {
187 copy->child[i] = zend_persist_ast(copy->child[i]);
188 }
189 }
190 node = (zend_ast *) copy;
191 } else {
192 uint32_t children = zend_ast_get_num_children(ast);
193 node = zend_shared_memdup(ast, zend_ast_size(children));
194 for (i = 0; i < children; i++) {
195 if (node->child[i]) {
196 node->child[i] = zend_persist_ast(node->child[i]);
197 }
198 }
199 }
200
201 return node;
202 }
203
zend_persist_zval(zval * z)204 static void zend_persist_zval(zval *z)
205 {
206 void *new_ptr;
207
208 switch (Z_TYPE_P(z)) {
209 case IS_STRING:
210 zend_accel_store_interned_string(Z_STR_P(z));
211 Z_TYPE_FLAGS_P(z) = 0;
212 break;
213 case IS_ARRAY:
214 new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z));
215 if (new_ptr) {
216 Z_ARR_P(z) = new_ptr;
217 Z_TYPE_FLAGS_P(z) = 0;
218 } else if (!ZCG(current_persistent_script)->corrupted
219 && zend_accel_in_shm(Z_ARR_P(z))) {
220 /* pass */
221 } else {
222 HashTable *ht;
223
224 if (!Z_REFCOUNTED_P(z)) {
225 ht = zend_shared_memdup_put(Z_ARR_P(z), sizeof(zend_array));
226 } else {
227 GC_REMOVE_FROM_BUFFER(Z_ARR_P(z));
228 ht = zend_shared_memdup_put_free(Z_ARR_P(z), sizeof(zend_array));
229 }
230 Z_ARR_P(z) = ht;
231 zend_hash_persist(ht);
232 if (HT_IS_PACKED(ht)) {
233 zval *zv;
234
235 ZEND_HASH_PACKED_FOREACH_VAL(ht, zv) {
236 zend_persist_zval(zv);
237 } ZEND_HASH_FOREACH_END();
238 } else {
239 Bucket *p;
240
241 ZEND_HASH_MAP_FOREACH_BUCKET(ht, p) {
242 if (p->key) {
243 zend_accel_store_interned_string(p->key);
244 }
245 zend_persist_zval(&p->val);
246 } ZEND_HASH_FOREACH_END();
247 }
248 /* make immutable array */
249 Z_TYPE_FLAGS_P(z) = 0;
250 GC_SET_REFCOUNT(Z_COUNTED_P(z), 2);
251 GC_ADD_FLAGS(Z_COUNTED_P(z), IS_ARRAY_IMMUTABLE);
252 }
253 break;
254 case IS_CONSTANT_AST:
255 new_ptr = zend_shared_alloc_get_xlat_entry(Z_AST_P(z));
256 if (new_ptr) {
257 Z_AST_P(z) = new_ptr;
258 Z_TYPE_FLAGS_P(z) = 0;
259 } else if (ZCG(current_persistent_script)->corrupted
260 || !zend_accel_in_shm(Z_AST_P(z))) {
261 zend_ast_ref *old_ref = Z_AST_P(z);
262 Z_AST_P(z) = zend_shared_memdup_put(Z_AST_P(z), sizeof(zend_ast_ref));
263 zend_persist_ast(GC_AST(old_ref));
264 Z_TYPE_FLAGS_P(z) = 0;
265 GC_SET_REFCOUNT(Z_COUNTED_P(z), 1);
266 GC_ADD_FLAGS(Z_COUNTED_P(z), GC_IMMUTABLE);
267 efree(old_ref);
268 }
269 break;
270 default:
271 ZEND_ASSERT(Z_TYPE_P(z) < IS_STRING);
272 break;
273 }
274 }
275
zend_persist_attributes(HashTable * attributes)276 static HashTable *zend_persist_attributes(HashTable *attributes)
277 {
278 uint32_t i;
279 zval *v;
280
281 if (!ZCG(current_persistent_script)->corrupted && zend_accel_in_shm(attributes)) {
282 return attributes;
283 }
284
285 /* Attributes for trait properties may be shared if preloading is used. */
286 HashTable *xlat = zend_shared_alloc_get_xlat_entry(attributes);
287 if (xlat) {
288 return xlat;
289 }
290
291 zend_hash_persist(attributes);
292
293 ZEND_HASH_PACKED_FOREACH_VAL(attributes, v) {
294 zend_attribute *attr = Z_PTR_P(v);
295 zend_attribute *copy = zend_shared_memdup_put_free(attr, ZEND_ATTRIBUTE_SIZE(attr->argc));
296
297 zend_accel_store_interned_string(copy->name);
298 zend_accel_store_interned_string(copy->lcname);
299
300 for (i = 0; i < copy->argc; i++) {
301 if (copy->args[i].name) {
302 zend_accel_store_interned_string(copy->args[i].name);
303 }
304 zend_persist_zval(©->args[i].value);
305 }
306
307 ZVAL_PTR(v, copy);
308 } ZEND_HASH_FOREACH_END();
309
310 HashTable *ptr = zend_shared_memdup_put_free(attributes, sizeof(HashTable));
311 GC_SET_REFCOUNT(ptr, 2);
312 GC_TYPE_INFO(ptr) = GC_ARRAY | ((IS_ARRAY_IMMUTABLE|GC_NOT_COLLECTABLE) << GC_FLAGS_SHIFT);
313
314 return ptr;
315 }
316
zend_accel_get_class_name_map_ptr(zend_string * type_name)317 uint32_t zend_accel_get_class_name_map_ptr(zend_string *type_name)
318 {
319 uint32_t ret;
320
321 if (zend_string_equals_literal_ci(type_name, "self") ||
322 zend_string_equals_literal_ci(type_name, "parent")) {
323 return 0;
324 }
325
326 /* We use type.name.gc.refcount to keep map_ptr of corresponding type */
327 if (ZSTR_HAS_CE_CACHE(type_name)) {
328 return GC_REFCOUNT(type_name);
329 }
330
331 if ((GC_FLAGS(type_name) & GC_IMMUTABLE)
332 && (GC_FLAGS(type_name) & IS_STR_PERMANENT)) {
333 do {
334 ret = ZEND_MAP_PTR_NEW_OFFSET();
335 } while (ret <= 2);
336 GC_SET_REFCOUNT(type_name, ret);
337 GC_ADD_FLAGS(type_name, IS_STR_CLASS_NAME_MAP_PTR);
338 return ret;
339 }
340
341 return 0;
342 }
343
zend_persist_type(zend_type * type)344 static void zend_persist_type(zend_type *type) {
345 if (ZEND_TYPE_HAS_LIST(*type)) {
346 zend_type_list *list = ZEND_TYPE_LIST(*type);
347 if (ZEND_TYPE_USES_ARENA(*type) || zend_accel_in_shm(list)) {
348 list = zend_shared_memdup_put(list, ZEND_TYPE_LIST_SIZE(list->num_types));
349 ZEND_TYPE_FULL_MASK(*type) &= ~_ZEND_TYPE_ARENA_BIT;
350 } else {
351 list = zend_shared_memdup_put_free(list, ZEND_TYPE_LIST_SIZE(list->num_types));
352 }
353 ZEND_TYPE_SET_PTR(*type, list);
354 }
355
356 zend_type *single_type;
357 ZEND_TYPE_FOREACH(*type, single_type) {
358 if (ZEND_TYPE_HAS_LIST(*single_type)) {
359 zend_persist_type(single_type);
360 continue;
361 }
362 if (ZEND_TYPE_HAS_NAME(*single_type)) {
363 zend_string *type_name = ZEND_TYPE_NAME(*single_type);
364 zend_accel_store_interned_string(type_name);
365 ZEND_TYPE_SET_PTR(*single_type, type_name);
366 if (!ZCG(current_persistent_script)->corrupted) {
367 zend_accel_get_class_name_map_ptr(type_name);
368 }
369 }
370 } ZEND_TYPE_FOREACH_END();
371 }
372
zend_persist_op_array_ex(zend_op_array * op_array,zend_persistent_script * main_persistent_script)373 static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_script* main_persistent_script)
374 {
375 zend_op *persist_ptr;
376 zval *orig_literals = NULL;
377
378 if (op_array->refcount && --(*op_array->refcount) == 0) {
379 efree(op_array->refcount);
380 }
381 op_array->refcount = NULL;
382
383 if (main_persistent_script) {
384 zend_execute_data *orig_execute_data = EG(current_execute_data);
385 zend_execute_data fake_execute_data;
386 zval *offset;
387
388 memset(&fake_execute_data, 0, sizeof(fake_execute_data));
389 fake_execute_data.func = (zend_function*)op_array;
390 EG(current_execute_data) = &fake_execute_data;
391 if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
392 main_persistent_script->compiler_halt_offset = Z_LVAL_P(offset);
393 }
394 EG(current_execute_data) = orig_execute_data;
395 }
396
397 if (op_array->function_name) {
398 zend_string *old_name = op_array->function_name;
399 zend_accel_store_interned_string(op_array->function_name);
400 /* Remember old function name, so it can be released multiple times if shared. */
401 if (op_array->function_name != old_name
402 && !zend_shared_alloc_get_xlat_entry(&op_array->function_name)) {
403 zend_shared_alloc_register_xlat_entry(&op_array->function_name, old_name);
404 }
405 }
406
407 if (op_array->scope) {
408 zend_class_entry *scope = zend_shared_alloc_get_xlat_entry(op_array->scope);
409
410 if (scope) {
411 op_array->scope = scope;
412 }
413
414 if (op_array->prototype) {
415 zend_function *ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype);
416
417 if (ptr) {
418 op_array->prototype = ptr;
419 }
420 }
421
422 persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
423 if (persist_ptr) {
424 op_array->opcodes = persist_ptr;
425 if (op_array->static_variables) {
426 op_array->static_variables = zend_shared_alloc_get_xlat_entry(op_array->static_variables);
427 ZEND_ASSERT(op_array->static_variables != NULL);
428 }
429 if (op_array->literals) {
430 op_array->literals = zend_shared_alloc_get_xlat_entry(op_array->literals);
431 ZEND_ASSERT(op_array->literals != NULL);
432 }
433 if (op_array->filename) {
434 op_array->filename = zend_shared_alloc_get_xlat_entry(op_array->filename);
435 ZEND_ASSERT(op_array->filename != NULL);
436 }
437 if (op_array->arg_info) {
438 zend_arg_info *arg_info = op_array->arg_info;
439 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
440 arg_info--;
441 }
442 arg_info = zend_shared_alloc_get_xlat_entry(arg_info);
443 ZEND_ASSERT(arg_info != NULL);
444 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
445 arg_info++;
446 }
447 op_array->arg_info = arg_info;
448 }
449 if (op_array->live_range) {
450 op_array->live_range = zend_shared_alloc_get_xlat_entry(op_array->live_range);
451 ZEND_ASSERT(op_array->live_range != NULL);
452 }
453 if (op_array->doc_comment) {
454 if (ZCG(accel_directives).save_comments) {
455 op_array->doc_comment = zend_shared_alloc_get_xlat_entry(op_array->doc_comment);
456 ZEND_ASSERT(op_array->doc_comment != NULL);
457 } else {
458 op_array->doc_comment = NULL;
459 }
460 }
461 if (op_array->attributes) {
462 op_array->attributes = zend_shared_alloc_get_xlat_entry(op_array->attributes);
463 ZEND_ASSERT(op_array->attributes != NULL);
464 }
465
466 if (op_array->try_catch_array) {
467 op_array->try_catch_array = zend_shared_alloc_get_xlat_entry(op_array->try_catch_array);
468 ZEND_ASSERT(op_array->try_catch_array != NULL);
469 }
470 if (op_array->vars) {
471 op_array->vars = zend_shared_alloc_get_xlat_entry(op_array->vars);
472 ZEND_ASSERT(op_array->vars != NULL);
473 }
474 if (op_array->dynamic_func_defs) {
475 op_array->dynamic_func_defs = zend_shared_alloc_get_xlat_entry(op_array->dynamic_func_defs);
476 ZEND_ASSERT(op_array->dynamic_func_defs != NULL);
477 }
478 ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist(op_array, ZCG(mem))));
479 return;
480 }
481 } else {
482 /* "prototype" may be undefined if "scope" isn't set */
483 op_array->prototype = NULL;
484 }
485
486 if (op_array->scope
487 && !(op_array->fn_flags & ZEND_ACC_CLOSURE)
488 && (op_array->scope->ce_flags & ZEND_ACC_CACHED)) {
489 return;
490 }
491
492 if (op_array->static_variables && !zend_accel_in_shm(op_array->static_variables)) {
493 Bucket *p;
494
495 zend_hash_persist(op_array->static_variables);
496 ZEND_HASH_MAP_FOREACH_BUCKET(op_array->static_variables, p) {
497 ZEND_ASSERT(p->key != NULL);
498 zend_accel_store_interned_string(p->key);
499 zend_persist_zval(&p->val);
500 } ZEND_HASH_FOREACH_END();
501 op_array->static_variables = zend_shared_memdup_put_free(op_array->static_variables, sizeof(HashTable));
502 /* make immutable array */
503 GC_SET_REFCOUNT(op_array->static_variables, 2);
504 GC_TYPE_INFO(op_array->static_variables) = GC_ARRAY | ((IS_ARRAY_IMMUTABLE|GC_NOT_COLLECTABLE) << GC_FLAGS_SHIFT);
505 }
506
507 if (op_array->literals) {
508 zval *p, *end;
509
510 orig_literals = op_array->literals;
511 #if ZEND_USE_ABS_CONST_ADDR
512 p = zend_shared_memdup_put_free(op_array->literals, sizeof(zval) * op_array->last_literal);
513 #else
514 p = zend_shared_memdup_put(op_array->literals, sizeof(zval) * op_array->last_literal);
515 #endif
516 end = p + op_array->last_literal;
517 op_array->literals = p;
518 while (p < end) {
519 zend_persist_zval(p);
520 p++;
521 }
522 }
523
524 {
525 zend_op *new_opcodes = zend_shared_memdup_put(op_array->opcodes, sizeof(zend_op) * op_array->last);
526 zend_op *opline = new_opcodes;
527 zend_op *end = new_opcodes + op_array->last;
528 int offset = 0;
529
530 for (; opline < end ; opline++, offset++) {
531 #if ZEND_USE_ABS_CONST_ADDR
532 if (opline->op1_type == IS_CONST) {
533 opline->op1.zv = (zval*)((char*)opline->op1.zv + ((char*)op_array->literals - (char*)orig_literals));
534 if (opline->opcode == ZEND_SEND_VAL
535 || opline->opcode == ZEND_SEND_VAL_EX
536 || opline->opcode == ZEND_QM_ASSIGN) {
537 /* Update handlers to eliminate REFCOUNTED check */
538 zend_vm_set_opcode_handler_ex(opline, 1 << Z_TYPE_P(opline->op1.zv), 0, 0);
539 }
540 }
541 if (opline->op2_type == IS_CONST) {
542 opline->op2.zv = (zval*)((char*)opline->op2.zv + ((char*)op_array->literals - (char*)orig_literals));
543 }
544 #else
545 if (opline->op1_type == IS_CONST) {
546 opline->op1.constant =
547 (char*)(op_array->literals +
548 ((zval*)((char*)(op_array->opcodes + (opline - new_opcodes)) +
549 (int32_t)opline->op1.constant) - orig_literals)) -
550 (char*)opline;
551 if (opline->opcode == ZEND_SEND_VAL
552 || opline->opcode == ZEND_SEND_VAL_EX
553 || opline->opcode == ZEND_QM_ASSIGN) {
554 zend_vm_set_opcode_handler_ex(opline, 0, 0, 0);
555 }
556 }
557 if (opline->op2_type == IS_CONST) {
558 opline->op2.constant =
559 (char*)(op_array->literals +
560 ((zval*)((char*)(op_array->opcodes + (opline - new_opcodes)) +
561 (int32_t)opline->op2.constant) - orig_literals)) -
562 (char*)opline;
563 }
564 #endif
565 #if ZEND_USE_ABS_JMP_ADDR
566 if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
567 /* fix jumps to point to new array */
568 switch (opline->opcode) {
569 case ZEND_JMP:
570 case ZEND_FAST_CALL:
571 opline->op1.jmp_addr = &new_opcodes[opline->op1.jmp_addr - op_array->opcodes];
572 break;
573 case ZEND_JMPZ:
574 case ZEND_JMPNZ:
575 case ZEND_JMPZ_EX:
576 case ZEND_JMPNZ_EX:
577 case ZEND_JMP_SET:
578 case ZEND_COALESCE:
579 case ZEND_FE_RESET_R:
580 case ZEND_FE_RESET_RW:
581 case ZEND_ASSERT_CHECK:
582 case ZEND_JMP_NULL:
583 case ZEND_BIND_INIT_STATIC_OR_JMP:
584 opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes];
585 break;
586 case ZEND_CATCH:
587 if (!(opline->extended_value & ZEND_LAST_CATCH)) {
588 opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes];
589 }
590 break;
591 case ZEND_FE_FETCH_R:
592 case ZEND_FE_FETCH_RW:
593 case ZEND_SWITCH_LONG:
594 case ZEND_SWITCH_STRING:
595 case ZEND_MATCH:
596 /* relative extended_value don't have to be changed */
597 break;
598 }
599 }
600 #endif
601 }
602
603 efree(op_array->opcodes);
604 op_array->opcodes = new_opcodes;
605 }
606
607 if (op_array->filename) {
608 zend_accel_store_string(op_array->filename);
609 }
610
611 if (op_array->arg_info) {
612 zend_arg_info *arg_info = op_array->arg_info;
613 uint32_t num_args = op_array->num_args;
614 uint32_t i;
615
616 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
617 arg_info--;
618 num_args++;
619 }
620 if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
621 num_args++;
622 }
623 arg_info = zend_shared_memdup_put_free(arg_info, sizeof(zend_arg_info) * num_args);
624 for (i = 0; i < num_args; i++) {
625 if (arg_info[i].name) {
626 zend_accel_store_interned_string(arg_info[i].name);
627 }
628 zend_persist_type(&arg_info[i].type);
629 }
630 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
631 arg_info++;
632 }
633 op_array->arg_info = arg_info;
634 }
635
636 if (op_array->live_range) {
637 op_array->live_range = zend_shared_memdup_put_free(op_array->live_range, sizeof(zend_live_range) * op_array->last_live_range);
638 }
639
640 if (op_array->doc_comment) {
641 if (ZCG(accel_directives).save_comments) {
642 zend_accel_store_interned_string(op_array->doc_comment);
643 } else {
644 zend_string_release_ex(op_array->doc_comment, 0);
645 op_array->doc_comment = NULL;
646 }
647 }
648
649 if (op_array->attributes) {
650 op_array->attributes = zend_persist_attributes(op_array->attributes);
651 }
652
653 if (op_array->try_catch_array) {
654 op_array->try_catch_array = zend_shared_memdup_put_free(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
655 }
656
657 if (op_array->vars) {
658 int i;
659 op_array->vars = zend_shared_memdup_put_free(op_array->vars, sizeof(zend_string*) * op_array->last_var);
660 for (i = 0; i < op_array->last_var; i++) {
661 zend_accel_store_interned_string(op_array->vars[i]);
662 }
663 }
664
665 if (op_array->num_dynamic_func_defs) {
666 op_array->dynamic_func_defs = zend_shared_memdup_put_free(
667 op_array->dynamic_func_defs, sizeof(zend_function *) * op_array->num_dynamic_func_defs);
668 for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
669 zval tmp;
670 ZVAL_PTR(&tmp, op_array->dynamic_func_defs[i]);
671 zend_persist_op_array(&tmp);
672 op_array->dynamic_func_defs[i] = Z_PTR(tmp);
673 }
674 }
675
676 ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist(op_array, ZCG(mem))));
677 }
678
zend_persist_op_array(zval * zv)679 static void zend_persist_op_array(zval *zv)
680 {
681 zend_op_array *op_array = Z_PTR_P(zv);
682 zend_op_array *old_op_array;
683 ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
684
685 old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
686 if (!old_op_array) {
687 op_array = Z_PTR_P(zv) = zend_shared_memdup_put(Z_PTR_P(zv), sizeof(zend_op_array));
688 zend_persist_op_array_ex(op_array, NULL);
689 if (!ZCG(current_persistent_script)->corrupted) {
690 op_array->fn_flags |= ZEND_ACC_IMMUTABLE;
691 ZEND_MAP_PTR_NEW(op_array->run_time_cache);
692 if (op_array->static_variables) {
693 ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
694 }
695 }
696 #ifdef HAVE_JIT
697 if (JIT_G(on)
698 && JIT_G(opt_level) <= ZEND_JIT_LEVEL_OPT_FUNCS
699 && (!ZCG(current_persistent_script)
700 || !ZCG(current_persistent_script)->corrupted)) {
701 zend_jit_op_array(op_array, ZCG(current_persistent_script) ? &ZCG(current_persistent_script)->script : NULL);
702 }
703 #endif
704 } else {
705 /* This can happen during preloading, if a dynamic function definition is declared. */
706 Z_PTR_P(zv) = old_op_array;
707 }
708 }
709
zend_persist_class_method(zval * zv,zend_class_entry * ce)710 static void zend_persist_class_method(zval *zv, zend_class_entry *ce)
711 {
712 zend_op_array *op_array = Z_PTR_P(zv);
713 zend_op_array *old_op_array;
714
715 if (op_array->type != ZEND_USER_FUNCTION) {
716 ZEND_ASSERT(op_array->type == ZEND_INTERNAL_FUNCTION);
717 if (op_array->fn_flags & ZEND_ACC_ARENA_ALLOCATED) {
718 old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
719 if (old_op_array) {
720 Z_PTR_P(zv) = old_op_array;
721 } else {
722 op_array = Z_PTR_P(zv) = zend_shared_memdup_put(op_array, sizeof(zend_internal_function));
723 if (op_array->scope) {
724 void *persist_ptr;
725
726 if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->scope))) {
727 op_array->scope = (zend_class_entry*)persist_ptr;
728 }
729 if (op_array->prototype) {
730 if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype))) {
731 op_array->prototype = (zend_function*)persist_ptr;
732 }
733 }
734 }
735 // Real dynamically created internal functions like enum methods must have their own run_time_cache pointer. They're always on the same scope as their defining class.
736 // However, copies - as caused by inheritance of internal methods - must retain the original run_time_cache pointer, shared with the source function.
737 if (!op_array->scope || (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE))) {
738 ZEND_MAP_PTR_NEW(op_array->run_time_cache);
739 }
740 }
741 }
742 return;
743 }
744
745 if ((op_array->fn_flags & ZEND_ACC_IMMUTABLE)
746 && !ZCG(current_persistent_script)->corrupted
747 && zend_accel_in_shm(op_array)) {
748 zend_shared_alloc_register_xlat_entry(op_array, op_array);
749 return;
750 }
751
752 old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
753 if (old_op_array) {
754 Z_PTR_P(zv) = old_op_array;
755 if (op_array->refcount && --(*op_array->refcount) == 0) {
756 efree(op_array->refcount);
757 }
758
759 /* If op_array is shared, the function name refcount is still incremented for each use,
760 * so we need to release it here. We remembered the original function name in xlat. */
761 zend_string *old_function_name =
762 zend_shared_alloc_get_xlat_entry(&old_op_array->function_name);
763 if (old_function_name) {
764 zend_string_release_ex(old_function_name, 0);
765 }
766 return;
767 }
768 op_array = Z_PTR_P(zv) = zend_shared_memdup_put(op_array, sizeof(zend_op_array));
769 zend_persist_op_array_ex(op_array, NULL);
770 if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
771 op_array->fn_flags |= ZEND_ACC_IMMUTABLE;
772 if (ce->ce_flags & ZEND_ACC_LINKED) {
773 ZEND_MAP_PTR_NEW(op_array->run_time_cache);
774 if (op_array->static_variables) {
775 ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
776 }
777 } else {
778 ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
779 ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, NULL);
780 }
781 }
782 }
783
zend_persist_property_info(zend_property_info * prop)784 static zend_property_info *zend_persist_property_info(zend_property_info *prop)
785 {
786 zend_class_entry *ce;
787 prop = zend_shared_memdup_put(prop, sizeof(zend_property_info));
788 ce = zend_shared_alloc_get_xlat_entry(prop->ce);
789 if (ce) {
790 prop->ce = ce;
791 }
792 zend_accel_store_interned_string(prop->name);
793 if (prop->doc_comment) {
794 if (ZCG(accel_directives).save_comments) {
795 zend_accel_store_interned_string(prop->doc_comment);
796 } else {
797 if (!zend_shared_alloc_get_xlat_entry(prop->doc_comment)) {
798 zend_shared_alloc_register_xlat_entry(prop->doc_comment, prop->doc_comment);
799 }
800 zend_string_release_ex(prop->doc_comment, 0);
801 prop->doc_comment = NULL;
802 }
803 }
804 if (prop->attributes) {
805 prop->attributes = zend_persist_attributes(prop->attributes);
806 }
807 zend_persist_type(&prop->type);
808 return prop;
809 }
810
zend_persist_class_constant(zval * zv)811 static void zend_persist_class_constant(zval *zv)
812 {
813 zend_class_constant *orig_c = Z_PTR_P(zv);
814 zend_class_constant *c = zend_shared_alloc_get_xlat_entry(orig_c);
815 zend_class_entry *ce;
816
817 if (c) {
818 Z_PTR_P(zv) = c;
819 return;
820 } else if (((orig_c->ce->ce_flags & ZEND_ACC_IMMUTABLE) && !(Z_CONSTANT_FLAGS(orig_c->value) & CONST_OWNED))
821 || orig_c->ce->type == ZEND_INTERNAL_CLASS) {
822 /* Class constant comes from a different file in shm or internal class, keep existing pointer. */
823 return;
824 } else if (!ZCG(current_persistent_script)->corrupted
825 && zend_accel_in_shm(Z_PTR_P(zv))) {
826 return;
827 }
828 c = Z_PTR_P(zv) = zend_shared_memdup_put(Z_PTR_P(zv), sizeof(zend_class_constant));
829 zend_persist_zval(&c->value);
830 ce = zend_shared_alloc_get_xlat_entry(c->ce);
831 if (ce) {
832 c->ce = ce;
833 }
834 if (c->doc_comment) {
835 if (ZCG(accel_directives).save_comments) {
836 zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment);
837 if (doc_comment) {
838 c->doc_comment = doc_comment;
839 } else {
840 zend_accel_store_interned_string(c->doc_comment);
841 }
842 } else {
843 zend_string *doc_comment = zend_shared_alloc_get_xlat_entry(c->doc_comment);
844 if (!doc_comment) {
845 zend_shared_alloc_register_xlat_entry(c->doc_comment, c->doc_comment);
846 zend_string_release_ex(c->doc_comment, 0);
847 }
848 c->doc_comment = NULL;
849 }
850 }
851 if (c->attributes) {
852 c->attributes = zend_persist_attributes(c->attributes);
853 }
854 zend_persist_type(&c->type);
855 }
856
zend_persist_class_entry(zend_class_entry * orig_ce)857 zend_class_entry *zend_persist_class_entry(zend_class_entry *orig_ce)
858 {
859 Bucket *p;
860 zend_class_entry *ce = orig_ce;
861
862 if (ce->type == ZEND_USER_CLASS) {
863 /* The same zend_class_entry may be reused by class_alias */
864 zend_class_entry *new_ce = zend_shared_alloc_get_xlat_entry(ce);
865 if (new_ce) {
866 return new_ce;
867 }
868 ce = zend_shared_memdup_put(ce, sizeof(zend_class_entry));
869 if (EXPECTED(!ZCG(current_persistent_script)->corrupted)) {
870 ce->ce_flags |= ZEND_ACC_IMMUTABLE;
871 if ((ce->ce_flags & ZEND_ACC_LINKED)
872 && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
873 ZEND_MAP_PTR_NEW(ce->mutable_data);
874 } else {
875 ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
876 }
877 } else {
878 ce->ce_flags |= ZEND_ACC_FILE_CACHED;
879 }
880 ce->inheritance_cache = NULL;
881
882 if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
883 if (ZSTR_HAS_CE_CACHE(ce->name)) {
884 ZSTR_SET_CE_CACHE_EX(ce->name, NULL, 0);
885 }
886 zend_accel_store_interned_string(ce->name);
887 if (!(ce->ce_flags & ZEND_ACC_ANON_CLASS)
888 && !ZCG(current_persistent_script)->corrupted) {
889 zend_accel_get_class_name_map_ptr(ce->name);
890 }
891 if (ce->parent_name && !(ce->ce_flags & ZEND_ACC_LINKED)) {
892 zend_accel_store_interned_string(ce->parent_name);
893 }
894 }
895
896 zend_hash_persist(&ce->function_table);
897 ZEND_HASH_MAP_FOREACH_BUCKET(&ce->function_table, p) {
898 ZEND_ASSERT(p->key != NULL);
899 zend_accel_store_interned_string(p->key);
900 zend_persist_class_method(&p->val, ce);
901 } ZEND_HASH_FOREACH_END();
902 HT_FLAGS(&ce->function_table) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS);
903 if (ce->default_properties_table) {
904 int i;
905
906 ce->default_properties_table = zend_shared_memdup_free(ce->default_properties_table, sizeof(zval) * ce->default_properties_count);
907 for (i = 0; i < ce->default_properties_count; i++) {
908 zend_persist_zval(&ce->default_properties_table[i]);
909 }
910 }
911 if (ce->default_static_members_table) {
912 int i;
913 ce->default_static_members_table = zend_shared_memdup_free(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count);
914
915 /* Persist only static properties in this class.
916 * Static properties from parent classes will be handled in class_copy_ctor and are marked with IS_INDIRECT */
917 for (i = 0; i < ce->default_static_members_count; i++) {
918 if (Z_TYPE(ce->default_static_members_table[i]) != IS_INDIRECT) {
919 zend_persist_zval(&ce->default_static_members_table[i]);
920 }
921 }
922 if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
923 if (ce->ce_flags & ZEND_ACC_LINKED) {
924 ZEND_MAP_PTR_NEW(ce->static_members_table);
925 } else {
926 ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
927 }
928 }
929 }
930
931 zend_hash_persist(&ce->constants_table);
932 ZEND_HASH_MAP_FOREACH_BUCKET(&ce->constants_table, p) {
933 ZEND_ASSERT(p->key != NULL);
934 zend_accel_store_interned_string(p->key);
935 zend_persist_class_constant(&p->val);
936 } ZEND_HASH_FOREACH_END();
937 HT_FLAGS(&ce->constants_table) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS);
938
939 zend_hash_persist(&ce->properties_info);
940 ZEND_HASH_MAP_FOREACH_BUCKET(&ce->properties_info, p) {
941 zend_property_info *prop = Z_PTR(p->val);
942 ZEND_ASSERT(p->key != NULL);
943 zend_accel_store_interned_string(p->key);
944 if (prop->ce == orig_ce) {
945 Z_PTR(p->val) = zend_persist_property_info(prop);
946 } else {
947 prop = zend_shared_alloc_get_xlat_entry(prop);
948 if (prop) {
949 Z_PTR(p->val) = prop;
950 } else {
951 /* This can happen if preloading is used and we inherit a property from an
952 * internal class. In that case we should keep pointing to the internal
953 * property, without any adjustments. */
954 }
955 }
956 } ZEND_HASH_FOREACH_END();
957 HT_FLAGS(&ce->properties_info) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS);
958
959 if (ce->properties_info_table) {
960 int i;
961
962 size_t size = sizeof(zend_property_info *) * ce->default_properties_count;
963 ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
964 ce->properties_info_table = zend_shared_memdup(
965 ce->properties_info_table, size);
966
967 for (i = 0; i < ce->default_properties_count; i++) {
968 if (ce->properties_info_table[i]) {
969 zend_property_info *prop_info = zend_shared_alloc_get_xlat_entry(
970 ce->properties_info_table[i]);
971 if (prop_info) {
972 ce->properties_info_table[i] = prop_info;
973 }
974 }
975 }
976 }
977
978 if (ce->iterator_funcs_ptr) {
979 ce->iterator_funcs_ptr = zend_shared_memdup(ce->iterator_funcs_ptr, sizeof(zend_class_iterator_funcs));
980 }
981 if (ce->arrayaccess_funcs_ptr) {
982 ce->arrayaccess_funcs_ptr = zend_shared_memdup(ce->arrayaccess_funcs_ptr, sizeof(zend_class_arrayaccess_funcs));
983 }
984
985 if (ce->ce_flags & ZEND_ACC_CACHED) {
986 return ce;
987 }
988
989 ce->ce_flags |= ZEND_ACC_CACHED;
990
991 if (ce->info.user.filename) {
992 zend_accel_store_string(ce->info.user.filename);
993 }
994
995 if (ce->info.user.doc_comment) {
996 if (ZCG(accel_directives).save_comments) {
997 zend_accel_store_interned_string(ce->info.user.doc_comment);
998 } else {
999 if (!zend_shared_alloc_get_xlat_entry(ce->info.user.doc_comment)) {
1000 zend_shared_alloc_register_xlat_entry(ce->info.user.doc_comment, ce->info.user.doc_comment);
1001 zend_string_release_ex(ce->info.user.doc_comment, 0);
1002 }
1003 ce->info.user.doc_comment = NULL;
1004 }
1005 }
1006
1007 if (ce->attributes) {
1008 ce->attributes = zend_persist_attributes(ce->attributes);
1009 }
1010
1011 if (ce->num_interfaces && !(ce->ce_flags & ZEND_ACC_LINKED)) {
1012 uint32_t i = 0;
1013
1014 for (i = 0; i < ce->num_interfaces; i++) {
1015 zend_accel_store_interned_string(ce->interface_names[i].name);
1016 zend_accel_store_interned_string(ce->interface_names[i].lc_name);
1017 }
1018 ce->interface_names = zend_shared_memdup_free(ce->interface_names, sizeof(zend_class_name) * ce->num_interfaces);
1019 }
1020
1021 if (ce->num_traits) {
1022 uint32_t i = 0;
1023
1024 for (i = 0; i < ce->num_traits; i++) {
1025 zend_accel_store_interned_string(ce->trait_names[i].name);
1026 zend_accel_store_interned_string(ce->trait_names[i].lc_name);
1027 }
1028 ce->trait_names = zend_shared_memdup_free(ce->trait_names, sizeof(zend_class_name) * ce->num_traits);
1029
1030 i = 0;
1031 if (ce->trait_aliases) {
1032 while (ce->trait_aliases[i]) {
1033 if (ce->trait_aliases[i]->trait_method.method_name) {
1034 zend_accel_store_interned_string(ce->trait_aliases[i]->trait_method.method_name);
1035 }
1036 if (ce->trait_aliases[i]->trait_method.class_name) {
1037 zend_accel_store_interned_string(ce->trait_aliases[i]->trait_method.class_name);
1038 }
1039
1040 if (ce->trait_aliases[i]->alias) {
1041 zend_accel_store_interned_string(ce->trait_aliases[i]->alias);
1042 }
1043
1044 ce->trait_aliases[i] = zend_shared_memdup_free(ce->trait_aliases[i], sizeof(zend_trait_alias));
1045 i++;
1046 }
1047
1048 ce->trait_aliases = zend_shared_memdup_free(ce->trait_aliases, sizeof(zend_trait_alias*) * (i + 1));
1049 }
1050
1051 if (ce->trait_precedences) {
1052 uint32_t j;
1053
1054 i = 0;
1055 while (ce->trait_precedences[i]) {
1056 zend_accel_store_interned_string(ce->trait_precedences[i]->trait_method.method_name);
1057 zend_accel_store_interned_string(ce->trait_precedences[i]->trait_method.class_name);
1058
1059 for (j = 0; j < ce->trait_precedences[i]->num_excludes; j++) {
1060 zend_accel_store_interned_string(ce->trait_precedences[i]->exclude_class_names[j]);
1061 }
1062
1063 ce->trait_precedences[i] = zend_shared_memdup_free(ce->trait_precedences[i], sizeof(zend_trait_precedence) + (ce->trait_precedences[i]->num_excludes - 1) * sizeof(zend_string*));
1064 i++;
1065 }
1066 ce->trait_precedences = zend_shared_memdup_free(
1067 ce->trait_precedences, sizeof(zend_trait_precedence*) * (i + 1));
1068 }
1069 }
1070
1071 ZEND_ASSERT(ce->backed_enum_table == NULL);
1072 }
1073
1074 return ce;
1075 }
1076
zend_update_parent_ce(zend_class_entry * ce)1077 void zend_update_parent_ce(zend_class_entry *ce)
1078 {
1079 if (ce->ce_flags & ZEND_ACC_LINKED) {
1080 if (ce->parent) {
1081 int i, end;
1082 zend_class_entry *parent = ce->parent;
1083
1084 if (parent->type == ZEND_USER_CLASS) {
1085 zend_class_entry *p = zend_shared_alloc_get_xlat_entry(parent);
1086
1087 if (p) {
1088 ce->parent = parent = p;
1089 }
1090 }
1091
1092 /* Create indirections to static properties from parent classes */
1093 i = parent->default_static_members_count - 1;
1094 while (parent && parent->default_static_members_table) {
1095 end = parent->parent ? parent->parent->default_static_members_count : 0;
1096 for (; i >= end; i--) {
1097 zval *p = &ce->default_static_members_table[i];
1098 /* The static property may have been overridden by a trait
1099 * during inheritance. In that case, the property default
1100 * value is replaced by zend_declare_typed_property() at the
1101 * property index of the parent property. Make sure we only
1102 * point to the parent property value if the child value was
1103 * already indirect. */
1104 if (Z_TYPE_P(p) == IS_INDIRECT) {
1105 ZVAL_INDIRECT(p, &parent->default_static_members_table[i]);
1106 }
1107 }
1108
1109 parent = parent->parent;
1110 }
1111 }
1112
1113 if (ce->num_interfaces) {
1114 uint32_t i = 0;
1115
1116 ce->interfaces = zend_shared_memdup_free(ce->interfaces, sizeof(zend_class_entry*) * ce->num_interfaces);
1117 for (i = 0; i < ce->num_interfaces; i++) {
1118 if (ce->interfaces[i]->type == ZEND_USER_CLASS) {
1119 zend_class_entry *tmp = zend_shared_alloc_get_xlat_entry(ce->interfaces[i]);
1120 if (tmp != NULL) {
1121 ce->interfaces[i] = tmp;
1122 }
1123 }
1124 }
1125 }
1126
1127 if (ce->iterator_funcs_ptr) {
1128 memset(ce->iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs));
1129 if (zend_class_implements_interface(ce, zend_ce_aggregate)) {
1130 ce->iterator_funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&ce->function_table, "getiterator", sizeof("getiterator") - 1);
1131 }
1132 if (zend_class_implements_interface(ce, zend_ce_iterator)) {
1133 ce->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&ce->function_table, "rewind", sizeof("rewind") - 1);
1134 ce->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&ce->function_table, "valid", sizeof("valid") - 1);
1135 ce->iterator_funcs_ptr->zf_key = zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_KEY));
1136 ce->iterator_funcs_ptr->zf_current = zend_hash_str_find_ptr(&ce->function_table, "current", sizeof("current") - 1);
1137 ce->iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&ce->function_table, "next", sizeof("next") - 1);
1138 }
1139 }
1140
1141 if (ce->arrayaccess_funcs_ptr) {
1142 ZEND_ASSERT(zend_class_implements_interface(ce, zend_ce_arrayaccess));
1143 ce->arrayaccess_funcs_ptr->zf_offsetget = zend_hash_str_find_ptr(&ce->function_table, "offsetget", sizeof("offsetget") - 1);
1144 ce->arrayaccess_funcs_ptr->zf_offsetexists = zend_hash_str_find_ptr(&ce->function_table, "offsetexists", sizeof("offsetexists") - 1);
1145 ce->arrayaccess_funcs_ptr->zf_offsetset = zend_hash_str_find_ptr(&ce->function_table, "offsetset", sizeof("offsetset") - 1);
1146 ce->arrayaccess_funcs_ptr->zf_offsetunset = zend_hash_str_find_ptr(&ce->function_table, "offsetunset", sizeof("offsetunset") - 1);
1147 }
1148 }
1149
1150 /* update methods */
1151 if (ce->constructor) {
1152 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->constructor);
1153 if (tmp != NULL) {
1154 ce->constructor = tmp;
1155 }
1156 }
1157 if (ce->destructor) {
1158 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->destructor);
1159 if (tmp != NULL) {
1160 ce->destructor = tmp;
1161 }
1162 }
1163 if (ce->clone) {
1164 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->clone);
1165 if (tmp != NULL) {
1166 ce->clone = tmp;
1167 }
1168 }
1169 if (ce->__get) {
1170 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__get);
1171 if (tmp != NULL) {
1172 ce->__get = tmp;
1173 }
1174 }
1175 if (ce->__set) {
1176 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__set);
1177 if (tmp != NULL) {
1178 ce->__set = tmp;
1179 }
1180 }
1181 if (ce->__call) {
1182 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__call);
1183 if (tmp != NULL) {
1184 ce->__call = tmp;
1185 }
1186 }
1187 if (ce->__serialize) {
1188 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__serialize);
1189 if (tmp != NULL) {
1190 ce->__serialize = tmp;
1191 }
1192 }
1193 if (ce->__unserialize) {
1194 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__unserialize);
1195 if (tmp != NULL) {
1196 ce->__unserialize = tmp;
1197 }
1198 }
1199 if (ce->__isset) {
1200 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__isset);
1201 if (tmp != NULL) {
1202 ce->__isset = tmp;
1203 }
1204 }
1205 if (ce->__unset) {
1206 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__unset);
1207 if (tmp != NULL) {
1208 ce->__unset = tmp;
1209 }
1210 }
1211 if (ce->__tostring) {
1212 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__tostring);
1213 if (tmp != NULL) {
1214 ce->__tostring = tmp;
1215 }
1216 }
1217 if (ce->__callstatic) {
1218 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__callstatic);
1219 if (tmp != NULL) {
1220 ce->__callstatic = tmp;
1221 }
1222 }
1223 if (ce->__debugInfo) {
1224 zend_function *tmp = zend_shared_alloc_get_xlat_entry(ce->__debugInfo);
1225 if (tmp != NULL) {
1226 ce->__debugInfo = tmp;
1227 }
1228 }
1229 }
1230
zend_accel_persist_class_table(HashTable * class_table)1231 static void zend_accel_persist_class_table(HashTable *class_table)
1232 {
1233 Bucket *p;
1234 zend_class_entry *ce;
1235 #ifdef HAVE_JIT
1236 bool orig_jit_on = JIT_G(on);
1237
1238 JIT_G(on) = 0;
1239 #endif
1240 zend_hash_persist(class_table);
1241 ZEND_HASH_MAP_FOREACH_BUCKET(class_table, p) {
1242 ZEND_ASSERT(p->key != NULL);
1243 zend_accel_store_interned_string(p->key);
1244 Z_CE(p->val) = zend_persist_class_entry(Z_CE(p->val));
1245 } ZEND_HASH_FOREACH_END();
1246 ZEND_HASH_MAP_FOREACH_BUCKET(class_table, p) {
1247 if (EXPECTED(Z_TYPE(p->val) != IS_ALIAS_PTR)) {
1248 ce = Z_PTR(p->val);
1249 zend_update_parent_ce(ce);
1250 }
1251 } ZEND_HASH_FOREACH_END();
1252 #ifdef HAVE_JIT
1253 JIT_G(on) = orig_jit_on;
1254 if (JIT_G(on) && JIT_G(opt_level) <= ZEND_JIT_LEVEL_OPT_FUNCS &&
1255 !ZCG(current_persistent_script)->corrupted) {
1256 zend_op_array *op_array;
1257
1258 ZEND_HASH_MAP_FOREACH_BUCKET(class_table, p) {
1259 if (EXPECTED(Z_TYPE(p->val) != IS_ALIAS_PTR)) {
1260 ce = Z_PTR(p->val);
1261 ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
1262 if (op_array->type == ZEND_USER_FUNCTION) {
1263 if (op_array->scope == ce
1264 && !(op_array->fn_flags & ZEND_ACC_ABSTRACT)
1265 && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
1266 zend_jit_op_array(op_array, ZCG(current_persistent_script) ? &ZCG(current_persistent_script)->script : NULL);
1267 for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
1268 zend_jit_op_array(op_array->dynamic_func_defs[i], ZCG(current_persistent_script) ? &ZCG(current_persistent_script)->script : NULL);
1269 }
1270 }
1271 }
1272 } ZEND_HASH_FOREACH_END();
1273 }
1274 } ZEND_HASH_FOREACH_END();
1275 ZEND_HASH_MAP_FOREACH_BUCKET(class_table, p) {
1276 if (EXPECTED(Z_TYPE(p->val) != IS_ALIAS_PTR)) {
1277 ce = Z_PTR(p->val);
1278 ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
1279 if (op_array->type == ZEND_USER_FUNCTION
1280 && !(op_array->fn_flags & ZEND_ACC_ABSTRACT)) {
1281 if ((op_array->scope != ce
1282 || (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE))
1283 && (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC
1284 || JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST
1285 || JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS
1286 || JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE)) {
1287 void *jit_extension = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
1288
1289 if (jit_extension) {
1290 ZEND_SET_FUNC_INFO(op_array, jit_extension);
1291 }
1292 }
1293 }
1294 } ZEND_HASH_FOREACH_END();
1295 }
1296 } ZEND_HASH_FOREACH_END();
1297 }
1298 #endif
1299 }
1300
zend_persist_warnings(uint32_t num_warnings,zend_error_info ** warnings)1301 zend_error_info **zend_persist_warnings(uint32_t num_warnings, zend_error_info **warnings) {
1302 if (warnings) {
1303 warnings = zend_shared_memdup_free(warnings, num_warnings * sizeof(zend_error_info *));
1304 for (uint32_t i = 0; i < num_warnings; i++) {
1305 warnings[i] = zend_shared_memdup_free(warnings[i], sizeof(zend_error_info));
1306 zend_accel_store_string(warnings[i]->filename);
1307 zend_accel_store_string(warnings[i]->message);
1308 }
1309 }
1310 return warnings;
1311 }
1312
zend_persist_early_bindings(uint32_t num_early_bindings,zend_early_binding * early_bindings)1313 static zend_early_binding *zend_persist_early_bindings(
1314 uint32_t num_early_bindings, zend_early_binding *early_bindings) {
1315 if (early_bindings) {
1316 early_bindings = zend_shared_memdup_free(
1317 early_bindings, num_early_bindings * sizeof(zend_early_binding));
1318 for (uint32_t i = 0; i < num_early_bindings; i++) {
1319 zend_accel_store_interned_string(early_bindings[i].lcname);
1320 zend_accel_store_interned_string(early_bindings[i].rtd_key);
1321 zend_accel_store_interned_string(early_bindings[i].lc_parent_name);
1322 }
1323 }
1324 return early_bindings;
1325 }
1326
zend_accel_script_persist(zend_persistent_script * script,int for_shm)1327 zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, int for_shm)
1328 {
1329 Bucket *p;
1330
1331 script->mem = ZCG(mem);
1332
1333 ZEND_ASSERT(((uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
1334
1335 script = zend_shared_memdup_free(script, sizeof(zend_persistent_script));
1336 script->corrupted = false;
1337 ZCG(current_persistent_script) = script;
1338
1339 if (!for_shm) {
1340 /* script is not going to be saved in SHM */
1341 script->corrupted = true;
1342 }
1343
1344 zend_accel_store_interned_string(script->script.filename);
1345
1346 #if defined(__AVX__) || defined(__SSE2__)
1347 /* Align to 64-byte boundary */
1348 ZCG(mem) = (void*)(((uintptr_t)ZCG(mem) + 63L) & ~63L);
1349 #else
1350 ZEND_ASSERT(((uintptr_t)ZCG(mem) & 0x7) == 0); /* should be 8 byte aligned */
1351 #endif
1352
1353 #ifdef HAVE_JIT
1354 if (JIT_G(on) && for_shm) {
1355 zend_jit_unprotect();
1356 }
1357 #endif
1358
1359 zend_map_ptr_extend(ZCSG(map_ptr_last));
1360
1361 zend_accel_persist_class_table(&script->script.class_table);
1362 zend_hash_persist(&script->script.function_table);
1363 ZEND_HASH_MAP_FOREACH_BUCKET(&script->script.function_table, p) {
1364 ZEND_ASSERT(p->key != NULL);
1365 zend_accel_store_interned_string(p->key);
1366 zend_persist_op_array(&p->val);
1367 } ZEND_HASH_FOREACH_END();
1368 zend_persist_op_array_ex(&script->script.main_op_array, script);
1369 if (!script->corrupted) {
1370 ZEND_MAP_PTR_INIT(script->script.main_op_array.run_time_cache, NULL);
1371 if (script->script.main_op_array.static_variables) {
1372 ZEND_MAP_PTR_NEW(script->script.main_op_array.static_variables_ptr);
1373 }
1374 #ifdef HAVE_JIT
1375 if (JIT_G(on) && JIT_G(opt_level) <= ZEND_JIT_LEVEL_OPT_FUNCS) {
1376 zend_jit_op_array(&script->script.main_op_array, &script->script);
1377 }
1378 #endif
1379 }
1380 script->warnings = zend_persist_warnings(script->num_warnings, script->warnings);
1381 script->early_bindings = zend_persist_early_bindings(
1382 script->num_early_bindings, script->early_bindings);
1383
1384 if (for_shm) {
1385 ZCSG(map_ptr_last) = CG(map_ptr_last);
1386 }
1387
1388 #ifdef HAVE_JIT
1389 if (JIT_G(on) && for_shm) {
1390 if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_SCRIPT) {
1391 zend_jit_script(&script->script);
1392 }
1393 zend_jit_protect();
1394 }
1395 #endif
1396
1397 script->corrupted = false;
1398 ZCG(current_persistent_script) = NULL;
1399
1400 return script;
1401 }
1402