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