Skip to content

Commit b14076a

Browse files
committed
Fix property access of PHP objects wrapped in variant
First, we fix the long standing issue that property access throws a `com_exception` ("0x80020003: member not found), because the `HRESULT` was not properly set after accessing the property. Next, we fix an issue introduced as of PHP 7.0.0, where the string length for write access had been properly adapted, but the string length for read access had been overlooked. Then we fix an issue introduced as of PHP 8.0.0, where new `HashTable`s no longer set `nNextFreeElement` to zero, but to `ZEND_LONG_MIN`. This doesn't work well with the `DISPID` lookup, which is a `LONG`. Finally we fix a potential double-free due to erroneously destroying the return value of `zend_read_property()`. Closes GH-16331.
1 parent 9345582 commit b14076a

File tree

3 files changed

+45
-7
lines changed

3 files changed

+45
-7
lines changed

NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.5.0alpha1
44

5+
- COM:
6+
. Fix property access of PHP objects wrapped in variant. (cmb)
7+
58
- DOM:
69
. Added Dom\Element::$outerHTML. (nielsdos)
710

ext/com_dotnet/com_wrapper.c

+9-7
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,11 @@ static HRESULT STDMETHODCALLTYPE disp_invokeex(
258258
* and expose it as a COM exception */
259259

260260
if (wFlags & DISPATCH_PROPERTYGET) {
261-
retval = zend_read_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name)+1, 1, &rv);
261+
retval = zend_read_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), 1, &rv);
262+
ret = S_OK;
262263
} else if (wFlags & DISPATCH_PROPERTYPUT) {
263264
zend_update_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), &params[0]);
265+
ret = S_OK;
264266
} else if (wFlags & DISPATCH_METHOD) {
265267
zend_try {
266268
retval = &rv;
@@ -305,7 +307,7 @@ static HRESULT STDMETHODCALLTYPE disp_invokeex(
305307
VariantInit(pvarRes);
306308
php_com_variant_from_zval(pvarRes, retval, COMG(code_page));
307309
}
308-
zval_ptr_dtor(retval);
310+
// zval_ptr_dtor(retval); // TODO needed for function calls?
309311
} else if (pvarRes) {
310312
VariantInit(pvarRes);
311313
}
@@ -425,7 +427,7 @@ static void generate_dispids(php_dispatchex *disp)
425427
zend_string *name = NULL;
426428
zval *tmp, tmp2;
427429
int keytype;
428-
zend_ulong pid;
430+
zend_long pid;
429431

430432
if (disp->dispid_to_name == NULL) {
431433
ALLOC_HASHTABLE(disp->dispid_to_name);
@@ -458,8 +460,8 @@ static void generate_dispids(php_dispatchex *disp)
458460

459461
/* add the mappings */
460462
ZVAL_STR_COPY(&tmp2, name);
461-
pid = zend_hash_next_free_element(disp->dispid_to_name);
462-
zend_hash_index_update(disp->dispid_to_name, pid, &tmp2);
463+
zend_hash_next_index_insert(disp->dispid_to_name, &tmp2);
464+
pid = zend_hash_next_free_element(disp->dispid_to_name) - 1;
463465

464466
ZVAL_LONG(&tmp2, pid);
465467
zend_hash_update(disp->name_to_dispid, name, &tmp2);
@@ -493,8 +495,8 @@ static void generate_dispids(php_dispatchex *disp)
493495

494496
/* add the mappings */
495497
ZVAL_STR_COPY(&tmp2, name);
496-
pid = zend_hash_next_free_element(disp->dispid_to_name);
497-
zend_hash_index_update(disp->dispid_to_name, pid, &tmp2);
498+
zend_hash_next_index_insert(disp->dispid_to_name, &tmp2);
499+
pid = zend_hash_next_free_element(disp->dispid_to_name) - 1;
498500

499501
ZVAL_LONG(&tmp2, pid);
500502
zend_hash_update(disp->name_to_dispid, name, &tmp2);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Testing reading and writing of properties
3+
--EXTENSIONS--
4+
com_dotnet
5+
--FILE--
6+
<?php
7+
class MyClass {
8+
public $foo = "foo";
9+
public string $bar = "bar";
10+
}
11+
12+
$o = new MyClass();
13+
$v = new variant($o);
14+
var_dump($v->foo);
15+
var_dump($v->bar);
16+
$v->foo = "new foo";
17+
var_dump($v->foo instanceof variant);
18+
var_dump((string) $v->foo);
19+
var_dump($o->foo instanceof variant);
20+
var_dump((string) $o->foo);
21+
$v->bar = "new bar";
22+
var_dump($v->bar);
23+
var_dump($o->bar);
24+
?>
25+
--EXPECT--
26+
string(3) "foo"
27+
string(3) "bar"
28+
bool(true)
29+
string(7) "new foo"
30+
bool(true)
31+
string(7) "new foo"
32+
string(7) "new bar"
33+
string(7) "new bar"

0 commit comments

Comments
 (0)