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