From 8b682743196e765debb5056e56a97a67304f5e62 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. Closes GH-16945. --- NEWS | 3 +- ext/com_dotnet/com_wrapper.c | 14 ++++--- ext/com_dotnet/tests/variant_variation3.phpt | 41 ++++++++++++++++++++ 3 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 ext/com_dotnet/tests/variant_variation3.phpt diff --git a/NEWS b/NEWS index 2bc7d6131aa..fb54b6c67a1 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,8 @@ PHP NEWS ?? ??? ????, PHP 8.5.0alpha1 - COM: - . Fix property access of PHP objects wrapped in variant. (cmb) + . Fixed property access of PHP objects wrapped in variant. (cmb) + . Fixed method calls for PHP objects wrapped in variant. (cmb) - Core: . Fixed bug GH-16665 (\array and \callable should not be usable in diff --git a/ext/com_dotnet/com_wrapper.c b/ext/com_dotnet/com_wrapper.c index 42698a2e651..81c31969161 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 00000000000..cb77f6982c8 --- /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