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