1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Add automatic type-checking to GET_WINDOWS_FUNCTION.

This gives me an extra safety-check against having mistyped one of the
function prototypes that we load at run time from DLLs: we verify that
the typedef we defined based on the prototype in our source code
matches the type of the real function as declared in the Windows
headers.

This was an idea I had while adding a pile of further functions using
this mechanism. It didn't catch any errors (either in the new
functions or in the existing collection), but that's no reason not to
keep it anyway now that I've thought of it!

In VS2015, this automated type-check works for most functions, but a
couple manage to break it. SetCurrentProcessExplicitAppUserModelID in
winjump.c can't be type-checked, because including <shobjidl.h> where
that function is declared would also bring in a load of other stuff
that conflicts with the painful manual COM declarations in winjump.c.
(That stuff could probably be removed now we're on an up-to-date
Visual Studio, on the other hand, but that's a separate chore.) And
gai_strerror, used in winnet.c, does _have_ an implementation in a
DLL, but the header files like to provide an inline version with a
different calling convention, which defeats this error-checking trick.
And in the older VS2003 that we still precautionarily build with,
several more type-checks have to be #ifdeffed out because the
functions they check against just aren't there at all.
This commit is contained in:
Simon Tatham 2017-04-11 18:56:55 +01:00
parent 3ff3be3882
commit 49fb598b0e
6 changed files with 55 additions and 10 deletions

View File

@ -79,7 +79,12 @@ struct ssh_gss_liblist *ssh_gss_setup(Conf *conf)
if (!kernel32_module) {
kernel32_module = load_system32_dll("kernel32.dll");
}
#if defined _MSC_VER && _MSC_VER < 1900
/* Omit the type-check because older MSVCs don't have this function */
GET_WINDOWS_FUNCTION_NO_TYPECHECK(kernel32_module, AddDllDirectory);
#else
GET_WINDOWS_FUNCTION(kernel32_module, AddDllDirectory);
#endif
list->libraries = snewn(3, struct ssh_gss_library);
list->nlibraries = 0;

View File

@ -282,7 +282,15 @@ static char *sk_handle_peer_info(Socket s)
if (!kernel32_module) {
kernel32_module = load_system32_dll("kernel32.dll");
GET_WINDOWS_FUNCTION(kernel32_module, GetNamedPipeClientProcessId);
#if defined _MSC_VER && _MSC_VER < 1900
/* For older Visual Studio, this function isn't available in
* the header files to type-check */
GET_WINDOWS_FUNCTION_NO_TYPECHECK(
kernel32_module, GetNamedPipeClientProcessId);
#else
GET_WINDOWS_FUNCTION(
kernel32_module, GetNamedPipeClientProcessId);
#endif
}
/*

View File

@ -728,7 +728,13 @@ BOOL set_explicit_app_user_model_id()
if (!shell32_module)
{
shell32_module = load_system32_dll("Shell32.dll");
GET_WINDOWS_FUNCTION(shell32_module, SetCurrentProcessExplicitAppUserModelID);
/*
* We can't typecheck this function here, because it's defined
* in <shobjidl.h>, which we're not including due to clashes
* with all the manual-COM machinery above.
*/
GET_WINDOWS_FUNCTION_NO_TYPECHECK(
shell32_module, SetCurrentProcessExplicitAppUserModelID);
}
if (p_SetCurrentProcessExplicitAppUserModelID)

View File

@ -177,7 +177,14 @@ void dll_hijacking_protection(void)
if (!kernel32_module) {
kernel32_module = load_system32_dll("kernel32.dll");
#if defined _MSC_VER && _MSC_VER < 1900
/* For older Visual Studio, this function isn't available in
* the header files to type-check */
GET_WINDOWS_FUNCTION_NO_TYPECHECK(
kernel32_module, SetDefaultDllDirectories);
#else
GET_WINDOWS_FUNCTION(kernel32_module, SetDefaultDllDirectories);
#endif
}
if (p_SetDefaultDllDirectories) {

View File

@ -268,7 +268,10 @@ void sk_init(void)
GET_WINDOWS_FUNCTION(winsock_module, getaddrinfo);
GET_WINDOWS_FUNCTION(winsock_module, freeaddrinfo);
GET_WINDOWS_FUNCTION(winsock_module, getnameinfo);
GET_WINDOWS_FUNCTION(winsock_module, gai_strerror);
/* This function would fail its type-check if we did one,
* because the VS header file provides an inline definition
* which is __cdecl instead of WINAPI. */
GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gai_strerror);
} else {
/* Fall back to wship6.dll for Windows 2000 */
wship6_module = load_system32_dll("wship6.dll");
@ -279,7 +282,8 @@ void sk_init(void)
GET_WINDOWS_FUNCTION(wship6_module, getaddrinfo);
GET_WINDOWS_FUNCTION(wship6_module, freeaddrinfo);
GET_WINDOWS_FUNCTION(wship6_module, getnameinfo);
GET_WINDOWS_FUNCTION(wship6_module, gai_strerror);
/* See comment above about type check */
GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gai_strerror);
} else {
#ifdef NET_SETUP_DIAGNOSTICS
logevent(NULL, "No IPv6 support detected");
@ -310,7 +314,13 @@ void sk_init(void)
GET_WINDOWS_FUNCTION(winsock_module, getservbyname);
GET_WINDOWS_FUNCTION(winsock_module, inet_addr);
GET_WINDOWS_FUNCTION(winsock_module, inet_ntoa);
#if defined _MSC_VER && _MSC_VER < 1900
/* Older Visual Studio doesn't know about this function at all, so
* can't type-check it */
GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, inet_ntop);
#else
GET_WINDOWS_FUNCTION(winsock_module, inet_ntop);
#endif
GET_WINDOWS_FUNCTION(winsock_module, connect);
GET_WINDOWS_FUNCTION(winsock_module, bind);
GET_WINDOWS_FUNCTION(winsock_module, setsockopt);

View File

@ -128,15 +128,24 @@ struct FontSpec *fontspec_new(const char *name,
*
* (DECL_WINDOWS_FUNCTION works with both these variants.)
*/
#define DECL_WINDOWS_FUNCTION(linkage, rettype, name, params) \
typedef rettype (WINAPI *t_##name) params; \
#define TYPECHECK(to_check, to_return) \
(sizeof(to_check) ? to_return : to_return)
#define DECL_WINDOWS_FUNCTION(linkage, rettype, name, params) \
typedef rettype (WINAPI *t_##name) params; \
linkage t_##name p_##name
#define STR1(x) #x
#define STR(x) STR1(x)
#define GET_WINDOWS_FUNCTION_PP(module, name) \
(p_##name = module ? (t_##name) GetProcAddress(module, STR(name)) : NULL)
#define GET_WINDOWS_FUNCTION(module, name) \
(p_##name = module ? (t_##name) GetProcAddress(module, #name) : NULL)
#define GET_WINDOWS_FUNCTION_PP(module, name) \
TYPECHECK((t_##name)NULL == name, \
(p_##name = module ? \
(t_##name) GetProcAddress(module, STR(name)) : NULL))
#define GET_WINDOWS_FUNCTION(module, name) \
TYPECHECK((t_##name)NULL == name, \
(p_##name = module ? \
(t_##name) GetProcAddress(module, #name) : NULL))
#define GET_WINDOWS_FUNCTION_NO_TYPECHECK(module, name) \
(p_##name = module ? \
(t_##name) GetProcAddress(module, #name) : NULL)
/*
* Global variables. Most modules declare these `extern', but