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;
 }