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