Skip to content

Commit bf6720d

Browse files
committed
Merge branch 'PHP-7.4'
* PHP-7.4: Fix #63208: BSTR to PHP string conversion not binary safe
2 parents 43b5d58 + 4af69b8 commit bf6720d

File tree

4 files changed

+77
-14
lines changed

4 files changed

+77
-14
lines changed

ext/com_dotnet/com_olechar.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,58 @@ PHP_COM_DOTNET_API char *php_com_olestring_to_string(OLECHAR *olestring, size_t
101101

102102
return string;
103103
}
104+
105+
BSTR php_com_string_to_bstr(zend_string *string, int codepage)
106+
{
107+
BSTR bstr = NULL;
108+
DWORD flags = codepage == CP_UTF8 ? 0 : MB_PRECOMPOSED | MB_ERR_INVALID_CHARS;
109+
size_t mb_len = ZSTR_LEN(string);
110+
int wc_len;
111+
112+
if ((wc_len = MultiByteToWideChar(codepage, flags, ZSTR_VAL(string), (int)mb_len + 1, NULL, 0)) <= 0) {
113+
goto fail;
114+
}
115+
if ((bstr = SysAllocStringLen(NULL, (UINT)(wc_len - 1))) == NULL) {
116+
goto fail;
117+
}
118+
if ((wc_len = MultiByteToWideChar(codepage, flags, ZSTR_VAL(string), (int)mb_len + 1, bstr, wc_len)) <= 0) {
119+
goto fail;
120+
}
121+
return bstr;
122+
123+
fail:
124+
char *msg = php_win32_error_to_msg(GetLastError());
125+
php_error_docref(NULL, E_WARNING,
126+
"Could not convert string to unicode: `%s'", msg);
127+
LocalFree(msg);
128+
SysFreeString(bstr);
129+
return SysAllocString(L"");
130+
}
131+
132+
zend_string *php_com_bstr_to_string(BSTR bstr, int codepage)
133+
{
134+
zend_string *string = NULL;
135+
UINT wc_len = SysStringLen(bstr);
136+
int mb_len;
137+
138+
mb_len = WideCharToMultiByte(codepage, 0, bstr, wc_len + 1, NULL, 0, NULL, NULL);
139+
if (mb_len > 0) {
140+
string = zend_string_alloc(mb_len - 1, 0);
141+
mb_len = WideCharToMultiByte(codepage, 0, bstr, wc_len + 1, ZSTR_VAL(string), mb_len, NULL, NULL);
142+
}
143+
144+
if (mb_len <= 0) {
145+
char *msg = php_win32_error_to_msg(GetLastError());
146+
147+
php_error_docref(NULL, E_WARNING,
148+
"Could not convert string from unicode: `%s'", msg);
149+
LocalFree(msg);
150+
151+
if (string != NULL) {
152+
zend_string_release(string);
153+
}
154+
string = ZSTR_EMPTY_ALLOC();
155+
}
156+
157+
return string;
158+
}

ext/com_dotnet/com_variant.c

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ static void safe_array_from_zval(VARIANT *v, zval *z, int codepage)
9494

9595
PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage)
9696
{
97-
OLECHAR *olestring;
9897
php_com_dotnet_object *obj;
9998
zend_uchar ztype = IS_NULL;
10099

@@ -162,13 +161,7 @@ PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codep
162161

163162
case IS_STRING:
164163
V_VT(v) = VT_BSTR;
165-
olestring = php_com_string_to_olestring(Z_STRVAL_P(z), Z_STRLEN_P(z), codepage);
166-
if (CP_UTF8 == codepage) {
167-
V_BSTR(v) = SysAllocStringByteLen((char*)olestring, (UINT)(wcslen(olestring) * sizeof(OLECHAR)));
168-
} else {
169-
V_BSTR(v) = SysAllocStringByteLen((char*)olestring, (UINT)(Z_STRLEN_P(z) * sizeof(OLECHAR)));
170-
}
171-
efree(olestring);
164+
V_BSTR(v) = php_com_string_to_bstr(Z_STR_P(z), codepage);
172165
break;
173166

174167
case IS_RESOURCE:
@@ -234,12 +227,8 @@ PHP_COM_DOTNET_API int php_com_zval_from_variant(zval *z, VARIANT *v, int codepa
234227
case VT_BSTR:
235228
olestring = V_BSTR(v);
236229
if (olestring) {
237-
size_t len;
238-
char *str = php_com_olestring_to_string(olestring,
239-
&len, codepage);
240-
ZVAL_STRINGL(z, str, len);
241-
// TODO: avoid reallocation???
242-
efree(str);
230+
zend_string *str = php_com_bstr_to_string(olestring, codepage);
231+
ZVAL_STR(z, str);
243232
olestring = NULL;
244233
}
245234
break;

ext/com_dotnet/php_com_dotnet_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ PHP_COM_DOTNET_API char *php_com_olestring_to_string(OLECHAR *olestring,
8484
size_t *string_len, int codepage);
8585
PHP_COM_DOTNET_API OLECHAR *php_com_string_to_olestring(const char *string,
8686
size_t string_len, int codepage);
87+
BSTR php_com_string_to_bstr(zend_string *string, int codepage);
88+
zend_string *php_com_bstr_to_string(BSTR bstr, int codepage);
8789

8890

8991
/* com_com.c */

ext/com_dotnet/tests/bug63208.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Bug #63208 (BSTR to PHP string conversion not binary safe)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('com_dotnet')) die('skip com_dotnet extension not available');
6+
?>
7+
--FILE--
8+
<?php
9+
$string = "\u{0905}b\0cd";
10+
$variant = new VARIANT($string, VT_ARRAY | VT_UI1, CP_UTF8); // Array of bytes
11+
$converted = (string) $variant;
12+
var_dump(bin2hex($string));
13+
var_dump(bin2hex($converted));
14+
?>
15+
--EXPECT--
16+
string(14) "e0a48562006364"
17+
string(14) "e0a48562006364"

0 commit comments

Comments
 (0)