1 /*
2    +----------------------------------------------------------------------+
3    | Zend OPcache                                                         |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2015 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 #define ZEND_PROTECTED_REFCOUNT	(1<<30)
29 
30 static zend_uint zend_accel_refcount = ZEND_PROTECTED_REFCOUNT;
31 
32 #if SIZEOF_SIZE_T <= SIZEOF_LONG
33 /* If sizeof(void*) == sizeof(ulong) we can use zend_hash index functions */
34 # define accel_xlat_set(old, new)	zend_hash_index_update(&ZCG(bind_hash), (ulong)(zend_uintptr_t)(old), &(new), sizeof(void*), NULL)
35 # define accel_xlat_get(old, new)	zend_hash_index_find(&ZCG(bind_hash), (ulong)(zend_uintptr_t)(old), (void**)&(new))
36 #else
37 # define accel_xlat_set(old, new)	zend_hash_quick_add(&ZCG(bind_hash), (char*)&(old), sizeof(void*), (ulong)(zend_uintptr_t)(old), (void**)&(new), sizeof(void*), NULL)
38 # define accel_xlat_get(old, new)	zend_hash_quick_find(&ZCG(bind_hash), (char*)&(old), sizeof(void*), (ulong)(zend_uintptr_t)(old), (void**)&(new))
39 #endif
40 
41 typedef int (*id_function_t)(void *, void *);
42 typedef void (*unique_copy_ctor_func_t)(void *pElement);
43 
44 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
45 static const Bucket *uninitialized_bucket = NULL;
46 #endif
47 
48 static int zend_prepare_function_for_execution(zend_op_array *op_array);
49 static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind);
50 
zend_accel_destroy_zend_function(zend_function * function)51 static void zend_accel_destroy_zend_function(zend_function *function)
52 {
53 	TSRMLS_FETCH();
54 
55 	if (function->type == ZEND_USER_FUNCTION) {
56 		if (function->op_array.static_variables) {
57 
58 			efree(function->op_array.static_variables);
59 			function->op_array.static_variables = NULL;
60 		}
61 	}
62 
63 	destroy_zend_function(function TSRMLS_CC);
64 }
65 
zend_accel_destroy_zend_class(zend_class_entry ** pce)66 static void zend_accel_destroy_zend_class(zend_class_entry **pce)
67 {
68 	zend_class_entry *ce = *pce;
69 
70 	ce->function_table.pDestructor = (dtor_func_t) zend_accel_destroy_zend_function;
71 	destroy_zend_class(pce);
72 }
73 
create_persistent_script(void)74 zend_persistent_script* create_persistent_script(void)
75 {
76 	zend_persistent_script *persistent_script = (zend_persistent_script *) emalloc(sizeof(zend_persistent_script));
77 	memset(persistent_script, 0, sizeof(zend_persistent_script));
78 
79 	zend_hash_init(&persistent_script->function_table, 100, NULL, (dtor_func_t) zend_accel_destroy_zend_function, 0);
80 	/* class_table is usually destroyed by free_persistent_script() that
81 	 * overrides destructor. ZEND_CLASS_DTOR may be used by standard
82 	 * PHP compiler
83 	 */
84 	zend_hash_init(&persistent_script->class_table, 10, NULL, ZEND_CLASS_DTOR, 0);
85 
86 	return persistent_script;
87 }
88 
compact_hash_table(HashTable * ht)89 static int compact_hash_table(HashTable *ht)
90 {
91 	uint i = 3;
92 	uint nSize;
93 	Bucket **t;
94 
95 	if (!ht->nNumOfElements) {
96 		/* Empty tables don't allocate space for Buckets */
97 		return 1;
98 	}
99 
100 	if (ht->nNumOfElements >= 0x80000000) {
101 		/* prevent overflow */
102 		nSize = 0x80000000;
103 	} else {
104 		while ((1U << i) < ht->nNumOfElements) {
105 			i++;
106 		}
107 		nSize = 1 << i;
108 	}
109 
110 	if (nSize >= ht->nTableSize) {
111 		/* Keep the size */
112 		return 1;
113 	}
114 
115 	t = (Bucket **)pemalloc(nSize * sizeof(Bucket *), ht->persistent);
116 	if (!t) {
117 		return 0;
118 	}
119 
120 	pefree(ht->arBuckets, ht->persistent);
121 
122 	ht->arBuckets = t;
123 	ht->nTableSize = nSize;
124 	ht->nTableMask = ht->nTableSize - 1;
125 	zend_hash_rehash(ht);
126 
127 	return 1;
128 }
129 
compact_persistent_script(zend_persistent_script * persistent_script)130 int compact_persistent_script(zend_persistent_script *persistent_script)
131 {
132 	return compact_hash_table(&persistent_script->function_table) &&
133 	       compact_hash_table(&persistent_script->class_table);
134 }
135 
free_persistent_script(zend_persistent_script * persistent_script,int destroy_elements)136 void free_persistent_script(zend_persistent_script *persistent_script, int destroy_elements)
137 {
138 	if (destroy_elements) {
139 		persistent_script->function_table.pDestructor = (dtor_func_t)zend_accel_destroy_zend_function;
140 		persistent_script->class_table.pDestructor = (dtor_func_t)zend_accel_destroy_zend_class;
141 	} else {
142 		persistent_script->function_table.pDestructor = NULL;
143 		persistent_script->class_table.pDestructor = NULL;
144 	}
145 
146 	zend_hash_destroy(&persistent_script->function_table);
147 	zend_hash_destroy(&persistent_script->class_table);
148 
149 	if (persistent_script->full_path) {
150 		efree(persistent_script->full_path);
151 	}
152 
153 	efree(persistent_script);
154 }
155 
is_not_internal_function(zend_function * function)156 static int is_not_internal_function(zend_function *function)
157 {
158 	return(function->type != ZEND_INTERNAL_FUNCTION);
159 }
160 
zend_accel_free_user_functions(HashTable * ht TSRMLS_DC)161 void zend_accel_free_user_functions(HashTable *ht TSRMLS_DC)
162 {
163 	dtor_func_t orig_dtor = ht->pDestructor;
164 
165 	ht->pDestructor = NULL;
166 	zend_hash_apply(ht, (apply_func_t) is_not_internal_function TSRMLS_CC);
167 	ht->pDestructor = orig_dtor;
168 }
169 
move_user_function(zend_function * function TSRMLS_DC,int num_args,va_list args,zend_hash_key * hash_key)170 static int move_user_function(zend_function *function
171 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
172 	TSRMLS_DC
173 #endif
174 	, int num_args, va_list args, zend_hash_key *hash_key)
175 {
176 	HashTable *function_table = va_arg(args, HashTable *);
177 	(void)num_args; /* keep the compiler happy */
178 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
179 	TSRMLS_FETCH();
180 #endif
181 
182 	if (function->type == ZEND_USER_FUNCTION) {
183 		zend_hash_quick_update(function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, function, sizeof(zend_function), NULL);
184 		return 1;
185 	} else {
186 		return 0;
187 	}
188 }
189 
zend_accel_move_user_functions(HashTable * src,HashTable * dst TSRMLS_DC)190 void zend_accel_move_user_functions(HashTable *src, HashTable *dst TSRMLS_DC)
191 {
192 	dtor_func_t orig_dtor = src->pDestructor;
193 
194 	src->pDestructor = NULL;
195 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
196 	zend_hash_apply_with_arguments(src, (apply_func_args_t)move_user_function, 1, dst);
197 #else
198 	zend_hash_apply_with_arguments(src TSRMLS_CC, (apply_func_args_t)move_user_function, 1, dst);
199 #endif
200 	src->pDestructor = orig_dtor;
201 }
202 
copy_internal_function(zend_function * function,HashTable * function_table TSRMLS_DC)203 static int copy_internal_function(zend_function *function, HashTable *function_table TSRMLS_DC)
204 {
205 	if (function->type == ZEND_INTERNAL_FUNCTION) {
206 		zend_hash_update(function_table, function->common.function_name, strlen(function->common.function_name) + 1, function, sizeof(zend_function), NULL);
207 	}
208 	return 0;
209 }
210 
zend_accel_copy_internal_functions(TSRMLS_D)211 void zend_accel_copy_internal_functions(TSRMLS_D)
212 {
213 	zend_hash_apply_with_argument(CG(function_table), (apply_func_arg_t)copy_internal_function, &ZCG(function_table) TSRMLS_CC);
214 	ZCG(internal_functions_count) = zend_hash_num_elements(&ZCG(function_table));
215 }
216 
zend_destroy_property_info(zend_property_info * property_info)217 static void zend_destroy_property_info(zend_property_info *property_info)
218 {
219 	interned_efree((char*)property_info->name);
220 	if (property_info->doc_comment) {
221 		efree((char*)property_info->doc_comment);
222 	}
223 }
224 
zend_clone_zval(zval * src,int bind TSRMLS_DC)225 static inline zval* zend_clone_zval(zval *src, int bind TSRMLS_DC)
226 {
227 	zval *ret, **ret_ptr = NULL;
228 
229 	if (!bind) {
230 		ALLOC_ZVAL(ret);
231 		*ret = *src;
232 		INIT_PZVAL(ret);
233 	} else if (Z_REFCOUNT_P(src) == 1) {
234 		ALLOC_ZVAL(ret);
235 		*ret = *src;
236 	} else if (accel_xlat_get(src, ret_ptr) != SUCCESS) {
237 		ALLOC_ZVAL(ret);
238 		*ret = *src;
239 		accel_xlat_set(src, ret);
240 	} else {
241 		return *ret_ptr;
242 	}
243 
244 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
245 	if ((Z_TYPE_P(ret) & IS_CONSTANT_TYPE_MASK) >= IS_ARRAY) {
246 		switch ((Z_TYPE_P(ret) & IS_CONSTANT_TYPE_MASK)) {
247 #else
248 	if ((Z_TYPE_P(ret) & ~IS_CONSTANT_INDEX) >= IS_ARRAY) {
249 		switch ((Z_TYPE_P(ret) & ~IS_CONSTANT_INDEX)) {
250 #endif
251 			case IS_STRING:
252 		    case IS_CONSTANT:
253 				Z_STRVAL_P(ret) = (char *) interned_estrndup(Z_STRVAL_P(ret), Z_STRLEN_P(ret));
254 				break;
255 			case IS_ARRAY:
256 		    case IS_CONSTANT_ARRAY:
257 				if (ret->value.ht && ret->value.ht != &EG(symbol_table)) {
258 					ALLOC_HASHTABLE(ret->value.ht);
259 					zend_hash_clone_zval(ret->value.ht, src->value.ht, 0);
260 				}
261 				break;
262 		}
263 	}
264 	return ret;
265 }
266 
267 static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind)
268 {
269 	Bucket *p, *q, **prev;
270 	ulong nIndex;
271 	zval *ppz;
272 	TSRMLS_FETCH();
273 
274 	ht->nTableSize = source->nTableSize;
275 	ht->nTableMask = source->nTableMask;
276 	ht->nNumOfElements = source->nNumOfElements;
277 	ht->nNextFreeElement = source->nNextFreeElement;
278 	ht->pDestructor = ZVAL_PTR_DTOR;
279 #if ZEND_DEBUG
280 	ht->inconsistent = 0;
281 #endif
282 	ht->persistent = 0;
283 	ht->arBuckets = NULL;
284 	ht->pListHead = NULL;
285 	ht->pListTail = NULL;
286 	ht->pInternalPointer = NULL;
287 	ht->nApplyCount = 0;
288 	ht->bApplyProtection = 1;
289 
290 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
291 	if (!ht->nTableMask) {
292 		ht->arBuckets = (Bucket**)&uninitialized_bucket;
293 		return;
294 	}
295 #endif
296 
297 	ht->arBuckets = (Bucket **) ecalloc(ht->nTableSize, sizeof(Bucket *));
298 
299 	prev = &ht->pListHead;
300 	p = source->pListHead;
301 	while (p) {
302 		nIndex = p->h & ht->nTableMask;
303 
304 		/* Create bucket and initialize key */
305 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
306 		if (!p->nKeyLength) {
307 			q = (Bucket *) emalloc(sizeof(Bucket));
308 			q->arKey = NULL;
309 		} else if (IS_INTERNED(p->arKey)) {
310 			q = (Bucket *) emalloc(sizeof(Bucket));
311 			q->arKey = p->arKey;
312 		} else {
313 			q = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength);
314 			q->arKey = ((char*)q) + sizeof(Bucket);
315 			memcpy((char*)q->arKey, p->arKey, p->nKeyLength);
316 		}
317 #else
318 		q = (Bucket *) emalloc(sizeof(Bucket) - 1 + p->nKeyLength);
319 		if (p->nKeyLength) {
320 			memcpy(q->arKey, p->arKey, p->nKeyLength);
321 		}
322 #endif
323 		q->h = p->h;
324 		q->nKeyLength = p->nKeyLength;
325 
326 		/* Insert into hash collision list */
327 		q->pNext = ht->arBuckets[nIndex];
328 		q->pLast = NULL;
329 		if (q->pNext) {
330 			q->pNext->pLast = q;
331 		}
332 		ht->arBuckets[nIndex] = q;
333 
334 		/* Insert into global list */
335 		q->pListLast = ht->pListTail;
336 		ht->pListTail = q;
337 		q->pListNext = NULL;
338 		*prev = q;
339 		prev = &q->pListNext;
340 
341 		/* Copy data */
342 		q->pData = &q->pDataPtr;
343 		if (!bind) {
344 			ALLOC_ZVAL(ppz);
345 			*ppz = *((zval*)p->pDataPtr);
346 			INIT_PZVAL(ppz);
347 		} else if (Z_REFCOUNT_P((zval*)p->pDataPtr) == 1) {
348 			ALLOC_ZVAL(ppz);
349 			*ppz = *((zval*)p->pDataPtr);
350 		} else if (accel_xlat_get(p->pDataPtr, ppz) != SUCCESS) {
351 			ALLOC_ZVAL(ppz);
352 			*ppz = *((zval*)p->pDataPtr);
353 			accel_xlat_set(p->pDataPtr, ppz);
354 		} else {
355 			q->pDataPtr = *(void**)ppz;
356 			p = p->pListNext;
357 			continue;
358 		}
359 		q->pDataPtr = (void*)ppz;
360 
361 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
362 		if ((Z_TYPE_P((zval*)p->pDataPtr) & IS_CONSTANT_TYPE_MASK) >= IS_ARRAY) {
363 			switch ((Z_TYPE_P((zval*)p->pDataPtr) & IS_CONSTANT_TYPE_MASK)) {
364 #else
365 		if ((Z_TYPE_P((zval*)p->pDataPtr) & ~IS_CONSTANT_INDEX) >= IS_ARRAY) {
366 			switch ((Z_TYPE_P((zval*)p->pDataPtr) & ~IS_CONSTANT_INDEX)) {
367 #endif
368 				case IS_STRING:
369 			    case IS_CONSTANT:
370 					Z_STRVAL_P(ppz) = (char *) interned_estrndup(Z_STRVAL_P((zval*)p->pDataPtr), Z_STRLEN_P((zval*)p->pDataPtr));
371 					break;
372 				case IS_ARRAY:
373 			    case IS_CONSTANT_ARRAY:
374 					if (((zval*)p->pDataPtr)->value.ht && ((zval*)p->pDataPtr)->value.ht != &EG(symbol_table)) {
375 						ALLOC_HASHTABLE(ppz->value.ht);
376 						zend_hash_clone_zval(ppz->value.ht, ((zval*)p->pDataPtr)->value.ht, 0);
377 					}
378 					break;
379 			}
380 		}
381 
382 		p = p->pListNext;
383 	}
384 	ht->pInternalPointer = ht->pListHead;
385 }
386 
387 static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce TSRMLS_DC)
388 {
389 	Bucket *p, *q, **prev;
390 	ulong nIndex;
391 	zend_class_entry **new_ce;
392 	zend_function** new_prototype;
393 	zend_op_array *new_entry;
394 
395 	ht->nTableSize = source->nTableSize;
396 	ht->nTableMask = source->nTableMask;
397 	ht->nNumOfElements = source->nNumOfElements;
398 	ht->nNextFreeElement = source->nNextFreeElement;
399 	ht->pDestructor = ZEND_FUNCTION_DTOR;
400 #if ZEND_DEBUG
401 	ht->inconsistent = 0;
402 #endif
403 	ht->persistent = 0;
404 	ht->pListHead = NULL;
405 	ht->pListTail = NULL;
406 	ht->pInternalPointer = NULL;
407 	ht->nApplyCount = 0;
408 	ht->bApplyProtection = 1;
409 
410 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
411 	if (!ht->nTableMask) {
412 		ht->arBuckets = (Bucket**)&uninitialized_bucket;
413 		return;
414 	}
415 #endif
416 
417 	ht->arBuckets = (Bucket **) ecalloc(ht->nTableSize, sizeof(Bucket *));
418 
419 	prev = &ht->pListHead;
420 	p = source->pListHead;
421 	while (p) {
422 		nIndex = p->h & ht->nTableMask;
423 
424 		/* Create bucket and initialize key */
425 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
426 		if (!p->nKeyLength) {
427 			q = (Bucket *) emalloc(sizeof(Bucket));
428 			q->arKey = NULL;
429 		} else if (IS_INTERNED(p->arKey)) {
430 			q = (Bucket *) emalloc(sizeof(Bucket));
431 			q->arKey = p->arKey;
432 		} else {
433 			q = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength);
434 			q->arKey = ((char*)q) + sizeof(Bucket);
435 			memcpy((char*)q->arKey, p->arKey, p->nKeyLength);
436 		}
437 #else
438 		q = (Bucket *) emalloc(sizeof(Bucket) - 1 + p->nKeyLength);
439 		if (p->nKeyLength) {
440 			memcpy(q->arKey, p->arKey, p->nKeyLength);
441 		}
442 #endif
443 		q->h = p->h;
444 		q->nKeyLength = p->nKeyLength;
445 
446 		/* Insert into hash collision list */
447 		q->pNext = ht->arBuckets[nIndex];
448 		q->pLast = NULL;
449 		if (q->pNext) {
450 			q->pNext->pLast = q;
451 		}
452 		ht->arBuckets[nIndex] = q;
453 
454 		/* Insert into global list */
455 		q->pListLast = ht->pListTail;
456 		ht->pListTail = q;
457 		q->pListNext = NULL;
458 		*prev = q;
459 		prev = &q->pListNext;
460 
461 		/* Copy data */
462 		q->pData = (void *) emalloc(sizeof(zend_function));
463 		new_entry = (zend_op_array*)q->pData;
464 		*new_entry = *(zend_op_array*)p->pData;
465 		q->pDataPtr = NULL;
466 
467 		/* Copy constructor */
468 		/* we use refcount to show that op_array is referenced from several places */
469 		if (new_entry->refcount != NULL) {
470 			accel_xlat_set(p->pData, new_entry);
471 		}
472 
473 		zend_prepare_function_for_execution(new_entry);
474 
475 		if (old_ce == new_entry->scope) {
476 			new_entry->scope = ce;
477 		} else {
478 			if (accel_xlat_get(new_entry->scope, new_ce) == SUCCESS) {
479 				new_entry->scope = *new_ce;
480 			} else {
481 				zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s, function %s", ce->name, new_entry->function_name);
482 			}
483 		}
484 
485 		/* update prototype */
486 		if (new_entry->prototype) {
487 			if (accel_xlat_get(new_entry->prototype, new_prototype) == SUCCESS) {
488 				new_entry->prototype = *new_prototype;
489 			} else {
490 				zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s, function %s", ce->name, new_entry->function_name);
491 			}
492 		}
493 
494 		p = p->pListNext;
495 	}
496 	ht->pInternalPointer = ht->pListHead;
497 }
498 
499 static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce TSRMLS_DC)
500 {
501 	Bucket *p, *q, **prev;
502 	ulong nIndex;
503 	zend_class_entry **new_ce;
504 	zend_property_info *prop_info;
505 
506 	ht->nTableSize = source->nTableSize;
507 	ht->nTableMask = source->nTableMask;
508 	ht->nNumOfElements = source->nNumOfElements;
509 	ht->nNextFreeElement = source->nNextFreeElement;
510 	ht->pDestructor = (dtor_func_t) zend_destroy_property_info;
511 #if ZEND_DEBUG
512 	ht->inconsistent = 0;
513 #endif
514 	ht->persistent = 0;
515 	ht->pListHead = NULL;
516 	ht->pListTail = NULL;
517 	ht->pInternalPointer = NULL;
518 	ht->nApplyCount = 0;
519 	ht->bApplyProtection = 1;
520 
521 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
522 	if (!ht->nTableMask) {
523 		ht->arBuckets = (Bucket**)&uninitialized_bucket;
524 		return;
525 	}
526 #endif
527 
528 	ht->arBuckets = (Bucket **) ecalloc(ht->nTableSize, sizeof(Bucket *));
529 
530 	prev = &ht->pListHead;
531 	p = source->pListHead;
532 	while (p) {
533 		nIndex = p->h & ht->nTableMask;
534 
535 		/* Create bucket and initialize key */
536 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
537 		if (!p->nKeyLength) {
538 			q = (Bucket *) emalloc(sizeof(Bucket));
539 			q->arKey = NULL;
540 		} else if (IS_INTERNED(p->arKey)) {
541 			q = (Bucket *) emalloc(sizeof(Bucket));
542 			q->arKey = p->arKey;
543 		} else {
544 			q = (Bucket *) emalloc(sizeof(Bucket) + p->nKeyLength);
545 			q->arKey = ((char*)q) + sizeof(Bucket);
546 			memcpy((char*)q->arKey, p->arKey, p->nKeyLength);
547 		}
548 #else
549 		q = (Bucket *) emalloc(sizeof(Bucket) - 1 + p->nKeyLength);
550 		if (p->nKeyLength) {
551 			memcpy(q->arKey, p->arKey, p->nKeyLength);
552 		}
553 #endif
554 		q->h = p->h;
555 		q->nKeyLength = p->nKeyLength;
556 
557 		/* Insert into hash collision list */
558 		q->pNext = ht->arBuckets[nIndex];
559 		q->pLast = NULL;
560 		if (q->pNext) {
561 			q->pNext->pLast = q;
562 		}
563 		ht->arBuckets[nIndex] = q;
564 
565 		/* Insert into global list */
566 		q->pListLast = ht->pListTail;
567 		ht->pListTail = q;
568 		q->pListNext = NULL;
569 		*prev = q;
570 		prev = &q->pListNext;
571 
572 		/* Copy data */
573 		q->pData = (void *) emalloc(sizeof(zend_property_info));
574 		prop_info = q->pData;
575 		*prop_info = *(zend_property_info*)p->pData;
576 		q->pDataPtr = NULL;
577 
578 		/* Copy constructor */
579 		prop_info->name = interned_estrndup(prop_info->name, prop_info->name_length);
580 		if (prop_info->doc_comment) {
581 			if (ZCG(accel_directives).load_comments) {
582 				prop_info->doc_comment = estrndup(prop_info->doc_comment, prop_info->doc_comment_len);
583 			} else {
584 				prop_info->doc_comment = NULL;
585 			}
586 		}
587 		if (prop_info->ce == old_ce) {
588 			prop_info->ce = ce;
589 		} else if (accel_xlat_get(prop_info->ce, new_ce) == SUCCESS) {
590 			prop_info->ce = *new_ce;
591 		} else {
592 			zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME" class loading error, class %s, property %s", ce->name, prop_info->name);
593 		}
594 
595 		p = p->pListNext;
596 	}
597 	ht->pInternalPointer = ht->pListHead;
598 }
599 
600 /* protects reference count, creates copy of statics */
601 static int zend_prepare_function_for_execution(zend_op_array *op_array)
602 {
603 	HashTable *shared_statics = op_array->static_variables;
604 
605 	/* protect reference count */
606 	op_array->refcount = &zend_accel_refcount;
607 	(*op_array->refcount) = ZEND_PROTECTED_REFCOUNT;
608 
609 	/* copy statics */
610 	if (shared_statics) {
611 		ALLOC_HASHTABLE(op_array->static_variables);
612 		zend_hash_clone_zval(op_array->static_variables, shared_statics, 0);
613 	}
614 
615 	return 0;
616 }
617 
618 #define zend_update_inherited_handler(handler) \
619 { \
620 	if (ce->handler != NULL) { \
621 		if (accel_xlat_get(ce->handler, new_func) == SUCCESS) { \
622 			ce->handler = *new_func; \
623 		} else { \
624 			zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s", ce->name); \
625 		} \
626 	} \
627 }
628 
629 /* Protects class' refcount, copies default properties, functions and class name */
630 static void zend_class_copy_ctor(zend_class_entry **pce)
631 {
632 	zend_class_entry *ce = *pce;
633 	zend_class_entry *old_ce = ce;
634 	zend_class_entry **new_ce;
635 	zend_function **new_func;
636 	TSRMLS_FETCH();
637 
638 	*pce = ce = emalloc(sizeof(zend_class_entry));
639 	*ce = *old_ce;
640 	ce->refcount = 1;
641 
642 	if (old_ce->refcount != 1) {
643 		/* this class is not used as a parent for any other classes */
644 		accel_xlat_set(old_ce, ce);
645 	}
646 
647 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
648 	if (old_ce->default_properties_table) {
649 		int i;
650 
651 		ce->default_properties_table = emalloc(sizeof(zval*) * old_ce->default_properties_count);
652 		for (i = 0; i < old_ce->default_properties_count; i++) {
653 			if (old_ce->default_properties_table[i]) {
654 				ce->default_properties_table[i] = zend_clone_zval(old_ce->default_properties_table[i], 0 TSRMLS_CC);
655 			} else {
656 				ce->default_properties_table[i] = NULL;
657 			}
658 		}
659 	}
660 #else
661 	zend_hash_clone_zval(&ce->default_properties, &old_ce->default_properties, 0);
662 #endif
663 
664 	zend_hash_clone_methods(&ce->function_table, &old_ce->function_table, old_ce, ce TSRMLS_CC);
665 
666 	/* static members */
667 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
668 	if (old_ce->default_static_members_table) {
669 		int i;
670 
671 		ce->default_static_members_table = emalloc(sizeof(zval*) * old_ce->default_static_members_count);
672 		for (i = 0; i < old_ce->default_static_members_count; i++) {
673 			if (old_ce->default_static_members_table[i]) {
674 				ce->default_static_members_table[i] = zend_clone_zval(old_ce->default_static_members_table[i], 1 TSRMLS_CC);
675 			} else {
676 				ce->default_static_members_table[i] = NULL;
677 			}
678 		}
679 	}
680 	ce->static_members_table = ce->default_static_members_table;
681 #else
682 	zend_hash_clone_zval(&ce->default_static_members, &old_ce->default_static_members, 1);
683 	ce->static_members = &ce->default_static_members;
684 #endif
685 
686 	/* properties_info */
687 	zend_hash_clone_prop_info(&ce->properties_info, &old_ce->properties_info, old_ce, ce TSRMLS_CC);
688 
689 	/* constants table */
690 	zend_hash_clone_zval(&ce->constants_table, &old_ce->constants_table, 0);
691 
692 	ce->name = interned_estrndup(ce->name, ce->name_length);
693 
694 	/* interfaces aren't really implemented, so we create a new table */
695 	if (ce->num_interfaces) {
696 		ce->interfaces = emalloc(sizeof(zend_class_entry *) * ce->num_interfaces);
697 		memset(ce->interfaces, 0, sizeof(zend_class_entry *) * ce->num_interfaces);
698 	} else {
699 		ce->interfaces = NULL;
700 	}
701 	if (ZEND_CE_DOC_COMMENT(ce)) {
702 		if (ZCG(accel_directives).load_comments) {
703 			ZEND_CE_DOC_COMMENT(ce) = estrndup(ZEND_CE_DOC_COMMENT(ce), ZEND_CE_DOC_COMMENT_LEN(ce));
704 		} else {
705 			ZEND_CE_DOC_COMMENT(ce) =  NULL;
706 		}
707 	}
708 
709 	if (ce->parent) {
710 		if (accel_xlat_get(ce->parent, new_ce) == SUCCESS) {
711 			ce->parent = *new_ce;
712 		} else {
713 			zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME" class loading error, class %s", ce->name);
714 		}
715 	}
716 
717 	zend_update_inherited_handler(constructor);
718 	zend_update_inherited_handler(destructor);
719 	zend_update_inherited_handler(clone);
720 	zend_update_inherited_handler(__get);
721 	zend_update_inherited_handler(__set);
722 	zend_update_inherited_handler(__call);
723 /* 5.1 stuff */
724 	zend_update_inherited_handler(serialize_func);
725 	zend_update_inherited_handler(unserialize_func);
726 	zend_update_inherited_handler(__isset);
727 	zend_update_inherited_handler(__unset);
728 /* 5.2 stuff */
729 	zend_update_inherited_handler(__tostring);
730 
731 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
732 /* 5.3 stuff */
733 	zend_update_inherited_handler(__callstatic);
734 #endif
735 
736 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
737 /* 5.4 traits */
738 	if (ce->trait_aliases) {
739 		zend_trait_alias **trait_aliases;
740 		int i = 0;
741 
742 		while (ce->trait_aliases[i]) {
743 			i++;
744 		}
745 		trait_aliases = emalloc(sizeof(zend_trait_alias*) * (i + 1));
746 		i = 0;
747 		while (ce->trait_aliases[i]) {
748 			trait_aliases[i] = emalloc(sizeof(zend_trait_alias));
749 			memcpy(trait_aliases[i], ce->trait_aliases[i], sizeof(zend_trait_alias));
750 			trait_aliases[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
751 			memcpy(trait_aliases[i]->trait_method, ce->trait_aliases[i]->trait_method, sizeof(zend_trait_method_reference));
752 			if (trait_aliases[i]->trait_method) {
753 				if (trait_aliases[i]->trait_method->method_name) {
754 					trait_aliases[i]->trait_method->method_name =
755 						estrndup(trait_aliases[i]->trait_method->method_name,
756 							trait_aliases[i]->trait_method->mname_len);
757 				}
758 				if (trait_aliases[i]->trait_method->class_name) {
759 					trait_aliases[i]->trait_method->class_name =
760 						estrndup(trait_aliases[i]->trait_method->class_name,
761 							trait_aliases[i]->trait_method->cname_len);
762 				}
763 			}
764 
765 			if (trait_aliases[i]->alias) {
766 				trait_aliases[i]->alias =
767 					estrndup(trait_aliases[i]->alias,
768 						trait_aliases[i]->alias_len);
769 			}
770 			i++;
771 		}
772 		trait_aliases[i] = NULL;
773 		ce->trait_aliases = trait_aliases;
774 	}
775 
776 	if (ce->trait_precedences) {
777 		zend_trait_precedence **trait_precedences;
778 		int i = 0;
779 
780 		while (ce->trait_precedences[i]) {
781 			i++;
782 		}
783 		trait_precedences = emalloc(sizeof(zend_trait_precedence*) * (i + 1));
784 		i = 0;
785 		while (ce->trait_precedences[i]) {
786 			trait_precedences[i] = emalloc(sizeof(zend_trait_precedence));
787 			memcpy(trait_precedences[i], ce->trait_precedences[i], sizeof(zend_trait_precedence));
788 			trait_precedences[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
789 			memcpy(trait_precedences[i]->trait_method, ce->trait_precedences[i]->trait_method, sizeof(zend_trait_method_reference));
790 
791 			trait_precedences[i]->trait_method->method_name =
792 				estrndup(trait_precedences[i]->trait_method->method_name,
793 					trait_precedences[i]->trait_method->mname_len);
794 			trait_precedences[i]->trait_method->class_name =
795 				estrndup(trait_precedences[i]->trait_method->class_name,
796 					trait_precedences[i]->trait_method->cname_len);
797 
798 			if (trait_precedences[i]->exclude_from_classes) {
799 				zend_class_entry **exclude_from_classes;
800 				int j = 0;
801 
802 				while (trait_precedences[i]->exclude_from_classes[j]) {
803 					j++;
804 				}
805 				exclude_from_classes = emalloc(sizeof(zend_class_entry*) * (j + 1));
806 				j = 0;
807 				while (trait_precedences[i]->exclude_from_classes[j]) {
808 					exclude_from_classes[j] = (zend_class_entry*)estrndup(
809 						(char*)trait_precedences[i]->exclude_from_classes[j],
810 						strlen((char*)trait_precedences[i]->exclude_from_classes[j]));
811 					j++;
812 				}
813 				exclude_from_classes[j] = NULL;
814 				trait_precedences[i]->exclude_from_classes = exclude_from_classes;
815 			}
816 			i++;
817 		}
818 		trait_precedences[i] = NULL;
819 		ce->trait_precedences = trait_precedences;
820 	}
821 #endif
822 }
823 
824 static int zend_hash_unique_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor, uint size, int ignore_dups, void **fail_data, void **conflict_data)
825 {
826 	Bucket *p;
827 	void *t;
828 
829 	p = source->pListHead;
830 	while (p) {
831 		if (p->nKeyLength > 0) {
832 			if (zend_hash_quick_add(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &t) == SUCCESS) {
833 				if (pCopyConstructor) {
834 					pCopyConstructor(t);
835 				}
836 			} else {
837 				if (p->nKeyLength > 0 && p->arKey[0] == 0) {
838 					/* Mangled key */
839 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
840 					if (zend_hash_quick_update(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &t) == SUCCESS) {
841 						if (pCopyConstructor) {
842 							pCopyConstructor(t);
843 						}
844 					}
845 #endif
846 				} else if (!ignore_dups && zend_hash_quick_find(target, p->arKey, p->nKeyLength, p->h, &t) == SUCCESS) {
847 					*fail_data = p->pData;
848 					*conflict_data = t;
849 					return FAILURE;
850 				}
851 			}
852 		} else {
853 			if (!zend_hash_index_exists(target, p->h) && zend_hash_index_update(target, p->h, p->pData, size, &t) == SUCCESS) {
854 				if (pCopyConstructor) {
855 					pCopyConstructor(t);
856 				}
857 			} else if (!ignore_dups && zend_hash_index_find(target,p->h, &t) == SUCCESS) {
858 				*fail_data = p->pData;
859 				*conflict_data = t;
860 				return FAILURE;
861 			}
862 		}
863 		p = p->pListNext;
864 	}
865 	target->pInternalPointer = target->pListHead;
866 
867 	return SUCCESS;
868 }
869 
870 static void zend_accel_function_hash_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor)
871 {
872 	zend_function *function1, *function2;
873 	TSRMLS_FETCH();
874 
875 	if (zend_hash_unique_copy(target, source, pCopyConstructor, sizeof(zend_function), 0, (void**)&function1, (void**)&function2) != SUCCESS) {
876 		CG(in_compilation) = 1;
877 		zend_set_compiled_filename(function1->op_array.filename TSRMLS_CC);
878 		CG(zend_lineno) = function1->op_array.opcodes[0].lineno;
879 		if (function2->type == ZEND_USER_FUNCTION
880 			&& function2->op_array.last > 0) {
881 			zend_error(E_ERROR, "Cannot redeclare %s() (previously declared in %s:%d)",
882 					   function1->common.function_name,
883 					   function2->op_array.filename,
884 					   (int)function2->op_array.opcodes[0].lineno);
885 		} else {
886 			zend_error(E_ERROR, "Cannot redeclare %s()", function1->common.function_name);
887 		}
888 	}
889 }
890 
891 static void zend_accel_class_hash_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor TSRMLS_DC)
892 {
893 	zend_class_entry **pce1, **pce2;
894 
895 	if (zend_hash_unique_copy(target, source, pCopyConstructor, sizeof(zend_class_entry*), ZCG(accel_directives).ignore_dups, (void**)&pce1, (void**)&pce2) != SUCCESS) {
896 		CG(in_compilation) = 1;
897 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
898 		zend_set_compiled_filename((*pce1)->info.user.filename TSRMLS_CC);
899 		CG(zend_lineno) = (*pce1)->info.user.line_start;
900 #else
901 		zend_set_compiled_filename((*pce1)->filename TSRMLS_CC);
902 		CG(zend_lineno) = (*pce1)->line_start;
903 #endif
904 		zend_error(E_ERROR, "Cannot redeclare class %s", (*pce1)->name);
905 	}
906 }
907 
908 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
909 static void zend_do_delayed_early_binding(zend_op_array *op_array, zend_uint early_binding TSRMLS_DC)
910 {
911 	zend_uint opline_num = early_binding;
912 
913 	if ((int)opline_num != -1) {
914 		zend_bool orig_in_compilation = CG(in_compilation);
915 		char *orig_compiled_filename = zend_set_compiled_filename(op_array->filename TSRMLS_CC);
916 		zend_class_entry **pce;
917 
918 		CG(in_compilation) = 1;
919 		while ((int)opline_num != -1) {
920 			if (zend_lookup_class(Z_STRVAL(op_array->opcodes[opline_num - 1].op2.u.constant), Z_STRLEN(op_array->opcodes[opline_num - 1].op2.u.constant), &pce TSRMLS_CC) == SUCCESS) {
921 				do_bind_inherited_class(&op_array->opcodes[opline_num], EG(class_table), *pce, 1 TSRMLS_CC);
922 			}
923 			opline_num = op_array->opcodes[opline_num].result.u.opline_num;
924 		}
925 		zend_restore_compiled_filename(orig_compiled_filename TSRMLS_CC);
926 		CG(in_compilation) = orig_in_compilation;
927 	}
928 }
929 #endif
930 
931 zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory TSRMLS_DC)
932 {
933 	zend_op_array *op_array;
934 
935 	op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
936 	*op_array = persistent_script->main_op_array;
937 
938 	if (from_shared_memory) {
939 		/* Copy all the necessary stuff from shared memory to regular memory, and protect the shared script */
940 		if (zend_hash_num_elements(&persistent_script->class_table) > 0) {
941 			zend_hash_init(&ZCG(bind_hash), 10, NULL, NULL, 0);
942 			zend_accel_class_hash_copy(CG(class_table), &persistent_script->class_table, (unique_copy_ctor_func_t) zend_class_copy_ctor TSRMLS_CC);
943 			zend_hash_destroy(&ZCG(bind_hash));
944 		}
945 		/* we must first to copy all classes and then prepare functions, since functions may try to bind
946 		   classes - which depend on pre-bind class entries existent in the class table */
947 		if (zend_hash_num_elements(&persistent_script->function_table) > 0) {
948 			zend_accel_function_hash_copy(CG(function_table), &persistent_script->function_table, (unique_copy_ctor_func_t)zend_prepare_function_for_execution);
949 		}
950 
951 		zend_prepare_function_for_execution(op_array);
952 
953 		/* Register __COMPILER_HALT_OFFSET__ constant */
954 		if (persistent_script->compiler_halt_offset != 0 &&
955 		    persistent_script->full_path) {
956 			char *name, *cfilename;
957 			char haltoff[] = "__COMPILER_HALT_OFFSET__";
958 			int len, clen;
959 
960 			cfilename = persistent_script->full_path;
961 			clen = strlen(cfilename);
962 			zend_mangle_property_name(&name, &len, haltoff, sizeof(haltoff) - 1, cfilename, clen, 0);
963 			if (!zend_hash_exists(EG(zend_constants), name, len + 1)) {
964 				zend_register_long_constant(name, len + 1, persistent_script->compiler_halt_offset, CONST_CS, 0 TSRMLS_CC);
965 			}
966 			efree(name);
967 		}
968 
969 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
970 		if ((int)persistent_script->early_binding != -1) {
971 			zend_do_delayed_early_binding(op_array, persistent_script->early_binding TSRMLS_CC);
972 		}
973 #endif
974 
975 	} else /* if (!from_shared_memory) */ {
976 		if (zend_hash_num_elements(&persistent_script->function_table) > 0) {
977 			zend_accel_function_hash_copy(CG(function_table), &persistent_script->function_table, NULL);
978 		}
979 		if (zend_hash_num_elements(&persistent_script->class_table) > 0) {
980 			zend_accel_class_hash_copy(CG(class_table), &persistent_script->class_table, NULL TSRMLS_CC);
981 		}
982 	}
983 
984 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
985 	if (op_array->early_binding != (zend_uint)-1) {
986 		char *orig_compiled_filename = CG(compiled_filename);
987 		CG(compiled_filename) = persistent_script->full_path;
988 		zend_do_delayed_early_binding(op_array TSRMLS_CC);
989 		CG(compiled_filename) = orig_compiled_filename;
990 	}
991 #endif
992 
993 	if (!from_shared_memory) {
994 		free_persistent_script(persistent_script, 0); /* free only hashes */
995 	}
996 
997 	return op_array;
998 }
999 
1000 /*
1001  * zend_adler32() is based on zlib implementation
1002  * Computes the Adler-32 checksum of a data stream
1003  *
1004  * Copyright (C) 1995-2005 Mark Adler
1005  * For conditions of distribution and use, see copyright notice in zlib.h
1006  *
1007  * Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
1008  *
1009  *  This software is provided 'as-is', without any express or implied
1010  *  warranty.  In no event will the authors be held liable for any damages
1011  *  arising from the use of this software.
1012  *
1013  *  Permission is granted to anyone to use this software for any purpose,
1014  *  including commercial applications, and to alter it and redistribute it
1015  *  freely, subject to the following restrictions:
1016  *
1017  *  1. The origin of this software must not be misrepresented; you must not
1018  *     claim that you wrote the original software. If you use this software
1019  *     in a product, an acknowledgment in the product documentation would be
1020  *     appreciated but is not required.
1021  *  2. Altered source versions must be plainly marked as such, and must not be
1022  *     misrepresented as being the original software.
1023  *  3. This notice may not be removed or altered from any source distribution.
1024  *
1025  */
1026 
1027 #define ADLER32_BASE 65521 /* largest prime smaller than 65536 */
1028 #define ADLER32_NMAX 5552
1029 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
1030 
1031 #define ADLER32_DO1(buf)        {s1 += *(buf); s2 += s1;}
1032 #define ADLER32_DO2(buf, i)     ADLER32_DO1(buf + i); ADLER32_DO1(buf + i + 1);
1033 #define ADLER32_DO4(buf, i)     ADLER32_DO2(buf, i); ADLER32_DO2(buf, i + 2);
1034 #define ADLER32_DO8(buf, i)     ADLER32_DO4(buf, i); ADLER32_DO4(buf, i + 4);
1035 #define ADLER32_DO16(buf)       ADLER32_DO8(buf, 0); ADLER32_DO8(buf, 8);
1036 
1037 unsigned int zend_adler32(unsigned int checksum, signed char *buf, uint len)
1038 {
1039 	unsigned int s1 = checksum & 0xffff;
1040 	unsigned int s2 = (checksum >> 16) & 0xffff;
1041 	signed char *end;
1042 
1043 	while (len >= ADLER32_NMAX) {
1044 		len -= ADLER32_NMAX;
1045 		end = buf + ADLER32_NMAX;
1046 		do {
1047 			ADLER32_DO16(buf);
1048 			buf += 16;
1049 		} while (buf != end);
1050 		s1 %= ADLER32_BASE;
1051 		s2 %= ADLER32_BASE;
1052 	}
1053 
1054 	if (len) {
1055 		if (len >= 16) {
1056 			end = buf + (len & 0xfff0);
1057 			len &= 0xf;
1058 			do {
1059 				ADLER32_DO16(buf);
1060 				buf += 16;
1061 			} while (buf != end);
1062 		}
1063 		if (len) {
1064 			end = buf + len;
1065 			do {
1066 				ADLER32_DO1(buf);
1067 				buf++;
1068 			} while (buf != end);
1069 		}
1070 		s1 %= ADLER32_BASE;
1071 		s2 %= ADLER32_BASE;
1072 	}
1073 
1074 	return (s2 << 16) | s1;
1075 }
1076