Repository: Unidata/netcdf-c (c)

Issue:
OpenDAP hang on Mingw-w64
* Windows 10 x64
* Current version of mingw-w64
  * Available from https://www.msys2.org/wiki/MSYS2-installation
* Install netcdf-4.7.4 package (e.g. `pacman -S mingw64/mingw-w64-x86_64-netcdf`)
* Try to access an OpenDAP dataset with `ncdump`
* For example, the following command hangs until interrupted by user:
  * `ncdump -hs  https://cida.usgs.gov/thredds/dodsC/stageiv_combined`

The problem appears to be triggered by compiler optimisations. I have tested gcc-8, gcc-10 and clang-12, and the hang occurs for all of them with the default optimizations chosen by CMake. The hang does NOT occur with optimisation at `-O1` or lower. 

Looking more closely at the optimization options for gcc, I found a specific optimization that causes the problem: `-foptimize-sibling-calls`. OpenDAP appears to work correctly if the package is compiled with `-O3 -fno-optimize-sibling-calls`.

Although there seems to be a workaround, it would be better to understand the root cause of the problem, which is why I am reporting it here.

Pull request description:
Avoid redefinition of strcasecmp under mingw-w64
Fixes #2083

NetCDF defines `strcasecmp` as a preprocessor macro on Windows platforms. This is probably needed for the Microsoft compilers, but the header files used by mingw-w64 compilers define `strcasecmp` as an inline function.

If both the inline function and the macro definitions are used with gcc at high optimisation levels (specifically the flag `-foptimize-sibling-calls`, which is included by default at `-O2` or higher), the OpenDAP tests hang.

On mingw-w64, the macro `__MINGW32__` is defined in both 32-bit and 64-bit environments. If this macro is defined, the macro definition of `strcasecmp` can be disabled, which avoids the hang when running OpenDAP tests.

Patch:
diff --git a/config.h.cmake.in b/config.h.cmake.in
index 26992697c..87f473e1f 100644
--- a/config.h.cmake.in
+++ b/config.h.cmake.in
@@ -57,23 +57,6 @@ are set when opening a binary file on Windows. */
    #define _OFF_T_DEFINED
    #endif
 
-   #ifdef _WIN32
-    #ifndef strcasecmp
-      #define strcasecmp _stricmp
-    #endif
-
-    #ifndef strincasecmp
-      #define strncasecmp _strnicmp
-    #endif
-
-    #ifndef snprintf
-     #if _MSC_VER<1900
-       #define snprintf _snprintf
-     #endif
-    #endif
-   #endif
-
-
    #define strdup _strdup
    #define fdopen _fdopen
    #define write _write
@@ -678,21 +661,6 @@ with zip */
 /* Define to `unsigned long if <sys/types.h> does not define. */
 #cmakedefine uintptr_t unsigned long
 
-/* Define strcasecmp, strncasecmp, snprintf on Win32 systems. */
-#ifdef _WIN32
-    #ifndef HAVE_STRCASECMP
-	 #define strcasecmp _stricmp
-    #endif
-
-    #ifndef HAVE_STRNCASECMP
-	 #define strncasecmp _strnicmp
-    #endif
-
-    #ifndef HAVE_SNPRINTF
-	 #define snprintf _snprintf
-    #endif
-#endif
-
 #cmakedefine WORDS_BIGENDIAN
 
 #include "ncconfigure.h"
diff --git a/configure.ac b/configure.ac
index 724434ee3..001fa5ea1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1801,16 +1801,6 @@ AC_SUBST(DO_FILTER_TESTS,[$enable_filter_testing])
 AC_SUBST(HAVE_BLOSC,[$enable_blosc])
 AC_SUBST(HAVE_SZIP,[$enable_szip])
 
-# Include some specifics for netcdf on windows.
-#AH_VERBATIM([_WIN32_STRICMP],
-AH_BOTTOM(
-[/* Define strcasecmp, strncasecmp, snprintf on Win32 systems. */
-#ifdef _WIN32
-	#define strcasecmp _stricmp
-	#define strncasecmp _strnicmp
-	#define snprintf _snprintf
-#endif])
-
 # Access netcdf specific version of config.h
 AH_BOTTOM([#include "ncconfigure.h"])
 
diff --git a/include/ncconfigure.h b/include/ncconfigure.h
index 17d68aada..b58bd379b 100644
--- a/include/ncconfigure.h
+++ b/include/ncconfigure.h
@@ -62,19 +62,32 @@ extern unsigned long long int strtoull(const char*, char**, int);
 #endif
 
 #endif /*STDC*/
-#endif /*!_WIN32*/
 
-#ifdef _WIN32
+#else /*_WIN32*/
+
 #ifndef HAVE_STRLCAT
 #define strlcat(d,s,n) strcat_s((d),(n),(s))
 #endif
-#ifndef HAVE_STRCASECMP
+
+
+#ifndef __MINGW32__
+#ifndef strcasecmp
 #define strcasecmp _stricmp
 #endif
+#ifndef strncasecmp
+#define strncasecmp _strnicmp
+#endif
+#ifndef snprintf
+#if _MSC_VER<1900
+#define snprintf _snprintf
+#endif
+#endif
 #ifndef fileno
 #define fileno(f) _fileno(f)
 #endif
-#endif
+#endif /*__MINGW32__*/
+
+#endif /*_WIN32*/
 
 /* handle null arguments */
 #ifndef nulldup
diff --git a/libdispatch/ncjson.c b/libdispatch/ncjson.c
index 0759931db..e86217564 100644
--- a/libdispatch/ncjson.c
+++ b/libdispatch/ncjson.c
@@ -62,7 +62,7 @@ typedef struct NCJbuf {
 
 /**************************************************/
 
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(__MINGW32__)
 #define strdup _strdup
 #define strcasecmp _stricmp
 #else
diff --git a/libdispatch/nclist.c b/libdispatch/nclist.c
index 59454ea3a..49f0dded4 100644
--- a/libdispatch/nclist.c
+++ b/libdispatch/nclist.c
@@ -6,7 +6,7 @@
 
 #include "nclist.h"
 
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(__MINGW32__)
 #define strcasecmp _stricmp
 #endif
 
diff --git a/ncdump/nccopy.c b/ncdump/nccopy.c
index 7568266f3..a1f23e2f0 100644
--- a/ncdump/nccopy.c
+++ b/ncdump/nccopy.c
@@ -15,7 +15,6 @@
 
 #if defined(_WIN32) && !defined(__MINGW32__)
 #include "XGetopt.h"
-#define snprintf _snprintf
 #endif
 
 #ifdef HAVE_UNISTD_H
diff --git a/ncdump/ncdump.c b/ncdump/ncdump.c
index 9920a72ad..3cbfc0844 100644
--- a/ncdump/ncdump.c
+++ b/ncdump/ncdump.c
@@ -11,7 +11,6 @@ Research/Unidata. See \ref copyright file for more info.  */
 
 #if defined(_WIN32) && !defined(__MINGW32__)
 #include "XGetopt.h"
-#define snprintf _snprintf
 #endif
 
 #ifdef HAVE_UNISTD_H
diff --git a/ncdump/ncvalidator.c b/ncdump/ncvalidator.c
index 439572385..c9bf90751 100644
--- a/ncdump/ncvalidator.c
+++ b/ncdump/ncvalidator.c
@@ -76,7 +76,6 @@ THIS SOFTWARE.
 #if defined(_WIN32) && !defined(__MINGW32__)
 #include <io.h>
 #include "XGetopt.h"
-#define snprintf _snprintf
 #endif
 
 #define X_ALIGN         4
diff --git a/ncgen/ncgen.h b/ncgen/ncgen.h
index 855d39ce8..523b2d1e1 100644
--- a/ncgen/ncgen.h
+++ b/ncgen/ncgen.h
@@ -6,11 +6,7 @@
  *   $Header: /upc/share/CVS/netcdf-3/ncgen/ncgen.h,v 1.18 2010/06/01 15:34:53 ed Exp $
 *********************************************************************/
 
-#ifdef _WIN32
-#include <float.h>
-#include "isnan.h"
-#define strcasecmp _stricmp
-#endif
+#include "config.h"
 
 #ifdef USE_NETCDF4
 #define CLASSICONLY 0
diff --git a/ncgen3/main.c b/ncgen3/main.c
index 4c7777998..e8253a178 100644
--- a/ncgen3/main.c
+++ b/ncgen3/main.c
@@ -17,7 +17,6 @@
 
 #if defined(_WIN32) && !defined(__MINGW32__)
 #include "XGetopt.h"
-#define snprintf _snprintf
 #endif
 
 #include "netcdf.h"


Test patch:
diff --git a/dap4_test/dump.c b/dap4_test/dump.c
index 1c242f131..76a49a5d5 100644
--- a/dap4_test/dump.c
+++ b/dap4_test/dump.c
@@ -17,7 +17,6 @@
 
 #if defined(_WIN32) && !defined(__MINGW32__)
 #include "XGetopt.h"
-#define snprintf _snprintf
 #endif
     
 #include "netcdf.h"