crt: tests: update t_pow This test has a few issues: 1. It calls `atoi`, but does not include stdlib.h. 2. typedef for `pow` is missing `__cdecl`; this would result in compilation error on i386 as all CRT functions have __cdecl calling convention. 3. `set_pow_msvcrt` does not check whether it was able to load `msvcrt.dll` and whether pointer returned by `GetProcAddress` is non-NULL; either could result in memory access violation. Also note that msvcrt.dll is not available on Windows NT 3.1 and Windows 95. In order to fix these: 1. Include stdlib.h. 2. Add `__cdecl` to typedef for `pow`. 3. Instead of loading msvcrt.dll with `LoadLibrary`, call `GetModuleHandle` to obtain handle of CRT the test is linked against and check if it is non-NULL. If returned handle is non-NULL, check whether pointer returned by `GetProcAddress` is non-NULL as well. 4. Test CRT's `pow` only if we successfully obtained its address; otherwise simply skip this subtest. Add t_pow to testcases/Makefile.am. Signed-off-by: Kirill Makurin <maiddaisuki@outlook.com> Signed-off-by: LIU Hao <lh_mouse@126.com>
diff --git a/mingw-w64-crt/testcases/Makefile.am b/mingw-w64-crt/testcases/Makefile.am index 86b3b0c..a384637 100644 --- a/mingw-w64-crt/testcases/Makefile.am +++ b/mingw-w64-crt/testcases/Makefile.am
@@ -55,6 +55,7 @@ t_mbrtowc \ t_mbsrtowcs \ t_nullptrexception \ + t_pow \ t_printf \ t_printf_g_width \ t_readdir \
diff --git a/mingw-w64-crt/testcases/t_pow.c b/mingw-w64-crt/testcases/t_pow.c index 6027fea..1bf7aee 100644 --- a/mingw-w64-crt/testcases/t_pow.c +++ b/mingw-w64-crt/testcases/t_pow.c
@@ -1,20 +1,63 @@ #include <math.h> #include <stdio.h> +#include <stdlib.h> #define WIN32_LEAN_AND_MEAN #include <windows.h> -typedef double (*my_pow)(double, double); +#ifndef __MSVCRT_VERSION__ +#define __MSVCRT_VERSION__ 0x0000 +#endif +#if defined(_UCRT) || __MSVCRT_VERSION__ >= 0x0E00 +#define CRT_FILENAME "ucrtbase.dll" +#elif __MSVCRT_VERSION__ >= 0x0C00 +#define CRT_FILENAME "msvcr120.dll" +#elif __MSVCRT_VERSION__ >= 0x0B00 +#define CRT_FILENAME "msvcr110.dll" +#elif __MSVCRT_VERSION__ >= 0x0A00 +#define CRT_FILENAME "msvcr100.dll" +#elif __MSVCRT_VERSION__ >= 0x0900 +#define CRT_FILENAME "msvcr90.dll" +#elif __MSVCRT_VERSION__ >= 0x0800 +#define CRT_FILENAME "msvcr80.dll" +#elif __MSVCRT_VERSION__ >= 0x0710 +#define CRT_FILENAME "msvcr71.dll" +#elif __MSVCRT_VERSION__ >= 0x0700 +#define CRT_FILENAME "msvcr70.dll" +#elif __MSVCRT_VERSION__ >= 0x0410 +#define CRT_FILENAME "msvcrt.dll" +#elif __MSVCRT_VERSION__ >= 0x0400 +#define CRT_FILENAME "msvcrt40.dll" +#elif __MSVCRT_VERSION__ >= 0x0200 +#define CRT_FILENAME "msvcrt20.dll" +#elif __MSVCRT_VERSION__ >= 0x0100 +#define CRT_FILENAME "msvcrt10.dll" +#else +#define CRT_FILENAME "crtdll.dll" +#endif + +/* All CRT functions have __cdecl calling convention */ +typedef double (__cdecl *my_pow)(double, double); + +/* The `pow` implementation to test */ static my_pow fpow = pow; -static void set_pow_msvcrt(void) +/* Set `fpow` to CRT's `pow` */ +static void set_pow_crt(void) { - HMODULE hMod = LoadLibrary ("msvcrt.dll"); - fpow = (my_pow) GetProcAddress (hMod, "pow"); + my_pow ptr_pow = NULL; + HMODULE hMod = GetModuleHandleA (CRT_FILENAME); + + if (hMod != NULL) { + ptr_pow = (my_pow) (UINT_PTR) GetProcAddress (hMod, "pow"); + } + + fpow = ptr_pow; } -static __attribute__((noinline)) double pow_by_log_exp (double x, double y) +/* `pow` implementation using `exp` and `log` */ +static __attribute__((noinline)) double __cdecl pow_by_log_exp (double x, double y) { /* pow(x, n) = exp(n * log(x)) */ if (x < 0.0) @@ -50,22 +93,37 @@ int main (int argc, char **argv) { int e = (argc > 1 ? atoi(argv[1]) : 20000000); + + /** + * Test `pow` function in libmingwex. + */ printf ("Current implementation in libmingwex: "); test (e); printf ("pow(-1.0, 2) = %g\n", (*fpow)(-1.0, 2.0)); printf ("pow(-1.0, 2.2) = %g\n", (*fpow)(-1.0, 2.2)); printf ("pow(2.0, -1) = %g\n", (*fpow)(2.0,-1.0)); - set_pow_msvcrt (); - printf ("Implementation in msvcrt.dll: "); - test (e); - printf ("pow(-1.0, 2) = %g\n", (*fpow)(-1.0, 2.0)); - printf ("pow(-1.0, 2.2) = %g\n", (*fpow)(-1.0, 2.2)); - printf ("pow(2.0, -1) = %g\n", (*fpow)(2.0,-1.0)); + + /** + * Test `pow` function in CRT. + */ + set_pow_crt (); + if (fpow != NULL) { + printf ("Implementation in "CRT_FILENAME": "); + test (e); + printf ("pow(-1.0, 2) = %g\n", (*fpow)(-1.0, 2.0)); + printf ("pow(-1.0, 2.2) = %g\n", (*fpow)(-1.0, 2.2)); + printf ("pow(2.0, -1) = %g\n", (*fpow)(2.0,-1.0)); + } + + /** + * Test `pow` implementation using `exp` and `log`. + */ fpow = pow_by_log_exp; printf ("Implementation by exp and log: "); test (e); printf ("pow(-1.0, 2) = %g\n", (*fpow)(-1.0, 2.0)); printf ("pow(-1.0, 2.2) = %g\n", (*fpow)(-1.0, 2.2)); printf ("pow(2.0, -1) = %g\n", (*fpow)(2.0,-1.0)); + return 0; }