From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cheng Zhao <zcbenz@gmail.com>
Date: Fri, 12 Nov 2021 17:25:37 +0900
Subject: fix: crash caused by GetHostNameW on Windows 7

Backported from https://github.com/libuv/libuv/pull/3285.

diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c
index 88602c7ee8623f16f87398cf3ffd1f71555fc1a0..5ffde08e1aed041c4da679156ed10f7e54bfc386 100644
--- a/deps/uv/src/win/util.c
+++ b/deps/uv/src/win/util.c
@@ -37,6 +37,7 @@
 #include <psapi.h>
 #include <tlhelp32.h>
 #include <windows.h>
+#include <svcguid.h>
 /* clang-format on */
 #include <userenv.h>
 #include <math.h>
@@ -56,6 +57,10 @@
 /* The number of nanoseconds in one second. */
 #define UV__NANOSEC 1000000000
 
+/* Local buffer size for WSAQUERYSETW data inside uv__gethostnamew_nt60
+   sizeof(WSAQUERYSETW) + 512 = 632 bytes to match GetHostNameW behavior */
+#define WSAQ_LOCAL_BUF_LEN (sizeof(WSAQUERYSETW) + 512)
+
 /* Max user name length, from iphlpapi.h */
 #ifndef UNLEN
 # define UNLEN 256
@@ -72,6 +77,11 @@ static CRITICAL_SECTION process_title_lock;
 /* Frequency of the high-resolution clock. */
 static uint64_t hrtime_frequency_ = 0;
 
+/* Parameters for WSAQUERYSETW inside uv__gethostnamew_nt60 */
+static GUID guid_host_name = SVCID_HOSTNAME;
+static AFPROTOCOLS af_protocols[2] = { {AF_INET, IPPROTO_UDP},
+                                       {AF_INET, IPPROTO_TCP} };
+
 
 /*
  * One-time initialization code for functionality defined in util.c.
@@ -1663,6 +1673,125 @@ int uv_os_unsetenv(const char* name) {
 }
 
 
+static int WSAAPI uv__gethostnamew_nt60(PWSTR name, int name_len) {
+  int result_len;
+  int error_code = NO_ERROR;
+
+  /* WSALookupService stuff
+   * Avoid dynamic memory allocation if possible */
+  CHAR local_buf[WSAQ_LOCAL_BUF_LEN];
+  DWORD dwlen = WSAQ_LOCAL_BUF_LEN;
+  WSAQUERYSETW* pwsaq;
+  /* hostname returned from WSALookupService stage */
+  WCHAR* result_name = NULL;
+  /* WSALookupService handle */
+  HANDLE hlookup;
+  /* Fallback to heap allocation if stack buffer is too small */
+  WSAQUERYSETW* heap_data = NULL;
+
+  /* check input */
+  if (name == NULL) {
+    error_code = WSAEFAULT;
+    goto cleanup;
+  }
+
+  /*
+   * Stage 1: Check environment variable
+   * _CLUSTER_NETWORK_NAME_ len == ComputeName(NETBIOS) len.
+   * i.e 15 characters + null.
+   * It overrides the actual hostname, so application can
+   * work when network name and computer name are different
+   */
+  result_len = GetEnvironmentVariableW(L"_CLUSTER_NETWORK_NAME_",
+                                       name,
+                                       name_len);
+  if (result_len != 0) {
+    if (result_len > name_len) {
+      error_code = WSAEFAULT;
+    }
+    goto cleanup;
+  }
+
+  /* Stage 2: Do normal lookup through WSALookupServiceLookup */
+  pwsaq = (WSAQUERYSETW*) local_buf;
+  memset(pwsaq, 0, sizeof(*pwsaq));
+  pwsaq->dwSize                  = sizeof(*pwsaq);
+  pwsaq->lpszServiceInstanceName = NULL;
+  pwsaq->lpServiceClassId        = &guid_host_name;
+  pwsaq->dwNameSpace             = NS_ALL;
+  pwsaq->lpafpProtocols          = &af_protocols[0];
+  pwsaq->dwNumberOfProtocols     = 2;
+
+  error_code = WSALookupServiceBeginW(pwsaq, LUP_RETURN_NAME, &hlookup);
+  if (error_code == NO_ERROR) {
+    /* Try stack allocation first */
+    error_code = WSALookupServiceNextW(hlookup, 0, &dwlen, pwsaq);
+    if (error_code == NO_ERROR) {
+      result_name = pwsaq->lpszServiceInstanceName;
+    } else {
+      error_code = WSAGetLastError();
+
+      if (error_code == WSAEFAULT) {
+        /* Should never happen */
+        assert(sizeof(CHAR) * dwlen >= sizeof(WSAQUERYSETW));
+
+        /* Fallback to the heap allocation */
+        heap_data = uv__malloc(sizeof(CHAR) * (size_t) dwlen);
+        if (heap_data != NULL) {
+          error_code = WSALookupServiceNextW(hlookup, 0, &dwlen, heap_data);
+          if (error_code == NO_ERROR) {
+            result_name = heap_data->lpszServiceInstanceName;
+          } else {
+            error_code = WSAGetLastError();
+          }
+        } else {
+          error_code = WSA_NOT_ENOUGH_MEMORY;
+        }
+      }
+    }
+
+    WSALookupServiceEnd(hlookup);
+
+    if (error_code != NO_ERROR) {
+      WSASetLastError(error_code);
+    }
+  }
+
+  if (result_name != NULL) {
+    size_t wlen = wcslen(result_name) + 1;
+
+    if (wlen <= (size_t) name_len) {
+      wmemcpy(name, result_name, wlen);
+    } else {
+      error_code = WSAEFAULT;
+    }
+    goto cleanup;
+  }
+
+  /* Stage 3: If WSALookupServiceLookup fails, fallback to GetComputerName */
+  result_len = name_len;
+  /* Reset error code */
+  error_code = NO_ERROR;
+
+  if (GetComputerNameW(name, (PDWORD)&result_len) == FALSE) {
+    error_code = WSAENETDOWN;
+    if (result_len >= name_len) {
+      error_code = WSAEFAULT;
+    }
+  }
+
+cleanup:
+  uv__free(heap_data);
+
+  if (error_code == NO_ERROR) {
+    return NO_ERROR;
+  } else {
+    WSASetLastError(error_code);
+    return SOCKET_ERROR;
+  }
+}
+
+
 int uv_os_gethostname(char* buffer, size_t* size) {
   WCHAR buf[UV_MAXHOSTNAMESIZE];
   size_t len;
@@ -1674,7 +1803,9 @@ int uv_os_gethostname(char* buffer, size_t* size) {
 
   uv__once_init(); /* Initialize winsock */
 
-  if (GetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
+  sGetHostNameW gethostnamew =
+      pGetHostNameW == NULL ? uv__gethostnamew_nt60 : pGetHostNameW;
+  if (gethostnamew(buf, UV_MAXHOSTNAMESIZE) != 0)
     return uv_translate_sys_error(WSAGetLastError());
 
   convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str);
diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c
index bb86ec8ceac8ba3fccd02b292aca7ddfab38e187..9d6effb10ddd1801f7411ee71a70575b7072ab7d 100644
--- a/deps/uv/src/win/winapi.c
+++ b/deps/uv/src/win/winapi.c
@@ -45,12 +45,15 @@ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
 /* User32.dll function pointer */
 sSetWinEventHook pSetWinEventHook;
 
+/* ws2_32.dll function pointer */
+sGetHostNameW pGetHostNameW;
 
 void uv_winapi_init(void) {
   HMODULE ntdll_module;
   HMODULE powrprof_module;
   HMODULE user32_module;
   HMODULE kernel32_module;
+  HMODULE ws2_32_module;;
 
   ntdll_module = GetModuleHandleA("ntdll.dll");
   if (ntdll_module == NULL) {
@@ -134,4 +137,10 @@ void uv_winapi_init(void) {
     pSetWinEventHook = (sSetWinEventHook)
       GetProcAddress(user32_module, "SetWinEventHook");
   }
+
+  ws2_32_module = LoadLibraryA("ws2_32.dll");
+  if (ws2_32_module != NULL) {
+    pGetHostNameW = (sGetHostNameW)
+      GetProcAddress(ws2_32_module, "GetHostNameW");
+  }
 }
diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h
index 0b66b5634bca88cec65b1bf0c0193986f5ddd542..5951717ab9e21db274f956c44410cc03c1617eaf 100644
--- a/deps/uv/src/win/winapi.h
+++ b/deps/uv/src/win/winapi.h
@@ -4739,6 +4739,11 @@ typedef struct _TCP_INITIAL_RTO_PARAMETERS {
 # define  SIO_TCP_INITIAL_RTO _WSAIOW(IOC_VENDOR,17)
 #endif
 
+/* From winsock2.h */
+typedef int (WSAAPI *sGetHostNameW)
+            (PWSTR name,
+             int   namelen);
+
 /* Ntdll function pointers */
 extern sRtlGetVersion pRtlGetVersion;
 extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
@@ -4759,4 +4764,7 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi
 /* User32.dll function pointer */
 extern sSetWinEventHook pSetWinEventHook;
 
+/* ws2_32.dll function pointer */
+extern sGetHostNameW pGetHostNameW;
+
 #endif /* UV_WIN_WINAPI_H_ */
