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