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 33e874ac442f88b58d2b68c8ec9764f6f664552e..37ece5e2867ab836492a8b7faa0aa5e1b8e562f0 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,10 +1803,10 @@ int uv_os_gethostname(char* buffer, size_t* size) {
 
   uv__once_init(); /* Initialize winsock */
 
-  if (pGetHostNameW == NULL)
-    return UV_ENOSYS;
+  uv_sGetHostNameW gethostnamew =
+      pGetHostNameW == NULL ? uv__gethostnamew_nt60 : pGetHostNameW;
 
-  if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
+  if (gethostnamew(buf, UV_MAXHOSTNAMESIZE) != 0)
     return uv_translate_sys_error(WSAGetLastError());
 
   convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str);
