Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cloning of com objects is seriously broken #17602

Open
cmb69 opened this issue Jan 27, 2025 · 2 comments
Open

Cloning of com objects is seriously broken #17602

cmb69 opened this issue Jan 27, 2025 · 2 comments

Comments

@cmb69
Copy link
Member

cmb69 commented Jan 27, 2025

Description

The following code:

<?php
$v = new variant("123");
$v2 = clone $v;

Resulted in this output:

Assertion failed: (!(((uintptr_t)((executor_globals.objects_store).object_buckets[handle])) & (1<<0))), file Zend\zend_objects_API.c, line 189

But I expected no output instead.


typedef struct _php_com_dotnet_object {
zend_object zo;
VARIANT v;
bool modified;
int code_page;
ITypeInfo *typeinfo;
zend_class_entry *ce;
/* associated event sink */
IDispatch *sink_dispatch;
GUID sink_id;
DWORD sink_cookie;
/* cache for method signatures */
HashTable *method_cache;
/* cache for name -> DISPID */
HashTable *id_of_name_cache;
} php_com_dotnet_object;

zend_object* php_com_object_clone(zend_object *object)
{
php_com_dotnet_object *cloneobj, *origobject;
origobject = (php_com_dotnet_object*) object;
cloneobj = (php_com_dotnet_object*)emalloc(sizeof(php_com_dotnet_object));
memcpy(cloneobj, origobject, sizeof(*cloneobj));
/* VariantCopy will perform VariantClear; we don't want to clobber
* the IDispatch that we memcpy'd, so we init a new variant in the
* clone structure */
VariantInit(&cloneobj->v);
/* We use the Indirection-following version of the API since we
* want to clone as much as possible */
VariantCopyInd(&cloneobj->v, &origobject->v);
if (cloneobj->typeinfo) {
ITypeInfo_AddRef(cloneobj->typeinfo);
}
return (zend_object*)cloneobj;
}

That memcpy() is a "bit" crude, and while we cater to v and typeinfo, we apparently missed sink_dispatch and possibly the elements of method_cache. modified seems to need an reset (not sure, though).

(I also wonder why we store the ce.)

Anyhow, I wonder if that's worth fixing, or whether we should just forbid cloning in the first place; we can still implement proper cloning if requested.

PHP Version

master (but likely since PHP 7, or even before)

Operating System

Windows

@Girgias
Copy link
Member

Girgias commented Jan 28, 2025

Honestly, I'm not sure cloning makes sense. Yes "cloning" a scalar variant is easy, but I have concerns about how crude the implementation is to properly clone more complicated variants such as arrays.

And as you said we can always relax this constraint further down the line.

@cmb69
Copy link
Member Author

cmb69 commented Jan 28, 2025

[…] but I have concerns about how crude the implementation is to properly clone more complicated variants such as arrays.

Oh, indeed, that is not properly implemented. We would at least need to check the return value of VariantCopyInd() which may fail for different reasons, and in that case throw an exception.

Also 115ee49, where we prohibited serialization for good reasons. I think these operations have been hacked in, because PHP supports it generally, but were never properly implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants