static inline void zend_clone_zval(zval *src, int bind) { void *ptr; if (Z_IMMUTABLE_P(src)) { return; } switch (Z_TYPE_P(src)) { case IS_STRING: case IS_CONSTANT: Z_STR_P(src) = zend_clone_str(Z_STR_P(src)); break; case IS_ARRAY: if (Z_ARR_P(src) != &EG(symbol_table)) { if (bind && Z_REFCOUNT_P(src) > 1 && (ptr = accel_xlat_get(Z_ARR_P(src))) != NULL) { Z_ARR_P(src) = ptr; } else { zend_array *old = Z_ARR_P(src); Z_ARR_P(src) = emalloc(sizeof(zend_array)); Z_ARR_P(src)->gc = old->gc; if (bind && Z_REFCOUNT_P(src) > 1) { accel_xlat_set(old, Z_ARR_P(src)); } zend_hash_clone_zval(Z_ARRVAL_P(src), old, 0); } } break; case IS_REFERENCE: if (bind && Z_REFCOUNT_P(src) > 1 && (ptr = accel_xlat_get(Z_REF_P(src))) != NULL) { Z_REF_P(src) = ptr; } else { zend_reference *old = Z_REF_P(src); ZVAL_NEW_REF(src, &old->val); Z_REF_P(src)->gc = old->gc; if (bind && Z_REFCOUNT_P(src) > 1) { accel_xlat_set(old, Z_REF_P(src)); } zend_clone_zval(Z_REFVAL_P(src), bind); } break; case IS_CONSTANT_AST: if (bind && Z_REFCOUNT_P(src) > 1 && (ptr = accel_xlat_get(Z_AST_P(src))) != NULL) { Z_AST_P(src) = ptr; } else { zend_ast_ref *old = Z_AST_P(src); ZVAL_NEW_AST(src, old->ast); Z_AST_P(src)->gc = old->gc; if (bind && Z_REFCOUNT_P(src) > 1) { accel_xlat_set(old, Z_AST_P(src)); } Z_ASTVAL_P(src) = zend_ast_clone(Z_ASTVAL_P(src)); } break; } }
static zend_ast *zend_ast_clone(zend_ast *ast) { uint32_t i; if (ast->kind == ZEND_AST_ZVAL) { zend_ast_zval *copy = emalloc(sizeof(zend_ast_zval)); copy->kind = ZEND_AST_ZVAL; copy->attr = ast->attr; ZVAL_COPY_VALUE(©->val, zend_ast_get_zval(ast)); zend_clone_zval(©->val, 0); return (zend_ast *) copy; } else if (zend_ast_is_list(ast)) { zend_ast_list *list = zend_ast_get_list(ast); zend_ast_list *copy = emalloc( sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * list->children); copy->kind = list->kind; copy->attr = list->attr; copy->children = list->children; for (i = 0; i < list->children; i++) { if (list->child[i]) { copy->child[i] = zend_ast_clone(list->child[i]); } else { copy->child[i] = NULL; } } return (zend_ast *) copy; } else { uint32_t children = zend_ast_get_num_children(ast); zend_ast *copy = emalloc(sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children); copy->kind = ast->kind; copy->attr = ast->attr; for (i = 0; i < children; i++) { if (ast->child[i]) { copy->child[i] = zend_ast_clone(ast->child[i]); } else { copy->child[i] = NULL; } } return copy; } }
/* Protects class' refcount, copies default properties, functions and class name */ static void zend_class_copy_ctor(zend_class_entry **pce) { zend_class_entry *ce = *pce; zend_class_entry *old_ce = ce; *pce = ce = ARENA_REALLOC(old_ce); ce->refcount = 1; if (old_ce->default_properties_table) { int i; ce->default_properties_table = emalloc(sizeof(zval) * old_ce->default_properties_count); for (i = 0; i < old_ce->default_properties_count; i++) { ZVAL_COPY_VALUE(&ce->default_properties_table[i], &old_ce->default_properties_table[i]); zend_clone_zval(&ce->default_properties_table[i], 1); } } zend_hash_clone_methods(&ce->function_table, &old_ce->function_table, old_ce, ce); /* static members */ if (old_ce->default_static_members_table) { int i; ce->default_static_members_table = emalloc(sizeof(zval) * old_ce->default_static_members_count); for (i = 0; i < old_ce->default_static_members_count; i++) { ZVAL_COPY_VALUE(&ce->default_static_members_table[i], &old_ce->default_static_members_table[i]); zend_clone_zval(&ce->default_static_members_table[i], 1); } } ce->static_members_table = ce->default_static_members_table; /* properties_info */ zend_hash_clone_prop_info(&ce->properties_info, &old_ce->properties_info, old_ce); /* constants table */ zend_hash_clone_zval(&ce->constants_table, &old_ce->constants_table, 1); ce->constants_table.u.flags &= ~HASH_FLAG_APPLY_PROTECTION; ce->name = zend_clone_str(ce->name); /* interfaces aren't really implemented, so we create a new table */ if (ce->num_interfaces) { ce->interfaces = emalloc(sizeof(zend_class_entry *) * ce->num_interfaces); memset(ce->interfaces, 0, sizeof(zend_class_entry *) * ce->num_interfaces); } else { ce->interfaces = NULL; } if (ZEND_CE_DOC_COMMENT(ce)) { if (ZCG(accel_directives).load_comments) { ZEND_CE_DOC_COMMENT(ce) = zend_string_dup(ZEND_CE_DOC_COMMENT(ce), 0); } else { ZEND_CE_DOC_COMMENT(ce) = NULL; } } if (ce->parent) { ce->parent = ARENA_REALLOC(ce->parent); } zend_update_inherited_handler(constructor); zend_update_inherited_handler(destructor); zend_update_inherited_handler(clone); zend_update_inherited_handler(__get); zend_update_inherited_handler(__set); zend_update_inherited_handler(__call); /* 5.1 stuff */ zend_update_inherited_handler(serialize_func); zend_update_inherited_handler(unserialize_func); zend_update_inherited_handler(__isset); zend_update_inherited_handler(__unset); /* 5.2 stuff */ zend_update_inherited_handler(__tostring); /* 5.3 stuff */ zend_update_inherited_handler(__callstatic); zend_update_inherited_handler(__debugInfo); /* 5.4 traits */ if (ce->trait_aliases) { zend_trait_alias **trait_aliases; int i = 0; while (ce->trait_aliases[i]) { i++; } trait_aliases = emalloc(sizeof(zend_trait_alias*) * (i + 1)); i = 0; while (ce->trait_aliases[i]) { trait_aliases[i] = emalloc(sizeof(zend_trait_alias)); memcpy(trait_aliases[i], ce->trait_aliases[i], sizeof(zend_trait_alias)); trait_aliases[i]->trait_method = emalloc(sizeof(zend_trait_method_reference)); memcpy(trait_aliases[i]->trait_method, ce->trait_aliases[i]->trait_method, sizeof(zend_trait_method_reference)); if (trait_aliases[i]->trait_method) { if (trait_aliases[i]->trait_method->method_name) { trait_aliases[i]->trait_method->method_name = zend_clone_str(trait_aliases[i]->trait_method->method_name); } if (trait_aliases[i]->trait_method->class_name) { trait_aliases[i]->trait_method->class_name = zend_clone_str(trait_aliases[i]->trait_method->class_name); } } if (trait_aliases[i]->alias) { trait_aliases[i]->alias = zend_clone_str(trait_aliases[i]->alias); } i++; } trait_aliases[i] = NULL; ce->trait_aliases = trait_aliases; } if (ce->trait_precedences) { zend_trait_precedence **trait_precedences; int i = 0; while (ce->trait_precedences[i]) { i++; } trait_precedences = emalloc(sizeof(zend_trait_precedence*) * (i + 1)); i = 0; while (ce->trait_precedences[i]) { trait_precedences[i] = emalloc(sizeof(zend_trait_precedence)); memcpy(trait_precedences[i], ce->trait_precedences[i], sizeof(zend_trait_precedence)); trait_precedences[i]->trait_method = emalloc(sizeof(zend_trait_method_reference)); memcpy(trait_precedences[i]->trait_method, ce->trait_precedences[i]->trait_method, sizeof(zend_trait_method_reference)); trait_precedences[i]->trait_method->method_name = zend_clone_str(trait_precedences[i]->trait_method->method_name); trait_precedences[i]->trait_method->class_name = zend_clone_str(trait_precedences[i]->trait_method->class_name); if (trait_precedences[i]->exclude_from_classes) { zend_string **exclude_from_classes; int j = 0; while (trait_precedences[i]->exclude_from_classes[j].class_name) { j++; } exclude_from_classes = emalloc(sizeof(zend_string*) * (j + 1)); j = 0; while (trait_precedences[i]->exclude_from_classes[j].class_name) { exclude_from_classes[j] = zend_clone_str(trait_precedences[i]->exclude_from_classes[j].class_name); j++; } exclude_from_classes[j] = NULL; trait_precedences[i]->exclude_from_classes = (void*)exclude_from_classes; } i++; } trait_precedences[i] = NULL; ce->trait_precedences = trait_precedences; } }
static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind) { uint idx; Bucket *p, *q, *r; zend_ulong nIndex; ht->nTableSize = source->nTableSize; ht->nTableMask = source->nTableMask; ht->nNumUsed = 0; ht->nNumOfElements = source->nNumOfElements; ht->nNextFreeElement = source->nNextFreeElement; ht->pDestructor = ZVAL_PTR_DTOR; ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED) | HASH_FLAG_APPLY_PROTECTION; ht->arData = NULL; ht->arHash = NULL; ht->nInternalPointer = source->nNumOfElements ? 0 : INVALID_IDX; if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) { ht->arHash = (uint32_t*)&uninitialized_bucket; return; } if (source->u.flags & HASH_FLAG_PACKED) { ht->u.flags |= HASH_FLAG_PACKED; ht->arData = (Bucket *) emalloc(ht->nTableSize * sizeof(Bucket)); ht->arHash = (uint32_t*)&uninitialized_bucket; for (idx = 0; idx < source->nNumUsed; idx++) { p = source->arData + idx; if (Z_TYPE(p->val) == IS_UNDEF) continue; nIndex = p->h & ht->nTableMask; r = ht->arData + ht->nNumUsed; q = ht->arData + p->h; while (r != q) { ZVAL_UNDEF(&r->val); r++; } ht->nNumUsed = p->h + 1; /* Initialize key */ q->h = p->h; q->key = NULL; /* Copy data */ ZVAL_COPY_VALUE(&q->val, &p->val); zend_clone_zval(&q->val, bind); } } else { ht->arData = (Bucket *) emalloc(ht->nTableSize * (sizeof(Bucket) + sizeof(uint32_t))); ht->arHash = (uint32_t*)(ht->arData + ht->nTableSize); memset(ht->arHash, INVALID_IDX, sizeof(uint32_t) * ht->nTableSize); for (idx = 0; idx < source->nNumUsed; idx++) { p = source->arData + idx; if (Z_TYPE(p->val) == IS_UNDEF) continue; nIndex = p->h & ht->nTableMask; /* Insert into hash collision list */ q = ht->arData + ht->nNumUsed; Z_NEXT(q->val) = ht->arHash[nIndex]; ht->arHash[nIndex] = ht->nNumUsed++; /* Initialize key */ q->h = p->h; if (!p->key) { q->key = NULL; } else { q->key = zend_clone_str(p->key); } /* Copy data */ ZVAL_COPY_VALUE(&q->val, &p->val); zend_clone_zval(&q->val, bind); } } }
static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind) { uint idx; Bucket *p, *q, *r; zend_ulong nIndex; ht->nTableSize = source->nTableSize; ht->nTableMask = source->nTableMask; ht->nNumUsed = 0; ht->nNumOfElements = source->nNumOfElements; ht->nNextFreeElement = source->nNextFreeElement; ht->pDestructor = ZVAL_PTR_DTOR; ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED) | HASH_FLAG_APPLY_PROTECTION; ht->nInternalPointer = source->nNumOfElements ? 0 : HT_INVALID_IDX; if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) { ht->arData = source->arData; return; } if (source->u.flags & HASH_FLAG_PACKED) { ht->u.flags |= HASH_FLAG_PACKED; HT_SET_DATA_ADDR(ht, (Bucket *) emalloc(HT_SIZE(ht))); HT_HASH_RESET_PACKED(ht); for (idx = 0; idx < source->nNumUsed; idx++) { p = source->arData + idx; if (Z_TYPE(p->val) == IS_UNDEF) continue; nIndex = p->h | ht->nTableMask; r = ht->arData + ht->nNumUsed; q = ht->arData + p->h; while (r != q) { ZVAL_UNDEF(&r->val); r++; } ht->nNumUsed = p->h + 1; /* Initialize key */ q->h = p->h; q->key = NULL; /* Copy data */ ZVAL_COPY_VALUE(&q->val, &p->val); zend_clone_zval(&q->val, bind); } } else { HT_SET_DATA_ADDR(ht, emalloc(HT_SIZE(ht))); HT_HASH_RESET(ht); for (idx = 0; idx < source->nNumUsed; idx++) { p = source->arData + idx; if (Z_TYPE(p->val) == IS_UNDEF) continue; nIndex = p->h | ht->nTableMask; /* Insert into hash collision list */ q = ht->arData + ht->nNumUsed; Z_NEXT(q->val) = HT_HASH(ht, nIndex); HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(ht->nNumUsed++); /* Initialize key */ q->h = p->h; if (!p->key) { q->key = NULL; } else { q->key = zend_clone_str(p->key); } /* Copy data */ ZVAL_COPY_VALUE(&q->val, &p->val); zend_clone_zval(&q->val, bind); } } }