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