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@zend.com>                                |
16    |          Zeev Suraski <zeev@zend.com>                                |
17    |          Stanislav Malyshev <stas@zend.com>                          |
18    |          Dmitry Stogov <dmitry@zend.com>                             |
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*), (old))
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_REFCOUNT(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 	destroy_zend_function(function);
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(persistent_script->script.filename);
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 
copy_internal_function(zval * zv,HashTable * function_table)138 static int copy_internal_function(zval *zv, HashTable *function_table)
139 {
140 	zend_internal_function *function = Z_PTR_P(zv);
141 	if (function->type == ZEND_INTERNAL_FUNCTION) {
142 		zend_hash_update_mem(function_table, function->function_name, function, sizeof(zend_internal_function));
143 	}
144 	return 0;
145 }
146 
zend_accel_copy_internal_functions(void)147 void zend_accel_copy_internal_functions(void)
148 {
149 	zend_hash_apply_with_argument(CG(function_table), (apply_func_arg_t)copy_internal_function, &ZCG(function_table));
150 	ZCG(internal_functions_count) = zend_hash_num_elements(&ZCG(function_table));
151 }
152 
zend_clone_zval(zval * src)153 static inline void zend_clone_zval(zval *src)
154 {
155 	void *ptr;
156 
157 	if (Z_TYPE_P(src) == IS_REFERENCE) {
158 		ptr = accel_xlat_get(Z_REF_P(src));
159 		if (ptr != NULL) {
160 			Z_REF_P(src) = ptr;
161 			return;
162 		} else {
163 			zend_reference *old = Z_REF_P(src);
164 			ZVAL_NEW_REF(src, &old->val);
165 			Z_REF_P(src)->gc = old->gc;
166 			accel_xlat_set(old, Z_REF_P(src));
167 			src = Z_REFVAL_P(src);
168 		}
169 	}
170 }
171 
zend_hash_clone_constants(HashTable * ht,HashTable * source)172 static void zend_hash_clone_constants(HashTable *ht, HashTable *source)
173 {
174 	Bucket *p, *q, *end;
175 	zend_ulong nIndex;
176 	zend_class_constant *c;
177 
178 	ht->nTableSize = source->nTableSize;
179 	ht->nTableMask = source->nTableMask;
180 	ht->nNumUsed = 0;
181 	ht->nNumOfElements = source->nNumOfElements;
182 	ht->nNextFreeElement = source->nNextFreeElement;
183 	ht->pDestructor = NULL;
184 	ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED) | HASH_FLAG_APPLY_PROTECTION;
185 	ht->nInternalPointer = source->nNumOfElements ? 0 : HT_INVALID_IDX;
186 
187 	if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
188 		ht->arData = source->arData;
189 		return;
190 	}
191 
192 	ZEND_ASSERT((source->u.flags & HASH_FLAG_PACKED) == 0);
193 	HT_SET_DATA_ADDR(ht, emalloc(HT_SIZE(ht)));
194 	HT_HASH_RESET(ht);
195 
196 	p = source->arData;
197 	end = p + source->nNumUsed;
198 	for (; p != end; p++) {
199 		if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
200 		nIndex = p->h | ht->nTableMask;
201 
202 		/* Insert into hash collision list */
203 		q = ht->arData + ht->nNumUsed;
204 		Z_NEXT(q->val) = HT_HASH(ht, nIndex);
205 		HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(ht->nNumUsed++);
206 
207 		/* Initialize key */
208 		q->h = p->h;
209 		q->key = p->key;
210 
211 		/* Copy data */
212 		c = ARENA_REALLOC(Z_PTR(p->val));
213 		ZVAL_PTR(&q->val, c);
214 
215 		zend_clone_zval(&c->value);
216 		if ((void*)c->ce >= ZCG(current_persistent_script)->arena_mem &&
217 		    (void*)c->ce < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {
218 			c->ce = ARENA_REALLOC(c->ce);
219 		}
220 	}
221 }
222 
zend_hash_clone_methods(HashTable * ht,HashTable * source,zend_class_entry * old_ce,zend_class_entry * ce)223 static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce)
224 {
225 	Bucket *p, *q, *end;
226 	zend_ulong nIndex;
227 	zend_op_array *new_entry;
228 
229 	ht->nTableSize = source->nTableSize;
230 	ht->nTableMask = source->nTableMask;
231 	ht->nNumUsed = 0;
232 	ht->nNumOfElements = source->nNumOfElements;
233 	ht->nNextFreeElement = source->nNextFreeElement;
234 	ht->pDestructor = ZEND_FUNCTION_DTOR;
235 	ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED);
236 	ht->nInternalPointer = source->nNumOfElements ? 0 : HT_INVALID_IDX;
237 
238 	if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
239 		ht->arData = source->arData;
240 		return;
241 	}
242 
243 	ZEND_ASSERT(!(source->u.flags & HASH_FLAG_PACKED));
244 	HT_SET_DATA_ADDR(ht, emalloc(HT_SIZE(ht)));
245 	HT_HASH_RESET(ht);
246 
247 	p = source->arData;
248 	end = p + source->nNumUsed;
249 	for (; p != end; p++) {
250 		if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
251 
252 		nIndex = p->h | ht->nTableMask;
253 
254 		/* Insert into hash collision list */
255 		q = ht->arData + ht->nNumUsed;
256 		Z_NEXT(q->val) = HT_HASH(ht, nIndex);
257 		HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(ht->nNumUsed++);
258 
259 		/* Initialize key */
260 		q->h = p->h;
261 		ZEND_ASSERT(p->key != NULL);
262 		q->key = p->key;
263 
264 		/* Copy data */
265 		ZVAL_PTR(&q->val, ARENA_REALLOC(Z_PTR(p->val)));
266 		new_entry = (zend_op_array*)Z_PTR(q->val);
267 
268 		if ((void*)new_entry->scope >= ZCG(current_persistent_script)->arena_mem &&
269 		    (void*)new_entry->scope < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {
270 
271 			new_entry->scope = ARENA_REALLOC(new_entry->scope);
272 
273 			/* update prototype */
274 			if (new_entry->prototype) {
275 				new_entry->prototype = ARENA_REALLOC(new_entry->prototype);
276 			}
277 		}
278 	}
279 }
280 
zend_hash_clone_prop_info(HashTable * ht,HashTable * source,zend_class_entry * old_ce)281 static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_class_entry *old_ce)
282 {
283 	Bucket *p, *q, *end;
284 	zend_ulong nIndex;
285 	zend_property_info *prop_info;
286 
287 	ht->nTableSize = source->nTableSize;
288 	ht->nTableMask = source->nTableMask;
289 	ht->nNumUsed = 0;
290 	ht->nNumOfElements = source->nNumOfElements;
291 	ht->nNextFreeElement = source->nNextFreeElement;
292 	ht->pDestructor = NULL;
293 	ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED);
294 	ht->nInternalPointer = source->nNumOfElements ? 0 : HT_INVALID_IDX;
295 
296 	if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
297 		ht->arData = source->arData;
298 		return;
299 	}
300 
301 	ZEND_ASSERT(!(source->u.flags & HASH_FLAG_PACKED));
302 	HT_SET_DATA_ADDR(ht, emalloc(HT_SIZE(ht)));
303 	HT_HASH_RESET(ht);
304 
305 	p = source->arData;
306 	end = p + source->nNumUsed;
307 	for (; p != end; p++) {
308 		if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
309 
310 		nIndex = p->h | ht->nTableMask;
311 
312 		/* Insert into hash collision list */
313 		q = ht->arData + ht->nNumUsed;
314 		Z_NEXT(q->val) = HT_HASH(ht, nIndex);
315 		HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(ht->nNumUsed++);
316 
317 		/* Initialize key */
318 		q->h = p->h;
319 		ZEND_ASSERT(p->key != NULL);
320 		q->key = p->key;
321 
322 		/* Copy data */
323 		prop_info = ARENA_REALLOC(Z_PTR(p->val));
324 		ZVAL_PTR(&q->val, prop_info);
325 
326 		if ((void*)prop_info->ce >= ZCG(current_persistent_script)->arena_mem &&
327 		    (void*)prop_info->ce < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {
328 			prop_info->ce = ARENA_REALLOC(prop_info->ce);
329 		}
330 	}
331 }
332 
333 #define zend_update_inherited_handler(handler) \
334 { \
335 	if (ce->handler != NULL) { \
336 		ce->handler = ARENA_REALLOC(ce->handler); \
337 	} \
338 }
339 
340 /* Protects class' refcount, copies default properties, functions and class name */
zend_class_copy_ctor(zend_class_entry ** pce)341 static void zend_class_copy_ctor(zend_class_entry **pce)
342 {
343 	zend_class_entry *ce = *pce;
344 	zend_class_entry *old_ce = ce;
345 	zval *src, *dst, *end;
346 
347 	*pce = ce = ARENA_REALLOC(old_ce);
348 	ce->refcount = 1;
349 
350 	if (old_ce->default_properties_table) {
351 		ce->default_properties_table = emalloc(sizeof(zval) * old_ce->default_properties_count);
352 		src = old_ce->default_properties_table;
353 		end = src + old_ce->default_properties_count;
354 		dst = ce->default_properties_table;
355 		for (; src != end; src++, dst++) {
356 			ZVAL_COPY_VALUE(dst, src);
357 			zend_clone_zval(dst);
358 		}
359 	}
360 
361 	zend_hash_clone_methods(&ce->function_table, &old_ce->function_table, old_ce, ce);
362 
363 	/* static members */
364 	if (old_ce->default_static_members_table) {
365 		ce->default_static_members_table = emalloc(sizeof(zval) * old_ce->default_static_members_count);
366 		src = old_ce->default_static_members_table;
367 		end = src + old_ce->default_static_members_count;
368 		dst = ce->default_static_members_table;
369 		for (; src != end; src++, dst++) {
370 			ZVAL_COPY_VALUE(dst, src);
371 			zend_clone_zval(dst);
372 		}
373 	}
374 	ce->static_members_table = ce->default_static_members_table;
375 
376 	/* properties_info */
377 	zend_hash_clone_prop_info(&ce->properties_info, &old_ce->properties_info, old_ce);
378 
379 	/* constants table */
380 	zend_hash_clone_constants(&ce->constants_table, &old_ce->constants_table);
381 	ce->constants_table.u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
382 
383 	/* interfaces aren't really implemented, so we create a new table */
384 	if (ce->num_interfaces) {
385 		ce->interfaces = emalloc(sizeof(zend_class_entry *) * ce->num_interfaces);
386 		memset(ce->interfaces, 0, sizeof(zend_class_entry *) * ce->num_interfaces);
387 	} else {
388 		ce->interfaces = NULL;
389 	}
390 
391 	if (ce->parent) {
392 		ce->parent = ARENA_REALLOC(ce->parent);
393 	}
394 
395 	zend_update_inherited_handler(constructor);
396 	zend_update_inherited_handler(destructor);
397 	zend_update_inherited_handler(clone);
398 	zend_update_inherited_handler(__get);
399 	zend_update_inherited_handler(__set);
400 	zend_update_inherited_handler(__call);
401 /* 5.1 stuff */
402 	zend_update_inherited_handler(serialize_func);
403 	zend_update_inherited_handler(unserialize_func);
404 	zend_update_inherited_handler(__isset);
405 	zend_update_inherited_handler(__unset);
406 /* 5.2 stuff */
407 	zend_update_inherited_handler(__tostring);
408 
409 /* 5.3 stuff */
410 	zend_update_inherited_handler(__callstatic);
411 	zend_update_inherited_handler(__debugInfo);
412 
413 /* 5.4 traits */
414 	if (ce->trait_aliases) {
415 		zend_trait_alias **trait_aliases;
416 		int i = 0;
417 
418 		while (ce->trait_aliases[i]) {
419 			i++;
420 		}
421 		trait_aliases = emalloc(sizeof(zend_trait_alias*) * (i + 1));
422 		i = 0;
423 		while (ce->trait_aliases[i]) {
424 			trait_aliases[i] = emalloc(sizeof(zend_trait_alias));
425 			memcpy(trait_aliases[i], ce->trait_aliases[i], sizeof(zend_trait_alias));
426 			trait_aliases[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
427 			memcpy(trait_aliases[i]->trait_method, ce->trait_aliases[i]->trait_method, sizeof(zend_trait_method_reference));
428 			i++;
429 		}
430 		trait_aliases[i] = NULL;
431 		ce->trait_aliases = trait_aliases;
432 	}
433 
434 	if (ce->trait_precedences) {
435 		zend_trait_precedence **trait_precedences;
436 		int i = 0;
437 
438 		while (ce->trait_precedences[i]) {
439 			i++;
440 		}
441 		trait_precedences = emalloc(sizeof(zend_trait_precedence*) * (i + 1));
442 		i = 0;
443 		while (ce->trait_precedences[i]) {
444 			trait_precedences[i] = emalloc(sizeof(zend_trait_precedence));
445 			memcpy(trait_precedences[i], ce->trait_precedences[i], sizeof(zend_trait_precedence));
446 			trait_precedences[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
447 			memcpy(trait_precedences[i]->trait_method, ce->trait_precedences[i]->trait_method, sizeof(zend_trait_method_reference));
448 
449 			if (trait_precedences[i]->exclude_from_classes) {
450 				zend_string **exclude_from_classes;
451 				int j = 0;
452 
453 				while (trait_precedences[i]->exclude_from_classes[j].class_name) {
454 					j++;
455 				}
456 				exclude_from_classes = emalloc(sizeof(zend_string*) * (j + 1));
457 				j = 0;
458 				while (trait_precedences[i]->exclude_from_classes[j].class_name) {
459 					exclude_from_classes[j] =
460 						trait_precedences[i]->exclude_from_classes[j].class_name;
461 					j++;
462 				}
463 				exclude_from_classes[j] = NULL;
464 				trait_precedences[i]->exclude_from_classes = (void*)exclude_from_classes;
465 			}
466 			i++;
467 		}
468 		trait_precedences[i] = NULL;
469 		ce->trait_precedences = trait_precedences;
470 	}
471 }
472 
zend_accel_function_hash_copy(HashTable * target,HashTable * source)473 static void zend_accel_function_hash_copy(HashTable *target, HashTable *source)
474 {
475 	zend_function *function1, *function2;
476 	Bucket *p, *end;
477 	zval *t;
478 
479 	zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
480 	p = source->arData;
481 	end = p + source->nNumUsed;
482 	for (; p != end; p++) {
483 		if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
484 		ZEND_ASSERT(p->key);
485 		t = zend_hash_find(target, p->key);
486 		if (UNEXPECTED(t != NULL)) {
487 			if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
488 				/* Mangled key */
489 				t = zend_hash_update(target, p->key, &p->val);
490 			} else {
491 				goto failure;
492 			}
493 		} else {
494 			_zend_hash_append_ptr(target, p->key, Z_PTR(p->val));
495 		}
496 	}
497 	target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX;
498 	return;
499 
500 failure:
501 	function1 = Z_PTR(p->val);
502 	function2 = Z_PTR_P(t);
503 	CG(in_compilation) = 1;
504 	zend_set_compiled_filename(function1->op_array.filename);
505 	CG(zend_lineno) = function1->op_array.opcodes[0].lineno;
506 	if (function2->type == ZEND_USER_FUNCTION
507 		&& function2->op_array.last > 0) {
508 		zend_error(E_ERROR, "Cannot redeclare %s() (previously declared in %s:%d)",
509 				   ZSTR_VAL(function1->common.function_name),
510 				   ZSTR_VAL(function2->op_array.filename),
511 				   (int)function2->op_array.opcodes[0].lineno);
512 	} else {
513 		zend_error(E_ERROR, "Cannot redeclare %s()", ZSTR_VAL(function1->common.function_name));
514 	}
515 }
516 
zend_accel_function_hash_copy_from_shm(HashTable * target,HashTable * source)517 static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable *source)
518 {
519 	zend_function *function1, *function2;
520 	Bucket *p, *end;
521 	zval *t;
522 
523 	zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
524 	p = source->arData;
525 	end = p + source->nNumUsed;
526 	for (; p != end; p++) {
527 		if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
528 		ZEND_ASSERT(p->key);
529 		t = zend_hash_find(target, p->key);
530 		if (UNEXPECTED(t != NULL)) {
531 			if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
532 				/* Mangled key */
533 				zend_hash_update_ptr(target, p->key, ARENA_REALLOC(Z_PTR(p->val)));
534 			} else {
535 				goto failure;
536 			}
537 		} else {
538 			_zend_hash_append_ptr(target, p->key, ARENA_REALLOC(Z_PTR(p->val)));
539 		}
540 	}
541 	target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX;
542 	return;
543 
544 failure:
545 	function1 = Z_PTR(p->val);
546 	function2 = Z_PTR_P(t);
547 	CG(in_compilation) = 1;
548 	zend_set_compiled_filename(function1->op_array.filename);
549 	CG(zend_lineno) = function1->op_array.opcodes[0].lineno;
550 	if (function2->type == ZEND_USER_FUNCTION
551 		&& function2->op_array.last > 0) {
552 		zend_error(E_ERROR, "Cannot redeclare %s() (previously declared in %s:%d)",
553 				   ZSTR_VAL(function1->common.function_name),
554 				   ZSTR_VAL(function2->op_array.filename),
555 				   (int)function2->op_array.opcodes[0].lineno);
556 	} else {
557 		zend_error(E_ERROR, "Cannot redeclare %s()", ZSTR_VAL(function1->common.function_name));
558 	}
559 }
560 
zend_accel_class_hash_copy(HashTable * target,HashTable * source,unique_copy_ctor_func_t pCopyConstructor)561 static void zend_accel_class_hash_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor)
562 {
563 	Bucket *p, *end;
564 	zval *t;
565 
566 	zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
567 	p = source->arData;
568 	end = p + source->nNumUsed;
569 	for (; p != end; p++) {
570 		if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
571 		ZEND_ASSERT(p->key);
572 		t = zend_hash_find(target, p->key);
573 		if (UNEXPECTED(t != NULL)) {
574 			if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
575 				/* Mangled key - ignore and wait for runtime */
576 				continue;
577 			} else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
578 				zend_class_entry *ce1 = Z_PTR(p->val);
579 				if (!(ce1->ce_flags & ZEND_ACC_ANON_CLASS)) {
580 					CG(in_compilation) = 1;
581 					zend_set_compiled_filename(ce1->info.user.filename);
582 					CG(zend_lineno) = ce1->info.user.line_start;
583 					zend_error(E_ERROR,
584 							"Cannot declare %s %s, because the name is already in use",
585 							zend_get_object_type(ce1), ZSTR_VAL(ce1->name));
586 					return;
587 				}
588 				continue;
589 			}
590 		} else {
591 			t = _zend_hash_append_ptr(target, p->key, Z_PTR(p->val));
592 			if (pCopyConstructor) {
593 				pCopyConstructor(&Z_PTR_P(t));
594 			}
595 		}
596 	}
597 	target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX;
598 	return;
599 }
600 
601 #ifdef __SSE2__
602 #include <mmintrin.h>
603 #include <emmintrin.h>
604 
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 	__m128i *dqdest = (__m128i*)dest;
608 	const __m128i *dqsrc  = (const __m128i*)src;
609 	const __m128i *end  = (const __m128i*)((const char*)src + size);
610 
611 	do {
612 		_mm_prefetch(dqsrc + 4, _MM_HINT_NTA);
613 		_mm_prefetch(dqdest + 4, _MM_HINT_T0);
614 
615 		__m128i xmm0 = _mm_load_si128(dqsrc + 0);
616 		__m128i xmm1 = _mm_load_si128(dqsrc + 1);
617 		__m128i xmm2 = _mm_load_si128(dqsrc + 2);
618 		__m128i xmm3 = _mm_load_si128(dqsrc + 3);
619 		dqsrc  += 4;
620 		_mm_store_si128(dqdest + 0, xmm0);
621 		_mm_store_si128(dqdest + 1, xmm1);
622 		_mm_store_si128(dqdest + 2, xmm2);
623 		_mm_store_si128(dqdest + 3, xmm3);
624 		dqdest += 4;
625 	} while (dqsrc != end);
626 }
627 #endif
628 
zend_accel_load_script(zend_persistent_script * persistent_script,int from_shared_memory)629 zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory)
630 {
631 	zend_op_array *op_array;
632 
633 	op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
634 	*op_array = persistent_script->script.main_op_array;
635 
636 	if (EXPECTED(from_shared_memory)) {
637 		zend_hash_init(&ZCG(bind_hash), 10, NULL, NULL, 0);
638 
639 		ZCG(current_persistent_script) = persistent_script;
640 		ZCG(arena_mem) = NULL;
641 		if (EXPECTED(persistent_script->arena_size)) {
642 #ifdef __SSE2__
643 			/* Target address must be aligned to 64-byte boundary */
644 			ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size + 64);
645 			ZCG(arena_mem) = (void*)(((zend_uintptr_t)ZCG(arena_mem) + 63L) & ~63L);
646 			fast_memcpy(ZCG(arena_mem), persistent_script->arena_mem, persistent_script->arena_size);
647 #else
648 			ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size);
649 			memcpy(ZCG(arena_mem), persistent_script->arena_mem, persistent_script->arena_size);
650 #endif
651 		}
652 
653 		/* Copy all the necessary stuff from shared memory to regular memory, and protect the shared script */
654 		if (zend_hash_num_elements(&persistent_script->script.class_table) > 0) {
655 			zend_accel_class_hash_copy(CG(class_table), &persistent_script->script.class_table, (unique_copy_ctor_func_t) zend_class_copy_ctor);
656 		}
657 		/* we must first to copy all classes and then prepare functions, since functions may try to bind
658 		   classes - which depend on pre-bind class entries existent in the class table */
659 		if (zend_hash_num_elements(&persistent_script->script.function_table) > 0) {
660 			zend_accel_function_hash_copy_from_shm(CG(function_table), &persistent_script->script.function_table);
661 		}
662 
663 		/* Register __COMPILER_HALT_OFFSET__ constant */
664 		if (persistent_script->compiler_halt_offset != 0 &&
665 		    persistent_script->script.filename) {
666 			zend_string *name;
667 			char haltoff[] = "__COMPILER_HALT_OFFSET__";
668 
669 			name = zend_mangle_property_name(haltoff, sizeof(haltoff) - 1, ZSTR_VAL(persistent_script->script.filename), ZSTR_LEN(persistent_script->script.filename), 0);
670 			if (!zend_hash_exists(EG(zend_constants), name)) {
671 				zend_register_long_constant(ZSTR_VAL(name), ZSTR_LEN(name), persistent_script->compiler_halt_offset, CONST_CS, 0);
672 			}
673 			zend_string_release(name);
674 		}
675 
676 		zend_hash_destroy(&ZCG(bind_hash));
677 		ZCG(current_persistent_script) = NULL;
678 	} else /* if (!from_shared_memory) */ {
679 		if (zend_hash_num_elements(&persistent_script->script.function_table) > 0) {
680 			zend_accel_function_hash_copy(CG(function_table), &persistent_script->script.function_table);
681 		}
682 		if (zend_hash_num_elements(&persistent_script->script.class_table) > 0) {
683 			zend_accel_class_hash_copy(CG(class_table), &persistent_script->script.class_table, NULL);
684 		}
685 	}
686 
687 	if (op_array->early_binding != (uint32_t)-1) {
688 		zend_string *orig_compiled_filename = CG(compiled_filename);
689 		CG(compiled_filename) = persistent_script->script.filename;
690 		zend_do_delayed_early_binding(op_array);
691 		CG(compiled_filename) = orig_compiled_filename;
692 	}
693 
694 	if (UNEXPECTED(!from_shared_memory)) {
695 		free_persistent_script(persistent_script, 0); /* free only hashes */
696 	}
697 
698 	return op_array;
699 }
700 
701 /*
702  * zend_adler32() is based on zlib implementation
703  * Computes the Adler-32 checksum of a data stream
704  *
705  * Copyright (C) 1995-2005 Mark Adler
706  * For conditions of distribution and use, see copyright notice in zlib.h
707  *
708  * Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
709  *
710  *  This software is provided 'as-is', without any express or implied
711  *  warranty.  In no event will the authors be held liable for any damages
712  *  arising from the use of this software.
713  *
714  *  Permission is granted to anyone to use this software for any purpose,
715  *  including commercial applications, and to alter it and redistribute it
716  *  freely, subject to the following restrictions:
717  *
718  *  1. The origin of this software must not be misrepresented; you must not
719  *     claim that you wrote the original software. If you use this software
720  *     in a product, an acknowledgment in the product documentation would be
721  *     appreciated but is not required.
722  *  2. Altered source versions must be plainly marked as such, and must not be
723  *     misrepresented as being the original software.
724  *  3. This notice may not be removed or altered from any source distribution.
725  *
726  */
727 
728 #define ADLER32_BASE 65521 /* largest prime smaller than 65536 */
729 #define ADLER32_NMAX 5552
730 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
731 
732 #define ADLER32_DO1(buf)        {s1 += *(buf); s2 += s1;}
733 #define ADLER32_DO2(buf, i)     ADLER32_DO1(buf + i); ADLER32_DO1(buf + i + 1);
734 #define ADLER32_DO4(buf, i)     ADLER32_DO2(buf, i); ADLER32_DO2(buf, i + 2);
735 #define ADLER32_DO8(buf, i)     ADLER32_DO4(buf, i); ADLER32_DO4(buf, i + 4);
736 #define ADLER32_DO16(buf)       ADLER32_DO8(buf, 0); ADLER32_DO8(buf, 8);
737 
zend_adler32(unsigned int checksum,unsigned char * buf,uint32_t len)738 unsigned int zend_adler32(unsigned int checksum, unsigned char *buf, uint32_t len)
739 {
740 	unsigned int s1 = checksum & 0xffff;
741 	unsigned int s2 = (checksum >> 16) & 0xffff;
742 	unsigned char *end;
743 
744 	while (len >= ADLER32_NMAX) {
745 		len -= ADLER32_NMAX;
746 		end = buf + ADLER32_NMAX;
747 		do {
748 			ADLER32_DO16(buf);
749 			buf += 16;
750 		} while (buf != end);
751 		s1 %= ADLER32_BASE;
752 		s2 %= ADLER32_BASE;
753 	}
754 
755 	if (len) {
756 		if (len >= 16) {
757 			end = buf + (len & 0xfff0);
758 			len &= 0xf;
759 			do {
760 				ADLER32_DO16(buf);
761 				buf += 16;
762 			} while (buf != end);
763 		}
764 		if (len) {
765 			end = buf + len;
766 			do {
767 				ADLER32_DO1(buf);
768 				buf++;
769 			} while (buf != end);
770 		}
771 		s1 %= ADLER32_BASE;
772 		s2 %= ADLER32_BASE;
773 	}
774 
775 	return (s2 << 16) | s1;
776 }
777 
zend_accel_script_checksum(zend_persistent_script * persistent_script)778 unsigned int zend_accel_script_checksum(zend_persistent_script *persistent_script)
779 {
780 	unsigned char *mem = (unsigned char*)persistent_script->mem;
781 	size_t size = persistent_script->size;
782 	size_t persistent_script_check_block_size = ((char *)&(persistent_script->dynamic_members)) - (char *)persistent_script;
783 	unsigned int checksum = ADLER32_INIT;
784 
785 	if (mem < (unsigned char*)persistent_script) {
786 		checksum = zend_adler32(checksum, mem, (unsigned char*)persistent_script - mem);
787 		size -= (unsigned char*)persistent_script - mem;
788 		mem  += (unsigned char*)persistent_script - mem;
789 	}
790 
791 	zend_adler32(checksum, mem, persistent_script_check_block_size);
792 	mem  += sizeof(*persistent_script);
793 	size -= sizeof(*persistent_script);
794 
795 	if (size > 0) {
796 		checksum = zend_adler32(checksum, mem, size);
797 	}
798 	return checksum;
799 }
800