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