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