xref: /PHP-8.3/ext/opcache/zend_persist.c (revision afba2010)
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(&copy->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(&copy->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