Fix localized error messages and memory leaks

The FormatMessage API needs to LocalFree the delivered error messages.
In cases where messages are delivered in non ASCII compatible encoding,
the messages might be unreadable. This aligns the error message encoding
with the encoding settings in PHP, the focus is UTF-8 as default.

Initialize error buffer

Avoid code duplication
This commit is contained in:
Anatol Belski 2018-09-17 09:48:33 +02:00
parent 3b475910d6
commit 321c0cc349
20 changed files with 105 additions and 135 deletions

View File

@ -68,6 +68,7 @@
#ifdef ZEND_WIN32
# include <wincrypt.h>
# include <process.h>
# include "win32/winutil.h"
#endif
#include <stdio.h>
@ -394,23 +395,17 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap,
void
stderr_last_error(char *msg)
{
LPSTR buf = NULL;
DWORD err = GetLastError();
char *buf = php_win32_error_to_msg(err);
if (!FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&buf,
0, NULL)) {
if (!buf[0]) {
fprintf(stderr, "\n%s: [0x%08lx]\n", msg, err);
}
else {
fprintf(stderr, "\n%s: [0x%08lx] %s\n", msg, err, buf);
}
php_win32_error_msg_free(buf);
}
#endif

View File

@ -231,7 +231,7 @@ PHP_FUNCTION(com_create_instance)
werr = php_win32_error_to_msg(res);
spprintf(&msg, 0, "Failed to create COM object `%s': %s", module_name, werr);
LocalFree(werr);
php_win32_error_msg_free(werr);
php_com_throw_exception(res, msg);
efree(msg);
@ -389,7 +389,7 @@ HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
case DISP_E_TYPEMISMATCH:
desc = php_win32_error_to_msg(hr);
spprintf(&msg, 0, "Parameter %d: %s", arg_err, desc);
LocalFree(desc);
php_win32_error_msg_free(desc);
break;
case DISP_E_BADPARAMCOUNT:
@ -405,7 +405,7 @@ HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
default:
desc = php_win32_error_to_msg(hr);
spprintf(&msg, 0, "Error [0x%08x] %s", hr, desc);
LocalFree(desc);
php_win32_error_msg_free(desc);
break;
}
@ -485,11 +485,10 @@ int php_com_do_invoke_byref(php_com_dotnet_object *obj, zend_internal_function *
hr = php_com_get_id_of_name(obj, f->function_name->val, f->function_name->len, &dispid);
if (FAILED(hr)) {
char *winerr = NULL;
char *msg = NULL;
winerr = php_win32_error_to_msg(hr);
char *winerr = php_win32_error_to_msg(hr);
spprintf(&msg, 0, "Unable to lookup `%s': %s", f->function_name->val, winerr);
LocalFree(winerr);
php_win32_error_msg_free(winerr);
php_com_throw_exception(hr, msg);
efree(msg);
return FAILURE;
@ -648,15 +647,14 @@ int php_com_do_invoke(php_com_dotnet_object *obj, char *name, size_t namelen,
{
DISPID dispid;
HRESULT hr;
char *winerr = NULL;
char *msg = NULL;
hr = php_com_get_id_of_name(obj, name, namelen, &dispid);
if (FAILED(hr)) {
winerr = php_win32_error_to_msg(hr);
char *winerr = php_win32_error_to_msg(hr);
spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
LocalFree(winerr);
php_win32_error_msg_free(winerr);
php_com_throw_exception(hr, msg);
efree(msg);
return FAILURE;

View File

@ -205,8 +205,7 @@ PHP_FUNCTION(com_dotnet_create_instance)
char buf[1024];
char *err = php_win32_error_to_msg(hr);
snprintf(buf, sizeof(buf), "Failed to init .Net runtime [%s] %s", where, err);
if (err)
LocalFree(err);
php_win32_error_msg_free(err);
php_com_throw_exception(hr, buf);
return;
}
@ -219,8 +218,7 @@ PHP_FUNCTION(com_dotnet_create_instance)
char buf[1024];
char *err = php_win32_error_to_msg(hr);
snprintf(buf, sizeof(buf), "Failed to re-init .Net domain [%s] %s", where, err);
if (err)
LocalFree(err);
php_win32_error_msg_free(err);
php_com_throw_exception(hr, buf);
ZVAL_NULL(object);
return;
@ -232,8 +230,7 @@ PHP_FUNCTION(com_dotnet_create_instance)
char buf[1024];
char *err = php_win32_error_to_msg(hr);
snprintf(buf, sizeof(buf), "Failed to re-init .Net domain [%s] %s", where, err);
if (err)
LocalFree(err);
php_win32_error_msg_free(err);
php_com_throw_exception(hr, buf);
ZVAL_NULL(object);
return;
@ -315,9 +312,7 @@ PHP_FUNCTION(com_dotnet_create_instance)
char buf[1024];
char *err = php_win32_error_to_msg(hr);
snprintf(buf, sizeof(buf), "Failed to instantiate .Net object [%s] [0x%08x] %s", where, hr, err);
if (err && err[0]) {
LocalFree(err);
}
php_win32_error_msg_free(err);
php_com_throw_exception(hr, buf);
return;
}

View File

@ -40,7 +40,7 @@ void php_com_throw_exception(HRESULT code, char *message)
zend_throw_exception(php_com_exception_class_entry, message, (zend_long)code);
#endif
if (free_msg) {
LocalFree(message);
php_win32_error_msg_free(message);
}
}

View File

@ -63,7 +63,7 @@ PHP_COM_DOTNET_API OLECHAR *php_com_string_to_olestring(char *string, size_t str
php_error_docref(NULL, E_WARNING,
"Could not convert string to unicode: `%s'", msg);
LocalFree(msg);
php_win32_error_msg_free(msg);
}
return olestring;
@ -94,7 +94,7 @@ PHP_COM_DOTNET_API char *php_com_olestring_to_string(OLECHAR *olestring, size_t
php_error_docref(NULL, E_WARNING,
"Could not convert string from unicode: `%s'", msg);
LocalFree(msg);
php_win32_error_msg_free(msg);
}
if (string_len) {

View File

@ -490,7 +490,7 @@ PHP_FUNCTION(com_variant_create_instance)
werr = php_win32_error_to_msg(res);
spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
LocalFree(werr);
php_win32_error_msg_free(werr);
php_com_throw_exception(res, msg);
efree(msg);
@ -1078,7 +1078,7 @@ PHP_FUNCTION(variant_set_type)
werr = php_win32_error_to_msg(res);
spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
LocalFree(werr);
php_win32_error_msg_free(werr);
php_com_throw_exception(res, msg);
efree(msg);
@ -1112,7 +1112,7 @@ PHP_FUNCTION(variant_cast)
werr = php_win32_error_to_msg(res);
spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
LocalFree(werr);
php_win32_error_msg_free(werr);
php_com_throw_exception(res, msg);
efree(msg);

View File

@ -23,6 +23,7 @@
#include "zend_shared_alloc.h"
#include "zend_accelerator_util_funcs.h"
#include "tsrm_win32.h"
#include "win32/winutil.h"
#include <winbase.h>
#include <process.h>
#include <LMCONS.H>
@ -40,25 +41,13 @@ static void *mapping_base;
static void zend_win_error_message(int type, char *msg, int err)
{
LPVOID lpMsgBuf;
HANDLE h;
char *ev_msgs[2];
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
char *buf = php_win32_error_to_msg(err);
h = RegisterEventSource(NULL, TEXT(ACCEL_EVENT_SOURCE));
ev_msgs[0] = msg;
ev_msgs[1] = lpMsgBuf;
ev_msgs[1] = buf;
ReportEvent(h, // event log handle
EVENTLOG_ERROR_TYPE, // event type
0, // category zero
@ -70,9 +59,9 @@ static void zend_win_error_message(int type, char *msg, int err)
NULL); // pointer to data
DeregisterEventSource(h);
LocalFree( lpMsgBuf );
zend_accel_error(type, "%s", msg);
php_win32_error_msg_free(buf);
}
static char *create_name_with_username(char *name)

View File

@ -637,7 +637,9 @@ static int php_openssl_win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx,
OPENSSL_free(der_buf);
if (cert_ctx == NULL) {
php_error_docref(NULL, E_WARNING, "Error creating certificate context: %s", php_win_err());
char *err = php_win_err();
php_error_docref(NULL, E_WARNING, "Error creating certificate context: %s", err);
php_win_err_free(err);
RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
}
}
@ -659,7 +661,9 @@ static int php_openssl_win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx,
chain_flags = CERT_CHAIN_CACHE_END_CERT | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
if (!CertGetCertificateChain(NULL, cert_ctx, NULL, NULL, &chain_params, chain_flags, NULL, &cert_chain_ctx)) {
php_error_docref(NULL, E_WARNING, "Error getting certificate chain: %s", php_win_err());
char *err = php_win_err();
php_error_docref(NULL, E_WARNING, "Error getting certificate chain: %s", err);
php_win_err_free(err);
CertFreeCertificateContext(cert_ctx);
RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
}
@ -743,7 +747,9 @@ static int php_openssl_win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx,
CertFreeCertificateContext(cert_ctx);
if (!verify_result) {
php_error_docref(NULL, E_WARNING, "Error verifying certificate chain policy: %s", php_win_err());
char *err = php_win_err();
php_error_docref(NULL, E_WARNING, "Error verifying certificate chain policy: %s", err);
php_win_err_free(err);
RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
}

View File

@ -37,6 +37,7 @@
# include <Ws2tcpip.h>
# include "php_sockets.h"
# include <win32/sockets.h>
# include <win32/winutil.h>
#else
# include <sys/types.h>
# include <sys/socket.h>
@ -649,12 +650,10 @@ char *sockets_strerror(int error) /* {{{ */
}
#else
{
LPTSTR tmp = NULL;
char *tmp = php_win32_error_to_msg(error);
buf = NULL;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &tmp, 0, NULL)
) {
if (tmp[0]) {
if (SOCKETS_G(strerror_buf)) {
efree(SOCKETS_G(strerror_buf));
}
@ -2822,22 +2821,16 @@ PHP_FUNCTION(socket_wsaprotocol_info_export)
if (SOCKET_ERROR == WSADuplicateSocket(socket->bsd_socket, (DWORD)target_pid, &wi)) {
DWORD err = WSAGetLastError();
LPSTR buf = NULL;
char *buf = php_win32_error_to_msg(err);
if (!FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&buf,
0, NULL)) {
if (!buf[0]) {
php_error_docref(NULL, E_WARNING, "Unable to export WSA protocol info [0x%08lx]", err);
} else {
php_error_docref(NULL, E_WARNING, "Unable to export WSA protocol info [0x%08lx]: %s", err, buf);
}
php_win32_error_msg_free(buf);
RETURN_FALSE;
}
@ -2900,22 +2893,16 @@ PHP_FUNCTION(socket_wsaprotocol_info_import)
sock = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &wi, 0, 0);
if (INVALID_SOCKET == sock) {
DWORD err = WSAGetLastError();
LPSTR buf = NULL;
char *buf = php_win32_error_to_msg(err);
if (!FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&buf,
0, NULL)) {
if (!buf[0]) {
php_error_docref(NULL, E_WARNING, "Unable to import WSA protocol info [0x%08lx]", err);
} else {
php_error_docref(NULL, E_WARNING, "Unable to import WSA protocol info [0x%08lx]: %s", err, buf);
}
php_win32_error_msg_free(buf);
RETURN_FALSE;
}

View File

@ -88,7 +88,7 @@ PHPAPI void *php_load_shlib(char *path, char **errp)
if (err && (*err)) {
size_t i = strlen(err);
(*errp)=estrdup(err);
LocalFree(err);
php_win32_error_msg_free(err);
while (i > 0 && isspace((*errp)[i-1])) { (*errp)[i-1] = '\0'; i--; }
} else {
(*errp) = estrdup("<No message>");

View File

@ -564,7 +564,9 @@ PHP_FUNCTION(proc_nice)
php_ignore_value(nice(pri));
if (errno) {
#ifdef PHP_WIN32
php_error_docref(NULL, E_WARNING, "%s", php_win_err());
char *err = php_win_err();
php_error_docref(NULL, E_WARNING, "%s", err);
php_win_err_free(err);
#else
php_error_docref(NULL, E_WARNING, "Only a super user may attempt to increase the priority of a process");
#endif

View File

@ -114,7 +114,9 @@ static int php_disk_total_space(char *path, double *space) /* {{{ */
PHP_WIN32_IOUTIL_INIT_W(path)
if (GetDiskFreeSpaceExW(pathw, &FreeBytesAvailableToCaller, &TotalNumberOfBytes, &TotalNumberOfFreeBytes) == 0) {
php_error_docref(NULL, E_WARNING, "%s", php_win_err());
char *err = php_win_err();
php_error_docref(NULL, E_WARNING, "%s", err);
php_win_err_free(err);
PHP_WIN32_IOUTIL_CLEANUP_W()
return FAILURE;
}
@ -208,7 +210,9 @@ static int php_disk_free_space(char *path, double *space) /* {{{ */
PHP_WIN32_IOUTIL_INIT_W(path)
if (GetDiskFreeSpaceExW(pathw, &FreeBytesAvailableToCaller, &TotalNumberOfBytes, &TotalNumberOfFreeBytes) == 0) {
php_error_docref(NULL, E_WARNING, "%s", php_win_err());
char *err = php_win_err();
php_error_docref(NULL, E_WARNING, "%s", err);
php_win_err_free(err);
PHP_WIN32_IOUTIL_CLEANUP_W()
return FAILURE;
}

View File

@ -1,4 +1,4 @@
/* Generated by re2c 1.0.1 */
/* Generated by re2c 1.0.3 */
#line 1 "ext/standard/var_unserializer.re"
/*
+----------------------------------------------------------------------+

View File

@ -1162,24 +1162,18 @@ PHPAPI ZEND_COLD void php_error_docref2(const char *docref, const char *param1,
/* }}} */
#ifdef PHP_WIN32
#define PHP_WIN32_ERROR_MSG_BUFFER_SIZE 512
PHPAPI ZEND_COLD void php_win32_docref2_from_error(DWORD error, const char *param1, const char *param2) {
if (error == 0) {
php_error_docref2(NULL, param1, param2, E_WARNING, "%s", strerror(errno));
} else {
char buf[PHP_WIN32_ERROR_MSG_BUFFER_SIZE + 1];
size_t buf_len;
char *buf = php_win32_error_to_msg(error);
size_t buf_len;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, buf, PHP_WIN32_ERROR_MSG_BUFFER_SIZE, NULL);
buf_len = strlen(buf);
if (buf_len >= 2) {
buf[buf_len - 1] = '\0';
buf[buf_len - 2] = '\0';
}
php_error_docref2(NULL, param1, param2, E_WARNING, "%s (code: %lu)", (char *)buf, error);
buf_len = strlen(buf);
if (buf_len >= 2) {
buf[buf_len - 1] = '\0';
buf[buf_len - 2] = '\0';
}
php_error_docref2(NULL, param1, param2, E_WARNING, "%s (code: %lu)", buf, error);
php_win32_error_msg_free(buf);
}
#undef PHP_WIN32_ERROR_MSG_BUFFER_SIZE
#endif
/* {{{ php_html_puts */

View File

@ -28,6 +28,7 @@
#ifdef PHP_WIN32
# include <Ws2tcpip.h>
# include "win32/inet.h"
# include "win32/winutil.h"
# define O_RDONLY _O_RDONLY
# include "win32/param.h"
#else
@ -1020,20 +1021,8 @@ PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize)
}
return buf;
#else
char *sysbuf;
int free_it = 1;
if (!FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&sysbuf,
0,
NULL)) {
free_it = 0;
char *sysbuf = php_win32_error_to_msg(err);
if (!sysbuf[0]) {
sysbuf = "Unknown Error";
}
@ -1044,9 +1033,7 @@ PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize)
buf[bufsize?(bufsize-1):0] = 0;
}
if (free_it) {
LocalFree(sysbuf);
}
php_win32_error_msg_free(sysbuf);
return buf;
#endif
@ -1063,28 +1050,15 @@ PHPAPI zend_string *php_socket_error_str(long err)
return zend_string_init(errstr, strlen(errstr), 0);
#else
zend_string *ret;
char *sysbuf;
int free_it = 1;
if (!FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&sysbuf,
0,
NULL)) {
free_it = 0;
char *sysbuf = php_win32_error_to_msg(err);
if (!sysbuf[0]) {
sysbuf = "Unknown Error";
}
ret = zend_string_init(sysbuf, strlen(sysbuf), 0);
if (free_it) {
LocalFree(sysbuf);
}
php_win32_error_msg_free(sysbuf);
return ret;
#endif

View File

@ -29,6 +29,7 @@
#include "php_scandir.h"
#ifdef PHP_WIN32
#include "win32/php_registry.h"
#include "win32/winutil.h"
#endif
#if HAVE_SCANDIR && HAVE_ALPHASORT && HAVE_DIRENT_H

View File

@ -2149,6 +2149,7 @@ consult the installation file that came with this distribution, or visit \n\
char *err_text = php_win32_error_to_msg(err);
fprintf(stderr, "unable to get current command line: [0x%08lx]: %s\n", err, err_text);
php_win32_error_msg_free(err_text);
goto parent_out;
}
@ -2167,6 +2168,8 @@ consult the installation file that came with this distribution, or visit \n\
fprintf(stderr, "unable to create job object: [0x%08lx]: %s\n", err, err_text);
php_win32_error_msg_free(err_text);
goto parent_out;
}
@ -2176,6 +2179,7 @@ consult the installation file that came with this distribution, or visit \n\
char *err_text = php_win32_error_to_msg(err);
fprintf(stderr, "unable to configure job object: [0x%08lx]: %s\n", err, err_text);
php_win32_error_msg_free(err_text);
}
while (parent) {
@ -2216,6 +2220,7 @@ consult the installation file that came with this distribution, or visit \n\
char *err_text = php_win32_error_to_msg(err);
fprintf(stderr, "unable to assign child process to job object: [0x%08lx]: %s\n", err, err_text);
php_win32_error_msg_free(err_text);
}
CloseHandle(pi.hThread);
} else {
@ -2225,6 +2230,7 @@ consult the installation file that came with this distribution, or visit \n\
kid_cgi_ps[i] = NULL;
fprintf(stderr, "unable to spawn: [0x%08lx]: %s\n", err, err_text);
php_win32_error_msg_free(err_text);
}
}

View File

@ -1311,7 +1311,7 @@ PHPDBG_API const char *phpdbg_load_module_or_extension(char **path, char **name)
char *err = GET_DL_ERROR();
if (err && err[0]) {
phpdbg_error("dl", "type=\"unknown\"", "%s", err);
LocalFree(err);
php_win32_error_msg_free(err);
} else {
phpdbg_error("dl", "type=\"unknown\"", "Unknown reason");
}

View File

@ -19,19 +19,36 @@
#include "php.h"
#include "winutil.h"
#include "codepage.h"
#include <bcrypt.h>
#include <lmcons.h>
PHP_WINUTIL_API char *php_win32_error_to_msg(HRESULT error)
{/*{{{*/
char *buf = NULL;
wchar_t *bufw = NULL;
char *buf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, 0, NULL
DWORD ret = FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&bufw, 0, NULL
);
return (buf ? (char *) buf : "");
if (!ret || !bufw) {
return "";
}
buf = php_win32_cp_conv_w_to_any(bufw, ret, PHP_WIN32_CP_IGNORE_LEN_P);
LocalFree(bufw);
return (buf ? buf : "");
}/*}}}*/
PHP_WINUTIL_API void php_win32_error_msg_free(char *msg)
{/*{{{*/
if (msg && msg[0]) {
free(msg);
}
}/*}}}*/
int php_win32_check_trailing_space(const char * path, const size_t path_len)

View File

@ -26,8 +26,10 @@
#endif
PHP_WINUTIL_API char *php_win32_error_to_msg(HRESULT error);
PHP_WINUTIL_API void php_win32_error_msg_free(char *msg);
#define php_win_err() php_win32_error_to_msg(GetLastError())
#define php_win_err_free(err) php_win32_error_msg_free(err)
int php_win32_check_trailing_space(const char * path, const size_t path_len);
PHP_WINUTIL_API int php_win32_get_random_bytes(unsigned char *buf, size_t size);
#ifdef PHP_EXPORTS