static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce)
{
	uint idx;
	Bucket *p, *q;
	zend_ulong nIndex;
	zend_op_array *new_entry;

	ht->nTableSize = source->nTableSize;
	ht->nTableMask = source->nTableMask;
	ht->nNumUsed = 0;
	ht->nNumOfElements = source->nNumOfElements;
	ht->nNextFreeElement = source->nNextFreeElement;
	ht->pDestructor = ZEND_FUNCTION_DTOR;
	ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED);
	ht->nInternalPointer = source->nNumOfElements ? 0 : INVALID_IDX;

	if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
		ht->arHash = (uint32_t*)&uninitialized_bucket;
		return;
	}

	ZEND_ASSERT(!(source->u.flags & HASH_FLAG_PACKED));
	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;
		ZEND_ASSERT(p->key != NULL);
		q->key = zend_clone_str(p->key);

		/* Copy data */
		ZVAL_PTR(&q->val, ARENA_REALLOC(Z_PTR(p->val)));
		new_entry = (zend_op_array*)Z_PTR(q->val);

		if ((void*)new_entry->scope >= ZCG(current_persistent_script)->arena_mem &&
		    (void*)new_entry->scope < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {

			new_entry->scope = ARENA_REALLOC(new_entry->scope);

			/* update prototype */
			if (new_entry->prototype) {
				new_entry->prototype = ARENA_REALLOC(new_entry->prototype);
			}
		}
	}
}
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;
	}
}
/* 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_prop_info(HashTable *ht, HashTable *source, zend_class_entry *old_ce)
{
	uint idx;
	Bucket *p, *q;
	zend_ulong nIndex;
	zend_property_info *prop_info;

	ht->nTableSize = source->nTableSize;
	ht->nTableMask = source->nTableMask;
	ht->nNumUsed = 0;
	ht->nNumOfElements = source->nNumOfElements;
	ht->nNextFreeElement = source->nNextFreeElement;
	ht->pDestructor = NULL;
	ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED);
	ht->nInternalPointer = source->nNumOfElements ? 0 : INVALID_IDX;

	if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
		ht->arHash = (uint32_t*)&uninitialized_bucket;
		return;
	}

	ZEND_ASSERT(!(source->u.flags & HASH_FLAG_PACKED));
	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;
		ZEND_ASSERT(p->key != NULL);
		q->key = zend_clone_str(p->key);

		/* Copy data */
		prop_info = ARENA_REALLOC(Z_PTR(p->val));
		ZVAL_PTR(&q->val, prop_info);

		if (prop_info->ce == old_ce || (prop_info->flags & ZEND_ACC_SHADOW)) {
			/* Copy constructor */
			prop_info->name = zend_clone_str(prop_info->name);
			if (prop_info->doc_comment) {
				if (ZCG(accel_directives).load_comments) {
					prop_info->doc_comment = zend_string_dup(prop_info->doc_comment, 0);
				} else {
					prop_info->doc_comment = NULL;
				}
			}
			prop_info->ce = ARENA_REALLOC(prop_info->ce);
		} else if ((void*)prop_info->ce >= ZCG(current_persistent_script)->arena_mem &&
		           (void*)prop_info->ce < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) {
			prop_info->ce = ARENA_REALLOC(prop_info->ce);
		}
	}
}
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);
		}
	}
}
Exemplo n.º 6
0
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);
		}
	}
}