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