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_API.h"
23 #include "zend_constants.h"
24 #include "zend_accelerator_util_funcs.h"
25 #include "zend_persist.h"
26 #include "zend_shared_alloc.h"
27 
28 #if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG
29 /* If sizeof(void*) == sizeof(zend_ulong) we can use zend_hash index functions */
30 # define accel_xlat_set(old, new)	zend_hash_index_add_new_ptr(&ZCG(bind_hash), (zend_ulong)(zend_uintptr_t)(old), (new))
31 # define accel_xlat_get(old)		zend_hash_index_find_ptr(&ZCG(bind_hash), (zend_ulong)(zend_uintptr_t)(old))
32 #else
33 # define accel_xlat_set(old, new)	zend_hash_str_add_new_ptr(&ZCG(bind_hash), (char*)&(old), sizeof(void*), (new))
34 # define accel_xlat_get(old)	    zend_hash_str_find_ptr(&ZCG(bind_hash), (char*)&(old), sizeof(void*))
35 #endif
36 
37 #define IN_ARENA(ptr) \
38 	((void*)(ptr) >= ZCG(current_persistent_script)->arena_mem && \
39 	 (void*)(ptr) < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size))
40 
41 #define ARENA_REALLOC(ptr) \
42 	(void*)(((char*)(ptr)) + ((char*)ZCG(arena_mem) - (char*)ZCG(current_persistent_script)->arena_mem))
43 
44 typedef int (*id_function_t)(void *, void *);
45 typedef void (*unique_copy_ctor_func_t)(void *pElement);
46 
create_persistent_script(void)47 zend_persistent_script* create_persistent_script(void)
48 {
49 	zend_persistent_script *persistent_script = (zend_persistent_script *) emalloc(sizeof(zend_persistent_script));
50 	memset(persistent_script, 0, sizeof(zend_persistent_script));
51 
52 	zend_hash_init(&persistent_script->script.function_table, 0, NULL, ZEND_FUNCTION_DTOR, 0);
53 	/* class_table is usually destroyed by free_persistent_script() that
54 	 * overrides destructor. ZEND_CLASS_DTOR may be used by standard
55 	 * PHP compiler
56 	 */
57 	zend_hash_init(&persistent_script->script.class_table, 0, NULL, ZEND_CLASS_DTOR, 0);
58 
59 	return persistent_script;
60 }
61 
free_persistent_script(zend_persistent_script * persistent_script,int destroy_elements)62 void free_persistent_script(zend_persistent_script *persistent_script, int destroy_elements)
63 {
64 	if (!destroy_elements) {
65 		/* Both the keys and values have been transferred into the global tables.
66 		 * Set nNumUsed=0 to only deallocate the table, but not destroy any elements. */
67 		persistent_script->script.function_table.nNumUsed = 0;
68 		persistent_script->script.class_table.nNumUsed = 0;
69 	} else {
70 		destroy_op_array(&persistent_script->script.main_op_array);
71 	}
72 
73 	zend_hash_destroy(&persistent_script->script.function_table);
74 	zend_hash_destroy(&persistent_script->script.class_table);
75 
76 	if (persistent_script->script.filename) {
77 		zend_string_release_ex(persistent_script->script.filename, 0);
78 	}
79 
80 	efree(persistent_script);
81 }
82 
zend_accel_move_user_functions(HashTable * src,uint32_t count,zend_script * script)83 void zend_accel_move_user_functions(HashTable *src, uint32_t count, zend_script *script)
84 {
85 	Bucket *p, *end;
86 	HashTable *dst;
87 	zend_string *filename;
88 	dtor_func_t orig_dtor;
89 	zend_function *function;
90 
91 	if (!count) {
92 		return;
93 	}
94 
95 	dst = &script->function_table;
96 	filename = script->main_op_array.filename;
97 	orig_dtor = src->pDestructor;
98 	src->pDestructor = NULL;
99 	zend_hash_extend(dst, count, 0);
100 	end = src->arData + src->nNumUsed;
101 	p = end - count;
102 	for (; p != end; p++) {
103 		if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
104 		function = Z_PTR(p->val);
105 		if (EXPECTED(function->type == ZEND_USER_FUNCTION)
106 		 && EXPECTED(function->op_array.filename == filename)) {
107 			_zend_hash_append_ptr(dst, p->key, function);
108 			zend_hash_del_bucket(src, p);
109 		}
110 	}
111 	src->pDestructor = orig_dtor;
112 }
113 
zend_accel_move_user_classes(HashTable * src,uint32_t count,zend_script * script)114 void zend_accel_move_user_classes(HashTable *src, uint32_t count, zend_script *script)
115 {
116 	Bucket *p, *end;
117 	HashTable *dst;
118 	zend_string *filename;
119 	dtor_func_t orig_dtor;
120 	zend_class_entry *ce;
121 
122 	if (!count) {
123 		return;
124 	}
125 
126 	dst = &script->class_table;
127 	filename = script->main_op_array.filename;
128 	orig_dtor = src->pDestructor;
129 	src->pDestructor = NULL;
130 	zend_hash_extend(dst, count, 0);
131 	end = src->arData + src->nNumUsed;
132 	p = end - count;
133 	for (; p != end; p++) {
134 		if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
135 		ce = Z_PTR(p->val);
136 		if (EXPECTED(ce->type == ZEND_USER_CLASS)
137 		 && EXPECTED(ce->info.user.filename == filename)) {
138 			_zend_hash_append_ptr(dst, p->key, ce);
139 			zend_hash_del_bucket(src, p);
140 		}
141 	}
142 	src->pDestructor = orig_dtor;
143 }
144 
zend_hash_clone_constants(HashTable * ht)145 static void zend_hash_clone_constants(HashTable *ht)
146 {
147 	Bucket *p, *end;
148 	zend_class_constant *c;
149 
150 	if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
151 		return;
152 	}
153 
154 	p = emalloc(HT_SIZE(ht));
155 	memcpy(p, HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht));
156 	HT_SET_DATA_ADDR(ht, p);
157 
158 	p = ht->arData;
159 	end = p + ht->nNumUsed;
160 	for (; p != end; p++) {
161 		ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
162 		c = Z_PTR(p->val);
163 		if (IN_ARENA(c)) {
164 			c = ARENA_REALLOC(c);
165 			Z_PTR(p->val) = c;
166 
167 			if (IN_ARENA(c->ce)) {
168 				c->ce = ARENA_REALLOC(c->ce);
169 			}
170 		}
171 	}
172 }
173 
zend_hash_clone_methods(HashTable * ht)174 static void zend_hash_clone_methods(HashTable *ht)
175 {
176 	Bucket *p, *end;
177 	zend_op_array *new_entry;
178 
179 	ht->pDestructor = ZEND_FUNCTION_DTOR;
180 
181 	if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
182 		return;
183 	}
184 
185 	p = emalloc(HT_SIZE(ht));
186 	memcpy(p, HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht));
187 	HT_SET_DATA_ADDR(ht, p);
188 
189 	p = ht->arData;
190 	end = p + ht->nNumUsed;
191 	for (; p != end; p++) {
192 		ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
193 		new_entry = Z_PTR(p->val);
194 		if (IN_ARENA(new_entry)) {
195 			new_entry = ARENA_REALLOC(new_entry);
196 			Z_PTR(p->val) = new_entry;
197 
198 			if (IN_ARENA(new_entry->scope)) {
199 				new_entry->scope = ARENA_REALLOC(new_entry->scope);
200 
201 				/* update prototype */
202 				if (IN_ARENA(new_entry->prototype)) {
203 					new_entry->prototype = ARENA_REALLOC(new_entry->prototype);
204 				}
205 			}
206 			if (IN_ARENA(ZEND_MAP_PTR(new_entry->run_time_cache))) {
207 				ZEND_MAP_PTR_INIT(new_entry->run_time_cache, ARENA_REALLOC(ZEND_MAP_PTR(new_entry->run_time_cache)));
208 			}
209 			ZEND_MAP_PTR_INIT(new_entry->static_variables_ptr, &new_entry->static_variables);
210 		}
211 	}
212 }
213 
zend_hash_clone_prop_info(HashTable * ht)214 static void zend_hash_clone_prop_info(HashTable *ht)
215 {
216 	Bucket *p, *end;
217 	zend_property_info *prop_info;
218 
219 	if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
220 		return;
221 	}
222 
223 	p = emalloc(HT_SIZE(ht));
224 	memcpy(p, HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht));
225 	HT_SET_DATA_ADDR(ht, p);
226 
227 	p = ht->arData;
228 	end = p + ht->nNumUsed;
229 	for (; p != end; p++) {
230 		ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
231 		prop_info = Z_PTR(p->val);
232 		if (IN_ARENA(prop_info)) {
233 			prop_info = ARENA_REALLOC(prop_info);
234 			Z_PTR(p->val) = prop_info;
235 
236 			if (IN_ARENA(prop_info->ce)) {
237 				prop_info->ce = ARENA_REALLOC(prop_info->ce);
238 			}
239 
240 			if (ZEND_TYPE_HAS_LIST(prop_info->type)) {
241 				zend_type_list *list = ZEND_TYPE_LIST(prop_info->type);
242 				if (IN_ARENA(list)) {
243 					list = ARENA_REALLOC(list);
244 					ZEND_TYPE_SET_PTR(prop_info->type, list);
245 
246 					zend_type *list_type;
247 					ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(prop_info->type), list_type) {
248 						if (ZEND_TYPE_HAS_CE(*list_type)) {
249 							zend_class_entry *ce = ZEND_TYPE_CE(*list_type);
250 							if (IN_ARENA(ce)) {
251 								ce = ARENA_REALLOC(ce);
252 								ZEND_TYPE_SET_PTR(*list_type, ce);
253 							}
254 						}
255 					} ZEND_TYPE_LIST_FOREACH_END();
256 				}
257 			} else if (ZEND_TYPE_HAS_CE(prop_info->type)) {
258 				zend_class_entry *ce = ZEND_TYPE_CE(prop_info->type);
259 				if (IN_ARENA(ce)) {
260 					ce = ARENA_REALLOC(ce);
261 					ZEND_TYPE_SET_PTR(prop_info->type, ce);
262 				}
263 			}
264 		}
265 	}
266 }
267 
268 #define zend_update_inherited_handler(handler) \
269 { \
270 	if (ce->handler != NULL && IN_ARENA(ce->handler)) { \
271 		ce->handler = ARENA_REALLOC(ce->handler); \
272 	} \
273 }
274 
275 /* Protects class' refcount, copies default properties, functions and class name */
zend_class_copy_ctor(zend_class_entry ** pce)276 static void zend_class_copy_ctor(zend_class_entry **pce)
277 {
278 	zend_class_entry *ce = *pce;
279 	zval *src, *dst, *end;
280 
281 	*pce = ce = ARENA_REALLOC(ce);
282 	ce->refcount = 1;
283 
284 	if ((ce->ce_flags & ZEND_ACC_LINKED) && IN_ARENA(ce->parent)) {
285 		ce->parent = ARENA_REALLOC(ce->parent);
286 	}
287 
288 	if (ce->default_properties_table) {
289 		dst = emalloc(sizeof(zval) * ce->default_properties_count);
290 		src = ce->default_properties_table;
291 		end = src + ce->default_properties_count;
292 		ce->default_properties_table = dst;
293 		for (; src != end; src++, dst++) {
294 			ZVAL_COPY_VALUE_PROP(dst, src);
295 		}
296 	}
297 
298 	zend_hash_clone_methods(&ce->function_table);
299 
300 	/* static members */
301 	if (ce->default_static_members_table) {
302 		int i, end;
303 		zend_class_entry *parent = !(ce->ce_flags & ZEND_ACC_LINKED) ? NULL : ce->parent;
304 
305 		dst = emalloc(sizeof(zval) * ce->default_static_members_count);
306 		src = ce->default_static_members_table;
307 		ce->default_static_members_table = dst;
308 		i = ce->default_static_members_count - 1;
309 
310 		/* Copy static properties in this class */
311 		end = parent ? parent->default_static_members_count : 0;
312 		for (; i >= end; i--) {
313 			zval *p = &dst[i];
314 			ZVAL_COPY_VALUE(p, &src[i]);
315 		}
316 
317 		/* Create indirections to static properties from parent classes */
318 		while (parent && parent->default_static_members_table) {
319 			end = parent->parent ? parent->parent->default_static_members_count : 0;
320 			for (; i >= end; i--) {
321 				zval *p = &dst[i];
322 				ZVAL_INDIRECT(p, &parent->default_static_members_table[i]);
323 			}
324 
325 			parent = parent->parent;
326 		}
327 	}
328 	ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
329 
330 	/* properties_info */
331 	zend_hash_clone_prop_info(&ce->properties_info);
332 
333 	/* constants table */
334 	zend_hash_clone_constants(&ce->constants_table);
335 
336 	if (ce->properties_info_table) {
337 		int i;
338 		ce->properties_info_table = ARENA_REALLOC(ce->properties_info_table);
339 		for (i = 0; i < ce->default_properties_count; i++) {
340 			if (IN_ARENA(ce->properties_info_table[i])) {
341 				ce->properties_info_table[i] = ARENA_REALLOC(ce->properties_info_table[i]);
342 			}
343 		}
344 	}
345 
346 	if (ce->num_interfaces) {
347 		zend_class_name *interface_names;
348 
349 		if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
350 			interface_names = emalloc(sizeof(zend_class_name) * ce->num_interfaces);
351 			memcpy(interface_names, ce->interface_names, sizeof(zend_class_name) * ce->num_interfaces);
352 			ce->interface_names = interface_names;
353 		} else {
354 			zend_class_entry **interfaces = emalloc(sizeof(zend_class_entry*) * ce->num_interfaces);
355 			uint32_t i;
356 
357 			for (i = 0; i < ce->num_interfaces; i++) {
358 				if (IN_ARENA(ce->interfaces[i])) {
359 					interfaces[i] = ARENA_REALLOC(ce->interfaces[i]);
360 				} else {
361 					interfaces[i] = ce->interfaces[i];
362 				}
363 			}
364 			ce->interfaces = interfaces;
365 		}
366 	}
367 
368 	zend_update_inherited_handler(constructor);
369 	zend_update_inherited_handler(destructor);
370 	zend_update_inherited_handler(clone);
371 	zend_update_inherited_handler(__get);
372 	zend_update_inherited_handler(__set);
373 	zend_update_inherited_handler(__call);
374 	zend_update_inherited_handler(__isset);
375 	zend_update_inherited_handler(__unset);
376 	zend_update_inherited_handler(__tostring);
377 	zend_update_inherited_handler(__callstatic);
378 	zend_update_inherited_handler(__debugInfo);
379 	zend_update_inherited_handler(__serialize);
380 	zend_update_inherited_handler(__unserialize);
381 
382 /* 5.4 traits */
383 	if (ce->num_traits) {
384 		zend_class_name *trait_names = emalloc(sizeof(zend_class_name) * ce->num_traits);
385 
386 		memcpy(trait_names, ce->trait_names, sizeof(zend_class_name) * ce->num_traits);
387 		ce->trait_names = trait_names;
388 
389 		if (ce->trait_aliases) {
390 			zend_trait_alias **trait_aliases;
391 			int i = 0;
392 
393 			while (ce->trait_aliases[i]) {
394 				i++;
395 			}
396 			trait_aliases = emalloc(sizeof(zend_trait_alias*) * (i + 1));
397 			i = 0;
398 			while (ce->trait_aliases[i]) {
399 				trait_aliases[i] = emalloc(sizeof(zend_trait_alias));
400 				memcpy(trait_aliases[i], ce->trait_aliases[i], sizeof(zend_trait_alias));
401 				i++;
402 			}
403 			trait_aliases[i] = NULL;
404 			ce->trait_aliases = trait_aliases;
405 		}
406 
407 		if (ce->trait_precedences) {
408 			zend_trait_precedence **trait_precedences;
409 			int i = 0;
410 
411 			while (ce->trait_precedences[i]) {
412 				i++;
413 			}
414 			trait_precedences = emalloc(sizeof(zend_trait_precedence*) * (i + 1));
415 			i = 0;
416 			while (ce->trait_precedences[i]) {
417 				trait_precedences[i] = emalloc(sizeof(zend_trait_precedence) + (ce->trait_precedences[i]->num_excludes - 1) * sizeof(zend_string*));
418 				memcpy(trait_precedences[i], ce->trait_precedences[i], sizeof(zend_trait_precedence) + (ce->trait_precedences[i]->num_excludes - 1) * sizeof(zend_string*));
419 				i++;
420 			}
421 			trait_precedences[i] = NULL;
422 			ce->trait_precedences = trait_precedences;
423 		}
424 	}
425 }
426 
zend_accel_function_hash_copy(HashTable * target,HashTable * source)427 static void zend_accel_function_hash_copy(HashTable *target, HashTable *source)
428 {
429 	zend_function *function1, *function2;
430 	Bucket *p, *end;
431 	zval *t;
432 
433 	zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
434 	p = source->arData;
435 	end = p + source->nNumUsed;
436 	for (; p != end; p++) {
437 		ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
438 		ZEND_ASSERT(p->key);
439 		t = zend_hash_find_ex(target, p->key, 1);
440 		if (UNEXPECTED(t != NULL)) {
441 			if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
442 				/* Runtime definition key. There are two circumstances under which the key can
443 				 * already be defined:
444 				 *  1. The file has been re-included without being changed in the meantime. In
445 				 *     this case we can keep the old value, because we know that the definition
446 				 *     hasn't changed.
447 				 *  2. The file has been changed in the meantime, but the RTD key ends up colliding.
448 				 *     This would be a bug.
449 				 * As we can't distinguish these cases, we assume that it is 1. and keep the old
450 				 * value. */
451 				continue;
452 			} else {
453 				goto failure;
454 			}
455 		} else {
456 			_zend_hash_append_ptr(target, p->key, Z_PTR(p->val));
457 		}
458 	}
459 	target->nInternalPointer = 0;
460 	return;
461 
462 failure:
463 	function1 = Z_PTR(p->val);
464 	function2 = Z_PTR_P(t);
465 	CG(in_compilation) = 1;
466 	zend_set_compiled_filename(function1->op_array.filename);
467 	CG(zend_lineno) = function1->op_array.opcodes[0].lineno;
468 	if (function2->type == ZEND_USER_FUNCTION
469 		&& function2->op_array.last > 0) {
470 		zend_error(E_ERROR, "Cannot redeclare %s() (previously declared in %s:%d)",
471 				   ZSTR_VAL(function1->common.function_name),
472 				   ZSTR_VAL(function2->op_array.filename),
473 				   (int)function2->op_array.opcodes[0].lineno);
474 	} else {
475 		zend_error(E_ERROR, "Cannot redeclare %s()", ZSTR_VAL(function1->common.function_name));
476 	}
477 }
478 
zend_accel_function_hash_copy_from_shm(HashTable * target,HashTable * source)479 static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable *source)
480 {
481 	zend_function *function1, *function2;
482 	Bucket *p, *end;
483 	zval *t;
484 
485 	zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
486 	p = source->arData;
487 	end = p + source->nNumUsed;
488 	for (; p != end; p++) {
489 		ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
490 		ZEND_ASSERT(p->key);
491 		t = zend_hash_find_ex(target, p->key, 1);
492 		if (UNEXPECTED(t != NULL)) {
493 			if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
494 				/* See comment in zend_accel_function_hash_copy(). */
495 				continue;
496 			} else {
497 				goto failure;
498 			}
499 		} else {
500 			_zend_hash_append_ptr_ex(target, p->key, Z_PTR(p->val), 1);
501 		}
502 	}
503 	target->nInternalPointer = 0;
504 	return;
505 
506 failure:
507 	function1 = Z_PTR(p->val);
508 	function2 = Z_PTR_P(t);
509 	CG(in_compilation) = 1;
510 	zend_set_compiled_filename(function1->op_array.filename);
511 	CG(zend_lineno) = function1->op_array.opcodes[0].lineno;
512 	if (function2->type == ZEND_USER_FUNCTION
513 		&& function2->op_array.last > 0) {
514 		zend_error(E_ERROR, "Cannot redeclare %s() (previously declared in %s:%d)",
515 				   ZSTR_VAL(function1->common.function_name),
516 				   ZSTR_VAL(function2->op_array.filename),
517 				   (int)function2->op_array.opcodes[0].lineno);
518 	} else {
519 		zend_error(E_ERROR, "Cannot redeclare %s()", ZSTR_VAL(function1->common.function_name));
520 	}
521 }
522 
zend_accel_class_hash_copy(HashTable * target,HashTable * source)523 static void zend_accel_class_hash_copy(HashTable *target, HashTable *source)
524 {
525 	Bucket *p, *end;
526 	zval *t;
527 
528 	zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
529 	p = source->arData;
530 	end = p + source->nNumUsed;
531 	for (; p != end; p++) {
532 		if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
533 		ZEND_ASSERT(p->key);
534 		t = zend_hash_find_ex(target, p->key, 1);
535 		if (UNEXPECTED(t != NULL)) {
536 			if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
537 				/* See comment in zend_accel_function_hash_copy(). */
538 				continue;
539 			} else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
540 				zend_class_entry *ce1 = Z_PTR(p->val);
541 				if (!(ce1->ce_flags & ZEND_ACC_ANON_CLASS)) {
542 					CG(in_compilation) = 1;
543 					zend_set_compiled_filename(ce1->info.user.filename);
544 					CG(zend_lineno) = ce1->info.user.line_start;
545 					zend_error(E_ERROR,
546 							"Cannot declare %s %s, because the name is already in use",
547 							zend_get_object_type(ce1), ZSTR_VAL(ce1->name));
548 					return;
549 				}
550 				continue;
551 			}
552 		} else {
553 			t = _zend_hash_append_ptr(target, p->key, Z_PTR(p->val));
554 		}
555 	}
556 	target->nInternalPointer = 0;
557 	return;
558 }
559 
zend_accel_class_hash_copy_from_shm(HashTable * target,HashTable * source)560 static void zend_accel_class_hash_copy_from_shm(HashTable *target, HashTable *source)
561 {
562 	Bucket *p, *end;
563 	zval *t;
564 
565 	zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
566 	p = source->arData;
567 	end = p + source->nNumUsed;
568 	for (; p != end; p++) {
569 		ZEND_ASSERT(Z_TYPE(p->val) != IS_UNDEF);
570 		ZEND_ASSERT(p->key);
571 		t = zend_hash_find_ex(target, p->key, 1);
572 		if (UNEXPECTED(t != NULL)) {
573 			if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
574 				/* See comment in zend_accel_function_hash_copy(). */
575 				continue;
576 			} else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
577 				zend_class_entry *ce1 = Z_PTR(p->val);
578 				if (!(ce1->ce_flags & ZEND_ACC_ANON_CLASS)) {
579 					CG(in_compilation) = 1;
580 					zend_set_compiled_filename(ce1->info.user.filename);
581 					CG(zend_lineno) = ce1->info.user.line_start;
582 					zend_error(E_ERROR,
583 							"Cannot declare %s %s, because the name is already in use",
584 							zend_get_object_type(ce1), ZSTR_VAL(ce1->name));
585 					return;
586 				}
587 				continue;
588 			}
589 		} else {
590 			t = _zend_hash_append_ptr_ex(target, p->key, Z_PTR(p->val), 1);
591 			if (!(((zend_class_entry*)Z_PTR_P(t))->ce_flags & ZEND_ACC_IMMUTABLE)) {
592 				zend_class_copy_ctor((zend_class_entry**)&Z_PTR_P(t));
593 			}
594 		}
595 	}
596 	target->nInternalPointer = 0;
597 	return;
598 }
599 
600 #if __has_feature(memory_sanitizer)
601 # define fast_memcpy memcpy
602 #elif defined(__AVX__)
603 # include <nmmintrin.h>
604 # if defined(__GNUC__) && defined(__i386__)
fast_memcpy(void * dest,const void * src,size_t size)605 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
606 {
607 	size_t delta = (char*)dest - (char*)src;
608 
609 	__asm__ volatile (
610 		".align 16\n\t"
611 		".LL0%=:\n\t"
612 		"prefetchnta 0x40(%1)\n\t"
613 		"vmovaps (%1), %%ymm0\n\t"
614 		"vmovaps 0x20(%1), %%ymm1\n\t"
615 		"vmovaps %%ymm0, (%1,%2)\n\t"
616 		"vmovaps %%ymm1, 0x20(%1,%2)\n\t"
617 		"addl $0x40, %1\n\t"
618 		"subl $0x40, %0\n\t"
619 		"ja .LL0%="
620 		: "+r"(size),
621 		"+r"(src)
622 		: "r"(delta)
623 		: "cc", "memory", "%ymm0", "%ymm1");
624 }
625 # elif defined(__GNUC__) && defined(__x86_64__)
fast_memcpy(void * dest,const void * src,size_t size)626 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
627 {
628 	size_t delta = (char*)dest - (char*)src;
629 
630 	__asm__ volatile (
631 		".align 16\n\t"
632 		".LL0%=:\n\t"
633 		"prefetchnta 0x40(%1)\n\t"
634 		"vmovaps (%1), %%ymm0\n\t"
635 		"vmovaps 0x20(%1), %%ymm1\n\t"
636 		"vmovaps %%ymm0, (%1,%2)\n\t"
637 		"vmovaps %%ymm1, 0x20(%1,%2)\n\t"
638 		"addq $0x40, %1\n\t"
639 		"subq $0x40, %0\n\t"
640 		"ja .LL0%="
641 		: "+r"(size),
642 		"+r"(src)
643 		: "r"(delta)
644 		: "cc", "memory", "%ymm0", "%ymm1");
645 }
646 # else
fast_memcpy(void * dest,const void * src,size_t size)647 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
648 {
649 	__m256 *dqdest = (__m256*)dest;
650 	const __m256 *dqsrc  = (const __m256*)src;
651 	const __m256 *end  = (const __m256*)((const char*)src + size);
652 
653 	do {
654 #ifdef PHP_WIN32
655 		_mm_prefetch((const char *)(dqsrc + 2), _MM_HINT_NTA);
656 #else
657 		_mm_prefetch(dqsrc + 2, _MM_HINT_NTA);
658 #endif
659 
660 		__m256 ymm0 = _mm256_load_ps((const float *)(dqsrc + 0));
661 		__m256 ymm1 = _mm256_load_ps((const float *)(dqsrc + 1));
662 		dqsrc  += 2;
663 		_mm256_store_ps((float *)(dqdest + 0), ymm0);
664 		_mm256_store_ps((float *)(dqdest + 1), ymm1);
665 		dqdest += 2;
666 	} while (dqsrc != end);
667 }
668 # endif
669 #elif defined(__SSE2__)
670 # include <emmintrin.h>
671 # if defined(__GNUC__) && defined(__i386__)
fast_memcpy(void * dest,const void * src,size_t size)672 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
673 {
674 	size_t delta = (char*)dest - (char*)src;
675 
676 	__asm__ volatile (
677 		".align 16\n\t"
678 		".LL0%=:\n\t"
679 		"prefetchnta 0x40(%1)\n\t"
680 		"movdqa (%1), %%xmm0\n\t"
681 		"movdqa 0x10(%1), %%xmm1\n\t"
682 		"movdqa 0x20(%1), %%xmm2\n\t"
683 		"movdqa 0x30(%1), %%xmm3\n\t"
684 		"movdqa %%xmm0, (%1,%2)\n\t"
685 		"movdqa %%xmm1, 0x10(%1,%2)\n\t"
686 		"movdqa %%xmm2, 0x20(%1,%2)\n\t"
687 		"movdqa %%xmm3, 0x30(%1,%2)\n\t"
688 		"addl $0x40, %1\n\t"
689 		"subl $0x40, %0\n\t"
690 		"ja .LL0%="
691 		: "+r"(size),
692 		  "+r"(src)
693 		: "r"(delta)
694 		: "cc", "memory", "%xmm0", "%xmm1", "%xmm1", "%xmm2");
695 }
696 # elif defined(__GNUC__) && defined(__x86_64__) && !defined(__ILP32__)
fast_memcpy(void * dest,const void * src,size_t size)697 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
698 {
699 	size_t delta = (char*)dest - (char*)src;
700 
701 	__asm__ volatile (
702 		".align 16\n\t"
703 		".LL0%=:\n\t"
704 		"prefetchnta 0x40(%1)\n\t"
705 		"movdqa (%1), %%xmm0\n\t"
706 		"movdqa 0x10(%1), %%xmm1\n\t"
707 		"movdqa 0x20(%1), %%xmm2\n\t"
708 		"movdqa 0x30(%1), %%xmm3\n\t"
709 		"movdqa %%xmm0, (%1,%2)\n\t"
710 		"movdqa %%xmm1, 0x10(%1,%2)\n\t"
711 		"movdqa %%xmm2, 0x20(%1,%2)\n\t"
712 		"movdqa %%xmm3, 0x30(%1,%2)\n\t"
713 		"addq $0x40, %1\n\t"
714 		"subq $0x40, %0\n\t"
715 		"ja .LL0%="
716 		: "+r"(size),
717 		  "+r"(src)
718 		: "r"(delta)
719 		: "cc", "memory", "%xmm0", "%xmm1", "%xmm1", "%xmm2");
720 }
721 # else
fast_memcpy(void * dest,const void * src,size_t size)722 static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
723 {
724 	__m128i *dqdest = (__m128i*)dest;
725 	const __m128i *dqsrc  = (const __m128i*)src;
726 	const __m128i *end  = (const __m128i*)((const char*)src + size);
727 
728 	do {
729 #ifdef PHP_WIN32
730 		_mm_prefetch((const char *)(dqsrc + 4), _MM_HINT_NTA);
731 #else
732 		_mm_prefetch(dqsrc + 4, _MM_HINT_NTA);
733 #endif
734 
735 		__m128i xmm0 = _mm_load_si128(dqsrc + 0);
736 		__m128i xmm1 = _mm_load_si128(dqsrc + 1);
737 		__m128i xmm2 = _mm_load_si128(dqsrc + 2);
738 		__m128i xmm3 = _mm_load_si128(dqsrc + 3);
739 		dqsrc  += 4;
740 		_mm_store_si128(dqdest + 0, xmm0);
741 		_mm_store_si128(dqdest + 1, xmm1);
742 		_mm_store_si128(dqdest + 2, xmm2);
743 		_mm_store_si128(dqdest + 3, xmm3);
744 		dqdest += 4;
745 	} while (dqsrc != end);
746 }
747 # endif
748 #endif
749 
zend_accel_load_script(zend_persistent_script * persistent_script,int from_shared_memory)750 zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory)
751 {
752 	zend_op_array *op_array;
753 
754 	op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
755 	*op_array = persistent_script->script.main_op_array;
756 	ZEND_MAP_PTR_INIT(op_array->static_variables_ptr, &op_array->static_variables);
757 
758 	if (EXPECTED(from_shared_memory)) {
759 		zend_hash_init(&ZCG(bind_hash), 10, NULL, NULL, 0);
760 
761 		ZCG(current_persistent_script) = persistent_script;
762 		ZCG(arena_mem) = NULL;
763 		if (EXPECTED(persistent_script->arena_size)) {
764 #if defined(__AVX__) || defined(__SSE2__)
765 			/* Target address must be aligned to 64-byte boundary */
766 			_mm_prefetch(persistent_script->arena_mem, _MM_HINT_NTA);
767 			ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size + 64);
768 			ZCG(arena_mem) = (void*)(((zend_uintptr_t)ZCG(arena_mem) + 63L) & ~63L);
769 			fast_memcpy(ZCG(arena_mem), persistent_script->arena_mem, persistent_script->arena_size);
770 #else
771 			ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size);
772 			memcpy(ZCG(arena_mem), persistent_script->arena_mem, persistent_script->arena_size);
773 #endif
774 		}
775 
776 		/* Copy all the necessary stuff from shared memory to regular memory, and protect the shared script */
777 		if (zend_hash_num_elements(&persistent_script->script.class_table) > 0) {
778 			zend_accel_class_hash_copy_from_shm(CG(class_table), &persistent_script->script.class_table);
779 		}
780 		/* we must first to copy all classes and then prepare functions, since functions may try to bind
781 		   classes - which depend on pre-bind class entries existent in the class table */
782 		if (zend_hash_num_elements(&persistent_script->script.function_table) > 0) {
783 			zend_accel_function_hash_copy_from_shm(CG(function_table), &persistent_script->script.function_table);
784 		}
785 
786 		/* Register __COMPILER_HALT_OFFSET__ constant */
787 		if (persistent_script->compiler_halt_offset != 0 &&
788 		    persistent_script->script.filename) {
789 			zend_string *name;
790 			static const char haltoff[] = "__COMPILER_HALT_OFFSET__";
791 
792 			name = zend_mangle_property_name(haltoff, sizeof(haltoff) - 1, ZSTR_VAL(persistent_script->script.filename), ZSTR_LEN(persistent_script->script.filename), 0);
793 			if (!zend_hash_exists(EG(zend_constants), name)) {
794 				zend_register_long_constant(ZSTR_VAL(name), ZSTR_LEN(name), persistent_script->compiler_halt_offset, CONST_CS, 0);
795 			}
796 			zend_string_release_ex(name, 0);
797 		}
798 
799 		zend_hash_destroy(&ZCG(bind_hash));
800 		ZCG(current_persistent_script) = NULL;
801 		zend_map_ptr_extend(ZCSG(map_ptr_last));
802 	} else /* if (!from_shared_memory) */ {
803 		if (zend_hash_num_elements(&persistent_script->script.function_table) > 0) {
804 			zend_accel_function_hash_copy(CG(function_table), &persistent_script->script.function_table);
805 		}
806 		if (zend_hash_num_elements(&persistent_script->script.class_table) > 0) {
807 			zend_accel_class_hash_copy(CG(class_table), &persistent_script->script.class_table);
808 		}
809 	}
810 
811 	if (persistent_script->script.first_early_binding_opline != (uint32_t)-1) {
812 		zend_string *orig_compiled_filename = CG(compiled_filename);
813 		CG(compiled_filename) = persistent_script->script.filename;
814 		zend_do_delayed_early_binding(op_array, persistent_script->script.first_early_binding_opline);
815 		CG(compiled_filename) = orig_compiled_filename;
816 	}
817 
818 	if (UNEXPECTED(!from_shared_memory)) {
819 		free_persistent_script(persistent_script, 0); /* free only hashes */
820 	}
821 
822 	return op_array;
823 }
824 
825 /*
826  * zend_adler32() is based on zlib implementation
827  * Computes the Adler-32 checksum of a data stream
828  *
829  * Copyright (C) 1995-2005 Mark Adler
830  * For conditions of distribution and use, see copyright notice in zlib.h
831  *
832  * Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
833  *
834  *  This software is provided 'as-is', without any express or implied
835  *  warranty.  In no event will the authors be held liable for any damages
836  *  arising from the use of this software.
837  *
838  *  Permission is granted to anyone to use this software for any purpose,
839  *  including commercial applications, and to alter it and redistribute it
840  *  freely, subject to the following restrictions:
841  *
842  *  1. The origin of this software must not be misrepresented; you must not
843  *     claim that you wrote the original software. If you use this software
844  *     in a product, an acknowledgment in the product documentation would be
845  *     appreciated but is not required.
846  *  2. Altered source versions must be plainly marked as such, and must not be
847  *     misrepresented as being the original software.
848  *  3. This notice may not be removed or altered from any source distribution.
849  *
850  */
851 
852 #define ADLER32_BASE 65521 /* largest prime smaller than 65536 */
853 #define ADLER32_NMAX 5552
854 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
855 
856 #define ADLER32_DO1(buf)        {s1 += *(buf); s2 += s1;}
857 #define ADLER32_DO2(buf, i)     ADLER32_DO1(buf + i); ADLER32_DO1(buf + i + 1);
858 #define ADLER32_DO4(buf, i)     ADLER32_DO2(buf, i); ADLER32_DO2(buf, i + 2);
859 #define ADLER32_DO8(buf, i)     ADLER32_DO4(buf, i); ADLER32_DO4(buf, i + 4);
860 #define ADLER32_DO16(buf)       ADLER32_DO8(buf, 0); ADLER32_DO8(buf, 8);
861 
zend_adler32(unsigned int checksum,unsigned char * buf,uint32_t len)862 unsigned int zend_adler32(unsigned int checksum, unsigned char *buf, uint32_t len)
863 {
864 	unsigned int s1 = checksum & 0xffff;
865 	unsigned int s2 = (checksum >> 16) & 0xffff;
866 	unsigned char *end;
867 
868 	while (len >= ADLER32_NMAX) {
869 		len -= ADLER32_NMAX;
870 		end = buf + ADLER32_NMAX;
871 		do {
872 			ADLER32_DO16(buf);
873 			buf += 16;
874 		} while (buf != end);
875 		s1 %= ADLER32_BASE;
876 		s2 %= ADLER32_BASE;
877 	}
878 
879 	if (len) {
880 		if (len >= 16) {
881 			end = buf + (len & 0xfff0);
882 			len &= 0xf;
883 			do {
884 				ADLER32_DO16(buf);
885 				buf += 16;
886 			} while (buf != end);
887 		}
888 		if (len) {
889 			end = buf + len;
890 			do {
891 				ADLER32_DO1(buf);
892 				buf++;
893 			} while (buf != end);
894 		}
895 		s1 %= ADLER32_BASE;
896 		s2 %= ADLER32_BASE;
897 	}
898 
899 	return (s2 << 16) | s1;
900 }
901 
zend_accel_script_checksum(zend_persistent_script * persistent_script)902 unsigned int zend_accel_script_checksum(zend_persistent_script *persistent_script)
903 {
904 	unsigned char *mem = (unsigned char*)persistent_script->mem;
905 	size_t size = persistent_script->size;
906 	size_t persistent_script_check_block_size = ((char *)&(persistent_script->dynamic_members)) - (char *)persistent_script;
907 	unsigned int checksum = ADLER32_INIT;
908 
909 	if (mem < (unsigned char*)persistent_script) {
910 		checksum = zend_adler32(checksum, mem, (unsigned char*)persistent_script - mem);
911 		size -= (unsigned char*)persistent_script - mem;
912 		mem  += (unsigned char*)persistent_script - mem;
913 	}
914 
915 	zend_adler32(checksum, mem, persistent_script_check_block_size);
916 	mem  += sizeof(*persistent_script);
917 	size -= sizeof(*persistent_script);
918 
919 	if (size > 0) {
920 		checksum = zend_adler32(checksum, mem, size);
921 	}
922 	return checksum;
923 }
924