Skip to content

Commit 56804e3

Browse files
committed
Fix GH-8750: Can not create VT_ERROR variant type
We add support for creating `VT_ERROR` variants via `__construct()`, and allow casting to int via `variant_cast()` and `variant_set_type()`. We do not, however, allow type conversion by other means, to avoid otherwise easily introduced type confusion. VB(A) also only allows explicit type conversion. We also introduce `DISP_E_PARAMNOTFOUND` which might be the most important `scode` for this purpose, since this allows to skip optional parameters in method calls. Closes GH-8886.
1 parent 6e24c16 commit 56804e3

File tree

8 files changed

+120
-5
lines changed

8 files changed

+120
-5
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ PHP NEWS
1010
json_encode(), serialize(), iconv_*(), mb_ereg*(), session_create_id(),
1111
http_build_query(), strstr(), Reflection*::__toString(). (Arnaud)
1212

13+
- COM:
14+
. Fixed bug GH-8750 (Can not create VT_ERROR variant type). (cmb)
15+
1316
- FPM:
1417
. Added listen.setfib pool option to set route FIB on FreeBSD. (David Carlier)
1518
. Added access.suppress_path pool option to filter access log entries.

UPGRADING

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ PHP 8.2 UPGRADE NOTES
264264
========================================
265265

266266
- COM_DOTNET:
267+
. DISP_E_PARAMNOTFOUND
267268
. LOCALE_NEUTRAL
268269

269270
- Curl:

ext/com_dotnet/com_extension.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@
3232
#define PHP_DISP_E_DIVBYZERO ((zend_long) (ULONG) DISP_E_DIVBYZERO)
3333
#define PHP_DISP_E_OVERFLOW ((zend_long) (ULONG) DISP_E_OVERFLOW)
3434
#define PHP_DISP_E_BADINDEX ((zend_long) (ULONG) DISP_E_BADINDEX)
35+
#define PHP_DISP_E_PARAMNOTFOUND ((zend_long) (ULONG) DISP_E_PARAMNOTFOUND)
3536
#define PHP_MK_E_UNAVAILABLE ((zend_long) (ULONG) MK_E_UNAVAILABLE)
3637
#else
3738
#define PHP_DISP_E_DIVBYZERO DISP_E_DIVBYZERO
3839
#define PHP_DISP_E_OVERFLOW DISP_E_OVERFLOW
3940
#define PHP_DISP_E_BADINDEX DISP_E_BADINDEX
41+
#define PHP_DISP_E_PARAMNOTFOUND DISP_E_PARAMNOTFOUND
4042
#define PHP_MK_E_UNAVAILABLE MK_E_UNAVAILABLE
4143
#endif
4244

ext/com_dotnet/com_extension.stub.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@
264264
* @cname PHP_DISP_E_BADINDEX
265265
*/
266266
const DISP_E_BADINDEX = UNKNOWN;
267+
/**
268+
* @var int
269+
* @cname PHP_DISP_E_PARAMNOTFOUND
270+
*/
271+
const DISP_E_PARAMNOTFOUND = UNKNOWN;
267272
/**
268273
* @var int
269274
* @cname PHP_MK_E_UNAVAILABLE

ext/com_dotnet/com_extension_arginfo.h

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/com_dotnet/com_variant.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ static void safe_array_from_zval(VARIANT *v, zval *z, int codepage)
9292
}
9393
}
9494

95-
PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage)
95+
static void php_com_variant_from_zval_ex(VARIANT *v, zval *z, int codepage, VARTYPE vt)
9696
{
9797
php_com_dotnet_object *obj;
9898
zend_uchar ztype = IS_NULL;
@@ -145,6 +145,11 @@ PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codep
145145
break;
146146

147147
case IS_LONG:
148+
if (vt == VT_ERROR) {
149+
V_VT(v) = VT_ERROR;
150+
V_ERROR(v) = Z_LVAL_P(z);
151+
break;
152+
}
148153
#if SIZEOF_ZEND_LONG == 4
149154
V_VT(v) = VT_I4;
150155
V_I4(v) = Z_LVAL_P(z);
@@ -172,6 +177,11 @@ PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codep
172177
}
173178
}
174179

180+
PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage)
181+
{
182+
php_com_variant_from_zval_ex(v, z, codepage, VT_EMPTY);
183+
}
184+
175185
PHP_COM_DOTNET_API zend_result php_com_zval_from_variant(zval *z, VARIANT *v, int codepage)
176186
{
177187
OLECHAR *olestring = NULL;
@@ -448,7 +458,7 @@ PHP_METHOD(variant, __construct)
448458
}
449459

450460
if (zvalue) {
451-
php_com_variant_from_zval(&obj->v, zvalue, obj->code_page);
461+
php_com_variant_from_zval_ex(&obj->v, zvalue, obj->code_page, vt);
452462
}
453463

454464
/* Only perform conversion if variant not already of type passed */
@@ -1019,6 +1029,7 @@ PHP_FUNCTION(variant_set_type)
10191029
zval *zobj;
10201030
php_com_dotnet_object *obj;
10211031
/* VARTYPE == unsigned short */ zend_long vt;
1032+
VARIANT vtmp;
10221033
HRESULT res;
10231034

10241035
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(),
@@ -1027,7 +1038,12 @@ PHP_FUNCTION(variant_set_type)
10271038
}
10281039
obj = CDNO_FETCH(zobj);
10291040

1030-
res = VariantChangeType(&obj->v, &obj->v, 0, (VARTYPE)vt);
1041+
if (V_VT(&obj->v) == VT_ERROR) {
1042+
VariantInit(&vtmp);
1043+
V_VT(&vtmp) = VT_I4;
1044+
V_I4(&vtmp) = V_ERROR(&obj->v);
1045+
}
1046+
res = VariantChangeType(&obj->v, V_VT(&obj->v) != VT_ERROR ? &obj->v : &vtmp, 0, (VARTYPE)vt);
10311047

10321048
if (SUCCEEDED(res)) {
10331049
if (vt != VT_DISPATCH && obj->typeinfo) {
@@ -1063,7 +1079,11 @@ PHP_FUNCTION(variant_cast)
10631079
obj = CDNO_FETCH(zobj);
10641080

10651081
VariantInit(&vres);
1066-
res = VariantChangeType(&vres, &obj->v, 0, (VARTYPE)vt);
1082+
if (V_VT(&obj->v) == VT_ERROR) {
1083+
V_VT(&vres) = VT_I4;
1084+
V_I4(&vres) = V_ERROR(&obj->v);
1085+
}
1086+
res = VariantChangeType(&vres, V_VT(&vres) == VT_EMPTY ? &obj->v : &vres, 0, (VARTYPE)vt);
10671087

10681088
if (SUCCEEDED(res)) {
10691089
php_com_wrap_variant(return_value, &vres, obj->code_page);

ext/com_dotnet/tests/gh8750.phpt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--TEST--
2+
Bug GH-8750 (Can not create VT_ERROR variant type)
3+
--EXTENSIONS--
4+
com_dotnet
5+
--SKIPIF--
6+
<?php
7+
$provider = "Microsoft.ACE.OLEDB.12.0";
8+
$filename = __DIR__ . "\\gh8750.mdb";
9+
$catalog = new com("ADOX.Catalog");
10+
try {
11+
$catalog->Create("Provider=$provider;Data Source=$filename");
12+
} catch (com_exception) {
13+
die("skip $provider provider not available");
14+
}
15+
$catalog = null;
16+
@unlink($filename);
17+
?>
18+
--FILE--
19+
<?php
20+
$filename = __DIR__ . "\\gh8750.mdb";
21+
22+
$catalog = new com("ADOX.Catalog");
23+
$catalog->Create("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$filename");
24+
$catalog = null;
25+
26+
$db = new com("ADODB.Connection");
27+
$db->ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$filename";
28+
$db->Mode = 1; // adModeRead
29+
$db->Open();
30+
// adSchemaProviderSpecific, *missing*, JET_SCHEMA_USERROSTER
31+
$rs = $db->OpenSchema(-1, new variant(DISP_E_PARAMNOTFOUND, VT_ERROR), "{947bb102-5d43-11d1-bdbf-00c04fb92675}");
32+
// manual counting since rs.RecordCount is -1 (not supported)
33+
$i = 0;
34+
while (!$rs->EOF) {
35+
$rs->MoveNext();
36+
$i++;
37+
}
38+
$rs->Close();
39+
$db->Close();
40+
var_dump($i);
41+
?>
42+
--EXPECT--
43+
int(1)
44+
--CLEAN--
45+
<?php
46+
unlink(__DIR__ . "/gh8750.mdb");
47+
?>

ext/com_dotnet/tests/gh8750a.phpt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
Bug GH-8750 (Can not create VT_ERROR variant type) - cast and conversion
3+
--EXTENSIONS--
4+
com_dotnet
5+
--FILE--
6+
<?php
7+
$error = new variant(DISP_E_PARAMNOTFOUND, VT_ERROR);
8+
9+
// explicit variant_cast() to int is supported if in range
10+
echo variant_cast($error, VT_I4), PHP_EOL;
11+
12+
// however, explicit (int) casts are not supported
13+
echo (int) $error, PHP_EOL;
14+
15+
// nor are implicit conversions
16+
try {
17+
echo 1 + $error, PHP_EOL;
18+
} catch (TypeError $err) {
19+
echo $err->getMessage(), PHP_EOL;
20+
}
21+
22+
// we can retrieve the type
23+
echo variant_get_type($error), PHP_EOL;
24+
25+
// and change it via variant_set_type()
26+
variant_set_type($error, VT_I4);
27+
echo variant_get_type($error), PHP_EOL;
28+
?>
29+
--EXPECTF--
30+
-2147352572
31+
32+
Warning: Object of class variant could not be converted to int in %s on line %d
33+
1
34+
Unsupported operand types: int + variant
35+
10
36+
3

0 commit comments

Comments
 (0)