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