From 2b9bebb161834333f6ad1343ad560fecb6fb036d Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 26 Nov 2024 16:43:25 +0100 Subject: [PATCH] Fix method calls for PHP objects wrapped in variant As is, methods of PHP can never be called, because we're first trying to read the property with the name of the method. We fix this by first checking for `DISPATCH_METHOD` and treat that as method call, if the method would be callable. Only otherwise we try to access the respective property. It needs to be noted that this breaks code which accesses a property of an object, which defines a method of the same name. However, instances of such classes should never be wrapped in variants, because this can't be distinguished by COM anyway. --- ext/com_dotnet/com_wrapper.c | 14 ++++--- ext/com_dotnet/tests/variant_variation3.phpt | 41 ++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 ext/com_dotnet/tests/variant_variation3.phpt diff --git a/ext/com_dotnet/com_wrapper.c b/ext/com_dotnet/com_wrapper.c index 42698a2e651f5..81c31969161b8 100644 --- a/ext/com_dotnet/com_wrapper.c +++ b/ext/com_dotnet/com_wrapper.c @@ -257,13 +257,10 @@ static HRESULT STDMETHODCALLTYPE disp_invokeex( /* TODO: if PHP raises an exception here, we should catch it * and expose it as a COM exception */ - if (wFlags & DISPATCH_PROPERTYGET) { - retval = zend_read_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), 1, &rv); - ret = S_OK; - } else if (wFlags & DISPATCH_PROPERTYPUT) { + if (wFlags & DISPATCH_PROPERTYPUT) { zend_update_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), ¶ms[0]); ret = S_OK; - } else if (wFlags & DISPATCH_METHOD) { + } else if (wFlags & DISPATCH_METHOD && zend_is_callable_ex(name, Z_OBJ(disp->object), 0, NULL, NULL, NULL)) { zend_try { retval = &rv; if (SUCCESS == call_user_function(NULL, &disp->object, name, @@ -289,6 +286,9 @@ static HRESULT STDMETHODCALLTYPE disp_invokeex( trace("something blew up\n"); ret = DISP_E_EXCEPTION; } zend_end_try(); + } else if (wFlags & DISPATCH_PROPERTYGET) { + retval = zend_read_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), 1, &rv); + ret = S_OK; } else { trace("Don't know how to handle this invocation %08x\n", wFlags); } @@ -307,7 +307,9 @@ static HRESULT STDMETHODCALLTYPE disp_invokeex( VariantInit(pvarRes); php_com_variant_from_zval(pvarRes, retval, COMG(code_page)); } - // zval_ptr_dtor(retval); // TODO needed for function calls? + if (retval == &rv) { + zval_ptr_dtor(retval); + } } else if (pvarRes) { VariantInit(pvarRes); } diff --git a/ext/com_dotnet/tests/variant_variation3.phpt b/ext/com_dotnet/tests/variant_variation3.phpt new file mode 100644 index 0000000000000..cb77f6982c871 --- /dev/null +++ b/ext/com_dotnet/tests/variant_variation3.phpt @@ -0,0 +1,41 @@ +--TEST-- +Testing reading properties and calling functions +--EXTENSIONS-- +com_dotnet +--FILE-- +foo); +var_dump($v->foo()); +var_dump($v->bar); +var_dump($v->bar()); +var_dump($v->stdclass); +var_dump($v->stdclass()); +try { + var_dump($v->qux); +} catch (com_exception $ex) { + echo $ex->getMessage(), "\n"; +} +?> +--EXPECTF-- +string(6) "method" +string(6) "method" +string(3) "bar" +string(3) "bar" +object(variant)#%d (0) { +} +object(variant)#%d (0) { +} +Unable to lookup `qux': %s