diff --git a/NEWS b/NEWS index 5ba60191067..2c8da20466c 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,9 @@ PHP NEWS . Fixed bug #79030 (Upgrade apache2handler's php_apache_sapi_get_request_time to return usec). (Herbert256) +- COM: + . Fixed bug #63208 (BSTR to PHP string conversion not binary safe). (cmb) + - Curl: . Fixed bug #79741 (curl_setopt CURLOPT_POSTFIELDS asserts on object with declared properties). (Nikita) diff --git a/ext/com_dotnet/com_olechar.c b/ext/com_dotnet/com_olechar.c index b9a332e4f54..1cd1017a024 100644 --- a/ext/com_dotnet/com_olechar.c +++ b/ext/com_dotnet/com_olechar.c @@ -103,3 +103,58 @@ PHP_COM_DOTNET_API char *php_com_olestring_to_string(OLECHAR *olestring, size_t 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; +} diff --git a/ext/com_dotnet/com_variant.c b/ext/com_dotnet/com_variant.c index f4f7d5a9dde..901b0a866a1 100644 --- a/ext/com_dotnet/com_variant.c +++ b/ext/com_dotnet/com_variant.c @@ -96,7 +96,6 @@ bogus: PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage) { - OLECHAR *olestring; php_com_dotnet_object *obj; zend_uchar ztype = IS_NULL; @@ -164,13 +163,7 @@ PHP_COM_DOTNET_API void php_com_variant_from_zval(VARIANT *v, zval *z, int codep case IS_STRING: V_VT(v) = VT_BSTR; - olestring = php_com_string_to_olestring(Z_STRVAL_P(z), Z_STRLEN_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); + V_BSTR(v) = php_com_string_to_bstr(Z_STR_P(z), codepage); break; case IS_RESOURCE: @@ -236,12 +229,8 @@ PHP_COM_DOTNET_API int php_com_zval_from_variant(zval *z, VARIANT *v, int codepa case VT_BSTR: olestring = V_BSTR(v); if (olestring) { - size_t len; - char *str = php_com_olestring_to_string(olestring, - &len, codepage); - ZVAL_STRINGL(z, str, len); - // TODO: avoid reallocation??? - efree(str); + zend_string *str = php_com_bstr_to_string(olestring, codepage); + ZVAL_STR(z, str); olestring = NULL; } break; diff --git a/ext/com_dotnet/php_com_dotnet_internal.h b/ext/com_dotnet/php_com_dotnet_internal.h index a2fe8136832..663c0694fe1 100644 --- a/ext/com_dotnet/php_com_dotnet_internal.h +++ b/ext/com_dotnet/php_com_dotnet_internal.h @@ -89,6 +89,8 @@ PHP_COM_DOTNET_API char *php_com_olestring_to_string(OLECHAR *olestring, size_t *string_len, int codepage); PHP_COM_DOTNET_API OLECHAR *php_com_string_to_olestring(char *string, 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 */ diff --git a/ext/com_dotnet/tests/bug63208.phpt b/ext/com_dotnet/tests/bug63208.phpt new file mode 100644 index 00000000000..ae62dbba980 --- /dev/null +++ b/ext/com_dotnet/tests/bug63208.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #63208 (BSTR to PHP string conversion not binary safe) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(14) "e0a48562006364" +string(14) "e0a48562006364"