Merge branch 'PHP-7.4'

* PHP-7.4:
  Fix #63208: BSTR to PHP string conversion not binary safe
This commit is contained in:
Christoph M. Becker 2020-06-29 19:06:56 +02:00
commit bf6720d582
4 changed files with 77 additions and 14 deletions

View file

@ -101,3 +101,58 @@ PHP_COM_DOTNET_API char *php_com_olestring_to_string(OLECHAR *olestring, size_t
return string; return string;
} }
BSTR php_com_string_to_bstr(zend_string *string, int codepage)
{
BSTR bstr = NULL;
DWORD flags = codepage == CP_UTF8 ? 0 : MB_PRECOMPOSED | MB_ERR_INVALID_CHARS;
size_t mb_len = ZSTR_LEN(string);
int wc_len;
if ((wc_len = MultiByteToWideChar(codepage, flags, ZSTR_VAL(string), (int)mb_len + 1, NULL, 0)) <= 0) {
goto fail;
}
if ((bstr = SysAllocStringLen(NULL, (UINT)(wc_len - 1))) == NULL) {
goto fail;
}
if ((wc_len = MultiByteToWideChar(codepage, flags, ZSTR_VAL(string), (int)mb_len + 1, bstr, wc_len)) <= 0) {
goto fail;
}
return bstr;
fail:
char *msg = php_win32_error_to_msg(GetLastError());
php_error_docref(NULL, E_WARNING,
"Could not convert string to unicode: `%s'", msg);
LocalFree(msg);
SysFreeString(bstr);
return SysAllocString(L"");
}
zend_string *php_com_bstr_to_string(BSTR bstr, int codepage)
{
zend_string *string = NULL;
UINT wc_len = SysStringLen(bstr);
int mb_len;
mb_len = WideCharToMultiByte(codepage, 0, bstr, wc_len + 1, NULL, 0, NULL, NULL);
if (mb_len > 0) {
string = zend_string_alloc(mb_len - 1, 0);
mb_len = WideCharToMultiByte(codepage, 0, bstr, wc_len + 1, ZSTR_VAL(string), mb_len, NULL, NULL);
}
if (mb_len <= 0) {
char *msg = php_win32_error_to_msg(GetLastError());
php_error_docref(NULL, E_WARNING,
"Could not convert string from unicode: `%s'", msg);
LocalFree(msg);
if (string != NULL) {
zend_string_release(string);
}
string = ZSTR_EMPTY_ALLOC();
}
return string;
}

View file

@ -94,7 +94,6 @@ bogus:
PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage) PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage)
{ {
OLECHAR *olestring;
php_com_dotnet_object *obj; php_com_dotnet_object *obj;
zend_uchar ztype = IS_NULL; zend_uchar ztype = IS_NULL;
@ -162,13 +161,7 @@ PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codep
case IS_STRING: case IS_STRING:
V_VT(v) = VT_BSTR; V_VT(v) = VT_BSTR;
olestring = php_com_string_to_olestring(Z_STRVAL_P(z), Z_STRLEN_P(z), codepage); V_BSTR(v) = php_com_string_to_bstr(Z_STR_P(z), codepage);
if (CP_UTF8 == codepage) {
V_BSTR(v) = SysAllocStringByteLen((char*)olestring, (UINT)(wcslen(olestring) * sizeof(OLECHAR)));
} else {
V_BSTR(v) = SysAllocStringByteLen((char*)olestring, (UINT)(Z_STRLEN_P(z) * sizeof(OLECHAR)));
}
efree(olestring);
break; break;
case IS_RESOURCE: case IS_RESOURCE:
@ -234,12 +227,8 @@ PHP_COM_DOTNET_API int php_com_zval_from_variant(zval *z, VARIANT *v, int codepa
case VT_BSTR: case VT_BSTR:
olestring = V_BSTR(v); olestring = V_BSTR(v);
if (olestring) { if (olestring) {
size_t len; zend_string *str = php_com_bstr_to_string(olestring, codepage);
char *str = php_com_olestring_to_string(olestring, ZVAL_STR(z, str);
&len, codepage);
ZVAL_STRINGL(z, str, len);
// TODO: avoid reallocation???
efree(str);
olestring = NULL; olestring = NULL;
} }
break; break;

View file

@ -84,6 +84,8 @@ PHP_COM_DOTNET_API char *php_com_olestring_to_string(OLECHAR *olestring,
size_t *string_len, int codepage); size_t *string_len, int codepage);
PHP_COM_DOTNET_API OLECHAR *php_com_string_to_olestring(const char *string, PHP_COM_DOTNET_API OLECHAR *php_com_string_to_olestring(const char *string,
size_t string_len, int codepage); size_t string_len, int codepage);
BSTR php_com_string_to_bstr(zend_string *string, int codepage);
zend_string *php_com_bstr_to_string(BSTR bstr, int codepage);
/* com_com.c */ /* com_com.c */

View file

@ -0,0 +1,17 @@
--TEST--
Bug #63208 (BSTR to PHP string conversion not binary safe)
--SKIPIF--
<?php
if (!extension_loaded('com_dotnet')) die('skip com_dotnet extension not available');
?>
--FILE--
<?php
$string = "\u{0905}b\0cd";
$variant = new VARIANT($string, VT_ARRAY | VT_UI1, CP_UTF8); // Array of bytes
$converted = (string) $variant;
var_dump(bin2hex($string));
var_dump(bin2hex($converted));
?>
--EXPECT--
string(14) "e0a48562006364"
string(14) "e0a48562006364"