1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Check linker compatibility directly from HMODULE

Checking the linker compatibility with extranous `ImageLoad()` calls is
possible, but unnecessary, since the modules are either already loaded
or loaded shortly afterwards, so that we can get the required
information directly from the module handles.  And actually, doing
`ImageLoad()` as well as `LoadLibrary()` leaves a tiny room for a race
condition, because both functions will lookup the module in the search
path, so there is no *guarantee* that both are dealing with the same
module.  Dropping the `ImageLoad()` calls also has the advantage to no
longer face the issue reported in bug #79557.  A very minor additional
advantage is that we no longer have to link against Imagehlp.dll.

Furthermore, there is no need to check for CRT compatibility multiple
times, so we can simplify the signature of `php_win32_crt_compatible`,
and at the same time clean up main.c a bit.

These changes require to change the signature of the exported
`php_win32_image_compatible` and `php_win32_crt_compatible` functions,
which now expect a `HMODULE` and nothing, respectively, instead of the
module name.
This commit is contained in:
Christoph M. Becker
2020-08-05 08:59:41 +02:00
parent 6fa2493789
commit 3e33e1e86d
8 changed files with 49 additions and 54 deletions

View File

@@ -373,6 +373,10 @@ PHP 8.0 INTERNALS UPGRADE NOTES
- zend_get_op_array_extension_handle()
10. Argument zend_extension to const char* in Zend Engine 4.0:
- zend_get_resource_handle()
11. Argument const char * to HMODULE in Zend Engine 4.0:
- php_win32_image_compatible()
12. const char * argument dropped in Zend Engine 4.0:
- php_win32_crt_compatible()
u. Instead of overwriting zend_error_cb extensions with debugging, monitoring
use-cases catching Errors/Exceptions are strongly encouraged to use

View File

@@ -41,6 +41,13 @@ zend_result zend_load_extension(const char *path)
#endif
return FAILURE;
}
#ifdef ZEND_WIN32
char *err;
if (!php_win32_image_compatible(handle, &err)) {
zend_error(E_CORE_WARNING, err);
return FAILURE;
}
#endif
return zend_load_extension_handle(handle, path);
#else
fprintf(stderr, "Extensions are not supported on this platform.\n");

View File

@@ -161,19 +161,17 @@ PHPAPI int php_load_extension(const char *filename, int type, int start_now)
efree(orig_libpath);
efree(err1);
}
efree(libpath);
#ifdef PHP_WIN32
if (!php_win32_image_compatible(libpath, &err1)) {
if (!php_win32_image_compatible(handle, &err1)) {
php_error_docref(NULL, error_type, err1);
efree(err1);
efree(libpath);
DL_UNLOAD(handle);
return FAILURE;
}
#endif
efree(libpath);
get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module");
/* Some OS prepend _ to symbol names while their dynamic linker

View File

@@ -2055,21 +2055,12 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
#endif
#ifdef PHP_WIN32
# if PHP_LINKER_MAJOR == 14
/* Extend for other CRT if needed. */
# if PHP_DEBUG
# define PHP_VCRUNTIME "vcruntime140d.dll"
# else
# define PHP_VCRUNTIME "vcruntime140.dll"
# endif
char *img_err;
if (!php_win32_crt_compatible(PHP_VCRUNTIME, &img_err)) {
if (!php_win32_crt_compatible(&img_err)) {
php_error(E_CORE_WARNING, img_err);
efree(img_err);
return FAILURE;
}
# undef PHP_VCRUNTIME
# endif
/* start up winsock services */
if (WSAStartup(wVersionRequested, &wsaData) != 0) {

View File

@@ -331,13 +331,6 @@ static void php_load_zend_extension_cb(void *arg)
#endif
if (IS_ABSOLUTE_PATH(filename, length)) {
#ifdef PHP_WIN32
char *err;
if (!php_win32_image_compatible(filename, &err)) {
php_error(E_CORE_WARNING, err);
return;
}
#endif
zend_load_extension(filename);
} else {
DL_HANDLE handle;
@@ -381,13 +374,13 @@ static void php_load_zend_extension_cb(void *arg)
efree(orig_libpath);
efree(err1);
efree(libpath);
}
#ifdef PHP_WIN32
if (!php_win32_image_compatible(libpath, &err1)) {
if (!php_win32_image_compatible(handle, &err1)) {
php_error(E_CORE_WARNING, err1);
efree(err1);
efree(libpath);
DL_UNLOAD(handle);
return;
}

View File

@@ -3401,7 +3401,7 @@ function toolset_setup_common_ldlags()
function toolset_setup_common_libs()
{
// urlmon.lib ole32.lib oleaut32.lib uuid.lib gdi32.lib winspool.lib comdlg32.lib
DEFINE("LIBS", "kernel32.lib ole32.lib user32.lib advapi32.lib shell32.lib ws2_32.lib Dnsapi.lib psapi.lib bcrypt.lib imagehlp.lib");
DEFINE("LIBS", "kernel32.lib ole32.lib user32.lib advapi32.lib shell32.lib ws2_32.lib Dnsapi.lib psapi.lib bcrypt.lib");
}
function toolset_setup_build_mode()

View File

@@ -20,7 +20,6 @@
#include "codepage.h"
#include <bcrypt.h>
#include <lmcons.h>
#include <imagehlp.h>
PHP_WINUTIL_API char *php_win32_error_to_msg(HRESULT error)
@@ -436,26 +435,13 @@ PHP_WINUTIL_API char *php_win32_get_username(void)
return uname;
}/*}}}*/
static zend_always_inline BOOL is_compatible(const char *name, BOOL is_smaller, char *format, char **err)
static zend_always_inline BOOL is_compatible(HMODULE handle, BOOL is_smaller, char *format, char **err)
{/*{{{*/
/* work around ImageLoad() issue */
const char *name_stripped = name;
if (name[0] == '.' && IS_SLASH(name[1])) {
name_stripped += 2;
}
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) handle;
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((char *) dosHeader + dosHeader->e_lfanew);
PLOADED_IMAGE img = ImageLoad(name_stripped, NULL);
if (!img) {
DWORD _err = GetLastError();
char *err_txt = php_win32_error_to_msg(_err);
spprintf(err, 0, "Failed to load %s, %s", name, err_txt);
free(err_txt);
return FALSE;
}
DWORD major = img->FileHeader->OptionalHeader.MajorLinkerVersion;
DWORD minor = img->FileHeader->OptionalHeader.MinorLinkerVersion;
DWORD major = pNTHeader->OptionalHeader.MajorLinkerVersion;
DWORD minor = pNTHeader->OptionalHeader.MinorLinkerVersion;
#if PHP_LINKER_MAJOR == 14
/* VS 2015, 2017 and 2019 are binary compatible, but only forward compatible.
@@ -474,23 +460,39 @@ static zend_always_inline BOOL is_compatible(const char *name, BOOL is_smaller,
if (PHP_LINKER_MAJOR != major)
#endif
{
spprintf(err, 0, format, name, major, minor, PHP_LINKER_MAJOR, PHP_LINKER_MINOR);
ImageUnload(img);
char buf[MAX_PATH];
if (GetModuleFileName(handle, buf, sizeof(buf)) != 0) {
spprintf(err, 0, format, buf, major, minor, PHP_LINKER_MAJOR, PHP_LINKER_MINOR);
} else {
spprintf(err, 0, "Can't retrieve the module name (error %u)", GetLastError());
}
return FALSE;
}
ImageUnload(img);
return TRUE;
}/*}}}*/
PHP_WINUTIL_API BOOL php_win32_image_compatible(const char *name, char **err)
PHP_WINUTIL_API BOOL php_win32_image_compatible(HMODULE handle, char **err)
{/*{{{*/
return is_compatible(name, TRUE, "Can't load module '%s' as it's linked with %u.%u, but the core is linked with %d.%d", err);
return is_compatible(handle, TRUE, "Can't load module '%s' as it's linked with %u.%u, but the core is linked with %d.%d", err);
}/*}}}*/
/* Expect a CRT name DLL. */
PHP_WINUTIL_API BOOL php_win32_crt_compatible(const char *name, char **err)
/* Expect a CRT module handle */
PHP_WINUTIL_API BOOL php_win32_crt_compatible(char **err)
{/*{{{*/
return is_compatible(name, FALSE, "'%s' %u.%u is not compatible with this PHP build linked with %d.%d", err);
#if PHP_LINKER_MAJOR == 14
/* Extend for other CRT if needed. */
# if PHP_DEBUG
const char *crt_name = "vcruntime140d.dll";
# else
const char *crt_name = "vcruntime140.dll";
# endif
HMODULE handle = GetModuleHandle(crt_name);
if (handle == NULL) {
spprintf(err, 0, "Can't get handle of module %s (error %u)", crt_name, GetLastError());
return FALSE;
}
return is_compatible(handle, FALSE, "'%s' %u.%u is not compatible with this PHP build linked with %d.%d", err);
#endif
return TRUE;
}/*}}}*/

View File

@@ -53,7 +53,7 @@ PHP_WINUTIL_API int php_win32_code_to_errno(unsigned long w32Err);
PHP_WINUTIL_API char *php_win32_get_username(void);
PHP_WINUTIL_API BOOL php_win32_image_compatible(const char *img, char **err);
PHP_WINUTIL_API BOOL php_win32_crt_compatible(const char *img, char **err);
PHP_WINUTIL_API BOOL php_win32_image_compatible(HMODULE handle, char **err);
PHP_WINUTIL_API BOOL php_win32_crt_compatible(char **err);
#endif