diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
commit | 2d37894b1b037cf24231090eda8589bbb44fb6fc (patch) | |
tree | be835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/libs/llvm12/lib/Support/Windows | |
parent | 718c552901d703c502ccbefdfc3c9028d608b947 (diff) | |
download | ydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/Support/Windows')
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Windows/COM.inc | 72 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Windows/DynamicLibrary.inc | 404 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Windows/Host.inc | 66 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Windows/Memory.inc | 392 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Windows/Path.inc | 3046 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Windows/Process.inc | 1006 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Windows/Program.inc | 1046 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Windows/Signals.inc | 1738 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Windows/ThreadLocal.inc | 102 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Windows/Threading.inc | 584 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Windows/Watchdog.inc | 46 | ||||
-rw-r--r-- | contrib/libs/llvm12/lib/Support/Windows/explicit_symbols.inc | 192 |
12 files changed, 4347 insertions, 4347 deletions
diff --git a/contrib/libs/llvm12/lib/Support/Windows/COM.inc b/contrib/libs/llvm12/lib/Support/Windows/COM.inc index 1d1f88d7a1..002182bc39 100644 --- a/contrib/libs/llvm12/lib/Support/Windows/COM.inc +++ b/contrib/libs/llvm12/lib/Support/Windows/COM.inc @@ -1,36 +1,36 @@ -//==- llvm/Support/Windows/COM.inc - Windows COM Implementation -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the Windows portion of COM support. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Windows code. -//===----------------------------------------------------------------------===// - -#include <objbase.h> - -namespace llvm { -namespace sys { - -InitializeCOMRAII::InitializeCOMRAII(COMThreadingMode Threading, - bool SpeedOverMemory) { - DWORD Coinit = 0; - if (Threading == COMThreadingMode::SingleThreaded) - Coinit |= COINIT_APARTMENTTHREADED; - else - Coinit |= COINIT_MULTITHREADED; - if (SpeedOverMemory) - Coinit |= COINIT_SPEED_OVER_MEMORY; - ::CoInitializeEx(nullptr, Coinit); -} - -InitializeCOMRAII::~InitializeCOMRAII() { ::CoUninitialize(); } -} -} +//==- llvm/Support/Windows/COM.inc - Windows COM Implementation -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Windows portion of COM support. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Windows code. +//===----------------------------------------------------------------------===// + +#include <objbase.h> + +namespace llvm { +namespace sys { + +InitializeCOMRAII::InitializeCOMRAII(COMThreadingMode Threading, + bool SpeedOverMemory) { + DWORD Coinit = 0; + if (Threading == COMThreadingMode::SingleThreaded) + Coinit |= COINIT_APARTMENTTHREADED; + else + Coinit |= COINIT_MULTITHREADED; + if (SpeedOverMemory) + Coinit |= COINIT_SPEED_OVER_MEMORY; + ::CoInitializeEx(nullptr, Coinit); +} + +InitializeCOMRAII::~InitializeCOMRAII() { ::CoUninitialize(); } +} +} diff --git a/contrib/libs/llvm12/lib/Support/Windows/DynamicLibrary.inc b/contrib/libs/llvm12/lib/Support/Windows/DynamicLibrary.inc index a4d6537851..a3f78fb0d6 100644 --- a/contrib/libs/llvm12/lib/Support/Windows/DynamicLibrary.inc +++ b/contrib/libs/llvm12/lib/Support/Windows/DynamicLibrary.inc @@ -1,202 +1,202 @@ -//===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of DynamicLibrary. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/Windows/WindowsSupport.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/raw_ostream.h" - -#include <psapi.h> - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code. -//===----------------------------------------------------------------------===// - - -DynamicLibrary::HandleSet::~HandleSet() { - for (void *Handle : llvm::reverse(Handles)) - FreeLibrary(HMODULE(Handle)); - - // 'Process' should not be released on Windows. - assert((!Process || Process==this) && "Bad Handle"); - // llvm_shutdown called, Return to default - DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; -} - -void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { - // Create the instance and return it to be the *Process* handle - // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL) - if (!File) - return &(*OpenedHandles); - - SmallVector<wchar_t, MAX_PATH> FileUnicode; - if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) { - SetLastError(ec.value()); - MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16"); - return &DynamicLibrary::Invalid; - } - - HMODULE Handle = LoadLibraryW(FileUnicode.data()); - if (Handle == NULL) { - MakeErrMsg(Err, std::string(File) + ": Can't open"); - return &DynamicLibrary::Invalid; - } - - return reinterpret_cast<void*>(Handle); -} - -static DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) { - if (!OpenedHandles.isConstructed()) - return nullptr; - DynamicLibrary::HandleSet &Inst = *OpenedHandles; - return Handle == &Inst ? &Inst : nullptr; -} - -void DynamicLibrary::HandleSet::DLClose(void *Handle) { - if (HandleSet* HS = IsOpenedHandlesInstance(Handle)) - HS->Process = nullptr; // Just drop the *Process* handle. - else - FreeLibrary((HMODULE)Handle); -} - -static bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) { - // EnumProcessModules will fail on Windows 64 while some versions of - // MingW-32 don't have EnumProcessModulesEx. - if ( -#ifdef _WIN64 - !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT) -#else - !EnumProcessModules(H, Data, Bytes, &Bytes) -#endif - ) { - std::string Err; - if (MakeErrMsg(&Err, "EnumProcessModules failure")) - llvm::errs() << Err << "\n"; - return false; - } - return true; -} - -void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { - HandleSet* HS = IsOpenedHandlesInstance(Handle); - if (!HS) - return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol)); - - // Could have done a dlclose on the *Process* handle - if (!HS->Process) - return nullptr; - - // Trials indicate EnumProcessModulesEx is consistantly faster than using - // EnumerateLoadedModules64 or CreateToolhelp32Snapshot. - // - // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx - // |=========|=============|======================================== - // | 37 | 0.0000585 * | 0.0003031 | 0.0000152 - // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683 - // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610 - // - // * Not including the load time of Dbghelp.dll (~.005 sec) - // - // There's still a case to somehow cache the result of EnumProcessModulesEx - // across invocations, but the complication of doing that properly... - // Possibly using LdrRegisterDllNotification to invalidate the cache? - - DWORD Bytes = 0; - HMODULE Self = HMODULE(GetCurrentProcess()); - if (!GetProcessModules(Self, Bytes)) - return nullptr; - - // Get the most recent list in case any modules added/removed between calls - // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES. - // MSDN is pretty clear that if the module list changes during the call to - // EnumProcessModulesEx the results should not be used. - std::vector<HMODULE> Handles; - do { - assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) && - "Should have at least one module and be aligned"); - Handles.resize(Bytes / sizeof(HMODULE)); - if (!GetProcessModules(Self, Bytes, Handles.data())) - return nullptr; - } while (Bytes != (Handles.size() * sizeof(HMODULE))); - - // Try EXE first, mirroring what dlsym(dlopen(NULL)) does. - if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol)) - return (void *) uintptr_t(Ptr); - - if (Handles.size() > 1) { - // This is different behaviour than what Posix dlsym(dlopen(NULL)) does. - // Doing that here is causing real problems for the JIT where msvc.dll - // and ucrt.dll can define the same symbols. The runtime linker will choose - // symbols from ucrt.dll first, but iterating NOT in reverse here would - // mean that the msvc.dll versions would be returned. - - for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) { - if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol)) - return (void *) uintptr_t(Ptr); - } - } - return nullptr; -} - - -// Stack probing routines are in the support library (e.g. libgcc), but we don't -// have dynamic linking on windows. Provide a hook. -#define EXPLICIT_SYMBOL(SYM) \ - extern "C" { extern void *SYM; } -#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO) - -#ifdef _M_IX86 -// Win32 on x86 implements certain single-precision math functions as macros. -// These functions are not exported by the DLL, but will still be needed -// for symbol-resolution by the JIT loader. Therefore, this Support libray -// provides helper functions with the same implementation. - -#define INLINE_DEF_SYMBOL1(TYP, SYM) \ - extern "C" TYP inline_##SYM(TYP _X) { return SYM(_X); } -#define INLINE_DEF_SYMBOL2(TYP, SYM) \ - extern "C" TYP inline_##SYM(TYP _X, TYP _Y) { return SYM(_X, _Y); } -#endif - -#include "explicit_symbols.inc" - -#undef EXPLICIT_SYMBOL -#undef EXPLICIT_SYMBOL2 -#undef INLINE_DEF_SYMBOL1 -#undef INLINE_DEF_SYMBOL2 - -static void *DoSearch(const char *SymbolName) { - -#define EXPLICIT_SYMBOL(SYM) \ - if (!strcmp(SymbolName, #SYM)) \ - return (void *)&SYM; -#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \ - if (!strcmp(SymbolName, #SYMFROM)) \ - return (void *)&SYMTO; - -#ifdef _M_IX86 -#define INLINE_DEF_SYMBOL1(TYP, SYM) \ - if (!strcmp(SymbolName, #SYM)) \ - return (void *)&inline_##SYM; -#define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM) -#endif - - { -#include "explicit_symbols.inc" - } - -#undef EXPLICIT_SYMBOL -#undef EXPLICIT_SYMBOL2 -#undef INLINE_DEF_SYMBOL1 -#undef INLINE_DEF_SYMBOL2 - - return nullptr; -} +//===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of DynamicLibrary. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Windows/WindowsSupport.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/raw_ostream.h" + +#include <psapi.h> + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code. +//===----------------------------------------------------------------------===// + + +DynamicLibrary::HandleSet::~HandleSet() { + for (void *Handle : llvm::reverse(Handles)) + FreeLibrary(HMODULE(Handle)); + + // 'Process' should not be released on Windows. + assert((!Process || Process==this) && "Bad Handle"); + // llvm_shutdown called, Return to default + DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; +} + +void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { + // Create the instance and return it to be the *Process* handle + // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL) + if (!File) + return &(*OpenedHandles); + + SmallVector<wchar_t, MAX_PATH> FileUnicode; + if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) { + SetLastError(ec.value()); + MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16"); + return &DynamicLibrary::Invalid; + } + + HMODULE Handle = LoadLibraryW(FileUnicode.data()); + if (Handle == NULL) { + MakeErrMsg(Err, std::string(File) + ": Can't open"); + return &DynamicLibrary::Invalid; + } + + return reinterpret_cast<void*>(Handle); +} + +static DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) { + if (!OpenedHandles.isConstructed()) + return nullptr; + DynamicLibrary::HandleSet &Inst = *OpenedHandles; + return Handle == &Inst ? &Inst : nullptr; +} + +void DynamicLibrary::HandleSet::DLClose(void *Handle) { + if (HandleSet* HS = IsOpenedHandlesInstance(Handle)) + HS->Process = nullptr; // Just drop the *Process* handle. + else + FreeLibrary((HMODULE)Handle); +} + +static bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) { + // EnumProcessModules will fail on Windows 64 while some versions of + // MingW-32 don't have EnumProcessModulesEx. + if ( +#ifdef _WIN64 + !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT) +#else + !EnumProcessModules(H, Data, Bytes, &Bytes) +#endif + ) { + std::string Err; + if (MakeErrMsg(&Err, "EnumProcessModules failure")) + llvm::errs() << Err << "\n"; + return false; + } + return true; +} + +void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { + HandleSet* HS = IsOpenedHandlesInstance(Handle); + if (!HS) + return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol)); + + // Could have done a dlclose on the *Process* handle + if (!HS->Process) + return nullptr; + + // Trials indicate EnumProcessModulesEx is consistantly faster than using + // EnumerateLoadedModules64 or CreateToolhelp32Snapshot. + // + // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx + // |=========|=============|======================================== + // | 37 | 0.0000585 * | 0.0003031 | 0.0000152 + // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683 + // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610 + // + // * Not including the load time of Dbghelp.dll (~.005 sec) + // + // There's still a case to somehow cache the result of EnumProcessModulesEx + // across invocations, but the complication of doing that properly... + // Possibly using LdrRegisterDllNotification to invalidate the cache? + + DWORD Bytes = 0; + HMODULE Self = HMODULE(GetCurrentProcess()); + if (!GetProcessModules(Self, Bytes)) + return nullptr; + + // Get the most recent list in case any modules added/removed between calls + // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES. + // MSDN is pretty clear that if the module list changes during the call to + // EnumProcessModulesEx the results should not be used. + std::vector<HMODULE> Handles; + do { + assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) && + "Should have at least one module and be aligned"); + Handles.resize(Bytes / sizeof(HMODULE)); + if (!GetProcessModules(Self, Bytes, Handles.data())) + return nullptr; + } while (Bytes != (Handles.size() * sizeof(HMODULE))); + + // Try EXE first, mirroring what dlsym(dlopen(NULL)) does. + if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol)) + return (void *) uintptr_t(Ptr); + + if (Handles.size() > 1) { + // This is different behaviour than what Posix dlsym(dlopen(NULL)) does. + // Doing that here is causing real problems for the JIT where msvc.dll + // and ucrt.dll can define the same symbols. The runtime linker will choose + // symbols from ucrt.dll first, but iterating NOT in reverse here would + // mean that the msvc.dll versions would be returned. + + for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) { + if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol)) + return (void *) uintptr_t(Ptr); + } + } + return nullptr; +} + + +// Stack probing routines are in the support library (e.g. libgcc), but we don't +// have dynamic linking on windows. Provide a hook. +#define EXPLICIT_SYMBOL(SYM) \ + extern "C" { extern void *SYM; } +#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO) + +#ifdef _M_IX86 +// Win32 on x86 implements certain single-precision math functions as macros. +// These functions are not exported by the DLL, but will still be needed +// for symbol-resolution by the JIT loader. Therefore, this Support libray +// provides helper functions with the same implementation. + +#define INLINE_DEF_SYMBOL1(TYP, SYM) \ + extern "C" TYP inline_##SYM(TYP _X) { return SYM(_X); } +#define INLINE_DEF_SYMBOL2(TYP, SYM) \ + extern "C" TYP inline_##SYM(TYP _X, TYP _Y) { return SYM(_X, _Y); } +#endif + +#include "explicit_symbols.inc" + +#undef EXPLICIT_SYMBOL +#undef EXPLICIT_SYMBOL2 +#undef INLINE_DEF_SYMBOL1 +#undef INLINE_DEF_SYMBOL2 + +static void *DoSearch(const char *SymbolName) { + +#define EXPLICIT_SYMBOL(SYM) \ + if (!strcmp(SymbolName, #SYM)) \ + return (void *)&SYM; +#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \ + if (!strcmp(SymbolName, #SYMFROM)) \ + return (void *)&SYMTO; + +#ifdef _M_IX86 +#define INLINE_DEF_SYMBOL1(TYP, SYM) \ + if (!strcmp(SymbolName, #SYM)) \ + return (void *)&inline_##SYM; +#define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM) +#endif + + { +#include "explicit_symbols.inc" + } + +#undef EXPLICIT_SYMBOL +#undef EXPLICIT_SYMBOL2 +#undef INLINE_DEF_SYMBOL1 +#undef INLINE_DEF_SYMBOL2 + + return nullptr; +} diff --git a/contrib/libs/llvm12/lib/Support/Windows/Host.inc b/contrib/libs/llvm12/lib/Support/Windows/Host.inc index 3f0f3791ce..5583db9090 100644 --- a/contrib/libs/llvm12/lib/Support/Windows/Host.inc +++ b/contrib/libs/llvm12/lib/Support/Windows/Host.inc @@ -1,33 +1,33 @@ -//===- llvm/Support/Win32/Host.inc ------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the Win32 Host support. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/Windows/WindowsSupport.h" -#include <cstdio> -#include <string> - -using namespace llvm; - -static std::string updateTripleOSVersion(std::string Triple) { - return Triple; -} - -std::string sys::getDefaultTargetTriple() { - const char *Triple = LLVM_DEFAULT_TARGET_TRIPLE; - - // Override the default target with an environment variable named by LLVM_TARGET_TRIPLE_ENV. -#if defined(LLVM_TARGET_TRIPLE_ENV) - if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV)) - Triple = EnvTriple; -#endif - - return Triple; -} +//===- llvm/Support/Win32/Host.inc ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 Host support. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Windows/WindowsSupport.h" +#include <cstdio> +#include <string> + +using namespace llvm; + +static std::string updateTripleOSVersion(std::string Triple) { + return Triple; +} + +std::string sys::getDefaultTargetTriple() { + const char *Triple = LLVM_DEFAULT_TARGET_TRIPLE; + + // Override the default target with an environment variable named by LLVM_TARGET_TRIPLE_ENV. +#if defined(LLVM_TARGET_TRIPLE_ENV) + if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV)) + Triple = EnvTriple; +#endif + + return Triple; +} diff --git a/contrib/libs/llvm12/lib/Support/Windows/Memory.inc b/contrib/libs/llvm12/lib/Support/Windows/Memory.inc index 791d7bb272..1b2de1915e 100644 --- a/contrib/libs/llvm12/lib/Support/Windows/Memory.inc +++ b/contrib/libs/llvm12/lib/Support/Windows/Memory.inc @@ -1,196 +1,196 @@ -//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of various Memory -// management utilities -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/WindowsError.h" - -// The Windows.h header must be the last one included. -#include "llvm/Support/Windows/WindowsSupport.h" - -static DWORD getWindowsProtectionFlags(unsigned Flags) { - switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { - // Contrary to what you might expect, the Windows page protection flags - // are not a bitwise combination of RWX values - case llvm::sys::Memory::MF_READ: - return PAGE_READONLY; - case llvm::sys::Memory::MF_WRITE: - // Note: PAGE_WRITE is not supported by VirtualProtect - return PAGE_READWRITE; - case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: - return PAGE_READWRITE; - case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: - return PAGE_EXECUTE_READ; - case llvm::sys::Memory::MF_READ | - llvm::sys::Memory::MF_WRITE | - llvm::sys::Memory::MF_EXEC: - return PAGE_EXECUTE_READWRITE; - case llvm::sys::Memory::MF_EXEC: - return PAGE_EXECUTE; - default: - llvm_unreachable("Illegal memory protection flag specified!"); - } - // Provide a default return value as required by some compilers. - return PAGE_NOACCESS; -} - -// While we'd be happy to allocate single pages, the Windows allocation -// granularity may be larger than a single page (in practice, it is 64K) -// so mapping less than that will create an unreachable fragment of memory. -static size_t getAllocationGranularity() { - SYSTEM_INFO Info; - ::GetSystemInfo(&Info); - if (Info.dwPageSize > Info.dwAllocationGranularity) - return Info.dwPageSize; - else - return Info.dwAllocationGranularity; -} - -// Large/huge memory pages need explicit process permissions in order to be -// used. See https://blogs.msdn.microsoft.com/oldnewthing/20110128-00/?p=11643 -// Also large pages need to be manually enabled on your OS. If all this is -// sucessfull, we return the minimal large memory page size. -static size_t enableProcessLargePages() { - HANDLE Token = 0; - size_t LargePageMin = GetLargePageMinimum(); - if (LargePageMin) - OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, - &Token); - if (!Token) - return 0; - LUID Luid; - if (!LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &Luid)) { - CloseHandle(Token); - return 0; - } - TOKEN_PRIVILEGES TP{}; - TP.PrivilegeCount = 1; - TP.Privileges[0].Luid = Luid; - TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - if (!AdjustTokenPrivileges(Token, FALSE, &TP, 0, 0, 0)) { - CloseHandle(Token); - return 0; - } - DWORD E = GetLastError(); - CloseHandle(Token); - if (E == ERROR_SUCCESS) - return LargePageMin; - return 0; -} - -namespace llvm { -namespace sys { - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, - const MemoryBlock *const NearBlock, - unsigned Flags, - std::error_code &EC) { - EC = std::error_code(); - if (NumBytes == 0) - return MemoryBlock(); - - static size_t DefaultGranularity = getAllocationGranularity(); - static size_t LargePageGranularity = enableProcessLargePages(); - - DWORD AllocType = MEM_RESERVE | MEM_COMMIT; - bool HugePages = false; - size_t Granularity = DefaultGranularity; - - if ((Flags & MF_HUGE_HINT) && LargePageGranularity > 0) { - AllocType |= MEM_LARGE_PAGES; - HugePages = true; - Granularity = LargePageGranularity; - } - - size_t NumBlocks = (NumBytes + Granularity - 1) / Granularity; - - uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + - NearBlock->allocatedSize() - : 0; - - // If the requested address is not aligned to the allocation granularity, - // round up to get beyond NearBlock. VirtualAlloc would have rounded down. - if (Start && Start % Granularity != 0) - Start += Granularity - Start % Granularity; - - DWORD Protect = getWindowsProtectionFlags(Flags); - - size_t AllocSize = NumBlocks * Granularity; - void *PA = ::VirtualAlloc(reinterpret_cast<void *>(Start), - AllocSize, AllocType, Protect); - if (PA == NULL) { - if (NearBlock || HugePages) { - // Try again without the NearBlock hint and without large memory pages - return allocateMappedMemory(NumBytes, NULL, Flags & ~MF_HUGE_HINT, EC); - } - EC = mapWindowsError(::GetLastError()); - return MemoryBlock(); - } - - MemoryBlock Result; - Result.Address = PA; - Result.AllocatedSize = AllocSize; - Result.Flags = (Flags & ~MF_HUGE_HINT) | (HugePages ? MF_HUGE_HINT : 0); - - if (Flags & MF_EXEC) - Memory::InvalidateInstructionCache(Result.Address, AllocSize); - - return Result; -} - - std::error_code Memory::releaseMappedMemory(MemoryBlock &M) { - if (M.Address == 0 || M.AllocatedSize == 0) - return std::error_code(); - - if (!VirtualFree(M.Address, 0, MEM_RELEASE)) - return mapWindowsError(::GetLastError()); - - M.Address = 0; - M.AllocatedSize = 0; - - return std::error_code(); -} - - std::error_code Memory::protectMappedMemory(const MemoryBlock &M, - unsigned Flags) { - if (M.Address == 0 || M.AllocatedSize == 0) - return std::error_code(); - - DWORD Protect = getWindowsProtectionFlags(Flags); - - DWORD OldFlags; - if (!VirtualProtect(M.Address, M.AllocatedSize, Protect, &OldFlags)) - return mapWindowsError(::GetLastError()); - - if (Flags & MF_EXEC) - Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); - - return std::error_code(); -} - -/// InvalidateInstructionCache - Before the JIT can run a block of code -/// that has been emitted it must invalidate the instruction cache on some -/// platforms. -void Memory::InvalidateInstructionCache( - const void *Addr, size_t Len) { - FlushInstructionCache(GetCurrentProcess(), Addr, Len); -} - -} // namespace sys -} // namespace llvm +//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of various Memory +// management utilities +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/WindowsError.h" + +// The Windows.h header must be the last one included. +#include "llvm/Support/Windows/WindowsSupport.h" + +static DWORD getWindowsProtectionFlags(unsigned Flags) { + switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { + // Contrary to what you might expect, the Windows page protection flags + // are not a bitwise combination of RWX values + case llvm::sys::Memory::MF_READ: + return PAGE_READONLY; + case llvm::sys::Memory::MF_WRITE: + // Note: PAGE_WRITE is not supported by VirtualProtect + return PAGE_READWRITE; + case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: + return PAGE_READWRITE; + case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: + return PAGE_EXECUTE_READ; + case llvm::sys::Memory::MF_READ | + llvm::sys::Memory::MF_WRITE | + llvm::sys::Memory::MF_EXEC: + return PAGE_EXECUTE_READWRITE; + case llvm::sys::Memory::MF_EXEC: + return PAGE_EXECUTE; + default: + llvm_unreachable("Illegal memory protection flag specified!"); + } + // Provide a default return value as required by some compilers. + return PAGE_NOACCESS; +} + +// While we'd be happy to allocate single pages, the Windows allocation +// granularity may be larger than a single page (in practice, it is 64K) +// so mapping less than that will create an unreachable fragment of memory. +static size_t getAllocationGranularity() { + SYSTEM_INFO Info; + ::GetSystemInfo(&Info); + if (Info.dwPageSize > Info.dwAllocationGranularity) + return Info.dwPageSize; + else + return Info.dwAllocationGranularity; +} + +// Large/huge memory pages need explicit process permissions in order to be +// used. See https://blogs.msdn.microsoft.com/oldnewthing/20110128-00/?p=11643 +// Also large pages need to be manually enabled on your OS. If all this is +// sucessfull, we return the minimal large memory page size. +static size_t enableProcessLargePages() { + HANDLE Token = 0; + size_t LargePageMin = GetLargePageMinimum(); + if (LargePageMin) + OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &Token); + if (!Token) + return 0; + LUID Luid; + if (!LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &Luid)) { + CloseHandle(Token); + return 0; + } + TOKEN_PRIVILEGES TP{}; + TP.PrivilegeCount = 1; + TP.Privileges[0].Luid = Luid; + TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if (!AdjustTokenPrivileges(Token, FALSE, &TP, 0, 0, 0)) { + CloseHandle(Token); + return 0; + } + DWORD E = GetLastError(); + CloseHandle(Token); + if (E == ERROR_SUCCESS) + return LargePageMin; + return 0; +} + +namespace llvm { +namespace sys { + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, + const MemoryBlock *const NearBlock, + unsigned Flags, + std::error_code &EC) { + EC = std::error_code(); + if (NumBytes == 0) + return MemoryBlock(); + + static size_t DefaultGranularity = getAllocationGranularity(); + static size_t LargePageGranularity = enableProcessLargePages(); + + DWORD AllocType = MEM_RESERVE | MEM_COMMIT; + bool HugePages = false; + size_t Granularity = DefaultGranularity; + + if ((Flags & MF_HUGE_HINT) && LargePageGranularity > 0) { + AllocType |= MEM_LARGE_PAGES; + HugePages = true; + Granularity = LargePageGranularity; + } + + size_t NumBlocks = (NumBytes + Granularity - 1) / Granularity; + + uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + + NearBlock->allocatedSize() + : 0; + + // If the requested address is not aligned to the allocation granularity, + // round up to get beyond NearBlock. VirtualAlloc would have rounded down. + if (Start && Start % Granularity != 0) + Start += Granularity - Start % Granularity; + + DWORD Protect = getWindowsProtectionFlags(Flags); + + size_t AllocSize = NumBlocks * Granularity; + void *PA = ::VirtualAlloc(reinterpret_cast<void *>(Start), + AllocSize, AllocType, Protect); + if (PA == NULL) { + if (NearBlock || HugePages) { + // Try again without the NearBlock hint and without large memory pages + return allocateMappedMemory(NumBytes, NULL, Flags & ~MF_HUGE_HINT, EC); + } + EC = mapWindowsError(::GetLastError()); + return MemoryBlock(); + } + + MemoryBlock Result; + Result.Address = PA; + Result.AllocatedSize = AllocSize; + Result.Flags = (Flags & ~MF_HUGE_HINT) | (HugePages ? MF_HUGE_HINT : 0); + + if (Flags & MF_EXEC) + Memory::InvalidateInstructionCache(Result.Address, AllocSize); + + return Result; +} + + std::error_code Memory::releaseMappedMemory(MemoryBlock &M) { + if (M.Address == 0 || M.AllocatedSize == 0) + return std::error_code(); + + if (!VirtualFree(M.Address, 0, MEM_RELEASE)) + return mapWindowsError(::GetLastError()); + + M.Address = 0; + M.AllocatedSize = 0; + + return std::error_code(); +} + + std::error_code Memory::protectMappedMemory(const MemoryBlock &M, + unsigned Flags) { + if (M.Address == 0 || M.AllocatedSize == 0) + return std::error_code(); + + DWORD Protect = getWindowsProtectionFlags(Flags); + + DWORD OldFlags; + if (!VirtualProtect(M.Address, M.AllocatedSize, Protect, &OldFlags)) + return mapWindowsError(::GetLastError()); + + if (Flags & MF_EXEC) + Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); + + return std::error_code(); +} + +/// InvalidateInstructionCache - Before the JIT can run a block of code +/// that has been emitted it must invalidate the instruction cache on some +/// platforms. +void Memory::InvalidateInstructionCache( + const void *Addr, size_t Len) { + FlushInstructionCache(GetCurrentProcess(), Addr, Len); +} + +} // namespace sys +} // namespace llvm diff --git a/contrib/libs/llvm12/lib/Support/Windows/Path.inc b/contrib/libs/llvm12/lib/Support/Windows/Path.inc index 84cd35ec06..adcbd1b5f8 100644 --- a/contrib/libs/llvm12/lib/Support/Windows/Path.inc +++ b/contrib/libs/llvm12/lib/Support/Windows/Path.inc @@ -1,407 +1,407 @@ -//===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the Windows specific implementation of the Path API. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Windows code that -//=== is guaranteed to work on *all* Windows variants. -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/WindowsError.h" -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/types.h> - -// These two headers must be included last, and make sure shlobj is required -// after Windows.h to make sure it picks up our definition of _WIN32_WINNT -#include "llvm/Support/Windows/WindowsSupport.h" -#include <shellapi.h> -#include <shlobj.h> - -#undef max - -// MinGW doesn't define this. -#ifndef _ERRNO_T_DEFINED -#define _ERRNO_T_DEFINED -typedef int errno_t; -#endif - -#ifdef _MSC_VER -# pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW. -# pragma comment(lib, "ole32.lib") // This provides CoTaskMemFree -#endif - -using namespace llvm; - -using llvm::sys::windows::UTF8ToUTF16; -using llvm::sys::windows::CurCPToUTF16; -using llvm::sys::windows::UTF16ToUTF8; -using llvm::sys::windows::widenPath; - -static bool is_separator(const wchar_t value) { - switch (value) { - case L'\\': - case L'/': - return true; - default: - return false; - } -} - -namespace llvm { -namespace sys { -namespace windows { - -// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the path -// is longer than the limit that the Win32 Unicode File API can tolerate, make -// it an absolute normalized path prefixed by '\\?\'. -std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16, - size_t MaxPathLen) { - assert(MaxPathLen <= MAX_PATH); - - // Several operations would convert Path8 to SmallString; more efficient to do - // it once up front. - SmallString<MAX_PATH> Path8Str; - Path8.toVector(Path8Str); - - if (std::error_code EC = UTF8ToUTF16(Path8Str, Path16)) - return EC; - - const bool IsAbsolute = llvm::sys::path::is_absolute(Path8); - size_t CurPathLen; - if (IsAbsolute) - CurPathLen = 0; // No contribution from current_path needed. - else { - CurPathLen = ::GetCurrentDirectoryW( - 0, NULL); // Returns the size including the null terminator. - if (CurPathLen == 0) - return mapWindowsError(::GetLastError()); - } - - const char *const LongPathPrefix = "\\\\?\\"; - - if ((Path16.size() + CurPathLen) < MaxPathLen || - Path8Str.startswith(LongPathPrefix)) - return std::error_code(); - - if (!IsAbsolute) { - if (std::error_code EC = llvm::sys::fs::make_absolute(Path8Str)) - return EC; - } - - // Remove '.' and '..' because long paths treat these as real path components. - llvm::sys::path::native(Path8Str, path::Style::windows); - llvm::sys::path::remove_dots(Path8Str, true); - - const StringRef RootName = llvm::sys::path::root_name(Path8Str); - assert(!RootName.empty() && - "Root name cannot be empty for an absolute path!"); - - SmallString<2 * MAX_PATH> FullPath(LongPathPrefix); - if (RootName[1] != ':') { // Check if UNC. - FullPath.append("UNC\\"); - FullPath.append(Path8Str.begin() + 2, Path8Str.end()); - } else - FullPath.append(Path8Str); - - return UTF8ToUTF16(FullPath, Path16); -} - -} // end namespace windows - -namespace fs { - -const file_t kInvalidFile = INVALID_HANDLE_VALUE; - -std::string getMainExecutable(const char *argv0, void *MainExecAddr) { - SmallVector<wchar_t, MAX_PATH> PathName; - DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); - - // A zero return value indicates a failure other than insufficient space. - if (Size == 0) - return ""; - - // Insufficient space is determined by a return value equal to the size of - // the buffer passed in. - if (Size == PathName.capacity()) - return ""; - - // On success, GetModuleFileNameW returns the number of characters written to - // the buffer not including the NULL terminator. - PathName.set_size(Size); - - // Convert the result from UTF-16 to UTF-8. - SmallVector<char, MAX_PATH> PathNameUTF8; - if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8)) - return ""; - - return std::string(PathNameUTF8.data()); -} - -UniqueID file_status::getUniqueID() const { - // The file is uniquely identified by the volume serial number along - // with the 64-bit file identifier. - uint64_t FileID = (static_cast<uint64_t>(FileIndexHigh) << 32ULL) | - static_cast<uint64_t>(FileIndexLow); - - return UniqueID(VolumeSerialNumber, FileID); -} - -ErrorOr<space_info> disk_space(const Twine &Path) { - ULARGE_INTEGER Avail, Total, Free; - if (!::GetDiskFreeSpaceExA(Path.str().c_str(), &Avail, &Total, &Free)) - return mapWindowsError(::GetLastError()); - space_info SpaceInfo; - SpaceInfo.capacity = - (static_cast<uint64_t>(Total.HighPart) << 32) + Total.LowPart; - SpaceInfo.free = (static_cast<uint64_t>(Free.HighPart) << 32) + Free.LowPart; - SpaceInfo.available = - (static_cast<uint64_t>(Avail.HighPart) << 32) + Avail.LowPart; - return SpaceInfo; -} - -TimePoint<> basic_file_status::getLastAccessedTime() const { - FILETIME Time; - Time.dwLowDateTime = LastAccessedTimeLow; - Time.dwHighDateTime = LastAccessedTimeHigh; - return toTimePoint(Time); -} - -TimePoint<> basic_file_status::getLastModificationTime() const { - FILETIME Time; - Time.dwLowDateTime = LastWriteTimeLow; - Time.dwHighDateTime = LastWriteTimeHigh; - return toTimePoint(Time); -} - -uint32_t file_status::getLinkCount() const { - return NumLinks; -} - -std::error_code current_path(SmallVectorImpl<char> &result) { - SmallVector<wchar_t, MAX_PATH> cur_path; - DWORD len = MAX_PATH; - - do { - cur_path.reserve(len); - len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); - - // A zero return value indicates a failure other than insufficient space. - if (len == 0) - return mapWindowsError(::GetLastError()); - - // If there's insufficient space, the len returned is larger than the len - // given. - } while (len > cur_path.capacity()); - - // On success, GetCurrentDirectoryW returns the number of characters not - // including the null-terminator. - cur_path.set_size(len); - return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); -} - -std::error_code set_current_path(const Twine &path) { - // Convert to utf-16. - SmallVector<wchar_t, 128> wide_path; - if (std::error_code ec = widenPath(path, wide_path)) - return ec; - - if (!::SetCurrentDirectoryW(wide_path.begin())) - return mapWindowsError(::GetLastError()); - - return std::error_code(); -} - -std::error_code create_directory(const Twine &path, bool IgnoreExisting, - perms Perms) { - SmallVector<wchar_t, 128> path_utf16; - - // CreateDirectoryW has a lower maximum path length as it must leave room for - // an 8.3 filename. - if (std::error_code ec = widenPath(path, path_utf16, MAX_PATH - 12)) - return ec; - - if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { - DWORD LastError = ::GetLastError(); - if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting) - return mapWindowsError(LastError); - } - - return std::error_code(); -} - -// We can't use symbolic links for windows. -std::error_code create_link(const Twine &to, const Twine &from) { - // Convert to utf-16. - SmallVector<wchar_t, 128> wide_from; - SmallVector<wchar_t, 128> wide_to; - if (std::error_code ec = widenPath(from, wide_from)) - return ec; - if (std::error_code ec = widenPath(to, wide_to)) - return ec; - - if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) - return mapWindowsError(::GetLastError()); - - return std::error_code(); -} - -std::error_code create_hard_link(const Twine &to, const Twine &from) { - return create_link(to, from); -} - -std::error_code remove(const Twine &path, bool IgnoreNonExisting) { - SmallVector<wchar_t, 128> path_utf16; - - if (std::error_code ec = widenPath(path, path_utf16)) - return ec; - - // We don't know whether this is a file or a directory, and remove() can - // accept both. The usual way to delete a file or directory is to use one of - // the DeleteFile or RemoveDirectory functions, but that requires you to know - // which one it is. We could stat() the file to determine that, but that would - // cost us additional system calls, which can be slow in a directory - // containing a large number of files. So instead we call CreateFile directly. - // The important part is the FILE_FLAG_DELETE_ON_CLOSE flag, which causes the - // file to be deleted once it is closed. We also use the flags - // FILE_FLAG_BACKUP_SEMANTICS (which allows us to open directories), and - // FILE_FLAG_OPEN_REPARSE_POINT (don't follow symlinks). - ScopedFileHandle h(::CreateFileW( - c_str(path_utf16), DELETE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_DELETE_ON_CLOSE, - NULL)); - if (!h) { - std::error_code EC = mapWindowsError(::GetLastError()); - if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) - return EC; - } - - return std::error_code(); -} - -static std::error_code is_local_internal(SmallVectorImpl<wchar_t> &Path, - bool &Result) { - SmallVector<wchar_t, 128> VolumePath; - size_t Len = 128; - while (true) { - VolumePath.resize(Len); - BOOL Success = - ::GetVolumePathNameW(Path.data(), VolumePath.data(), VolumePath.size()); - - if (Success) - break; - - DWORD Err = ::GetLastError(); - if (Err != ERROR_INSUFFICIENT_BUFFER) - return mapWindowsError(Err); - - Len *= 2; - } - // If the output buffer has exactly enough space for the path name, but not - // the null terminator, it will leave the output unterminated. Push a null - // terminator onto the end to ensure that this never happens. - VolumePath.push_back(L'\0'); - VolumePath.set_size(wcslen(VolumePath.data())); - const wchar_t *P = VolumePath.data(); - - UINT Type = ::GetDriveTypeW(P); - switch (Type) { - case DRIVE_FIXED: - Result = true; - return std::error_code(); - case DRIVE_REMOTE: - case DRIVE_CDROM: - case DRIVE_RAMDISK: - case DRIVE_REMOVABLE: - Result = false; - return std::error_code(); - default: - return make_error_code(errc::no_such_file_or_directory); - } - llvm_unreachable("Unreachable!"); -} - -std::error_code is_local(const Twine &path, bool &result) { - if (!llvm::sys::fs::exists(path) || !llvm::sys::path::has_root_path(path)) - return make_error_code(errc::no_such_file_or_directory); - - SmallString<128> Storage; - StringRef P = path.toStringRef(Storage); - - // Convert to utf-16. - SmallVector<wchar_t, 128> WidePath; - if (std::error_code ec = widenPath(P, WidePath)) - return ec; - return is_local_internal(WidePath, result); -} - -static std::error_code realPathFromHandle(HANDLE H, - SmallVectorImpl<wchar_t> &Buffer) { - DWORD CountChars = ::GetFinalPathNameByHandleW( - H, Buffer.begin(), Buffer.capacity(), FILE_NAME_NORMALIZED); - if (CountChars && CountChars >= Buffer.capacity()) { - // The buffer wasn't big enough, try again. In this case the return value - // *does* indicate the size of the null terminator. - Buffer.reserve(CountChars); - CountChars = ::GetFinalPathNameByHandleW( - H, Buffer.begin(), Buffer.capacity(), FILE_NAME_NORMALIZED); - } - if (CountChars == 0) - return mapWindowsError(GetLastError()); - Buffer.set_size(CountChars); - return std::error_code(); -} - -static std::error_code realPathFromHandle(HANDLE H, - SmallVectorImpl<char> &RealPath) { - RealPath.clear(); - SmallVector<wchar_t, MAX_PATH> Buffer; - if (std::error_code EC = realPathFromHandle(H, Buffer)) - return EC; - - // Strip the \\?\ prefix. We don't want it ending up in output, and such - // paths don't get canonicalized by file APIs. - wchar_t *Data = Buffer.data(); - DWORD CountChars = Buffer.size(); - if (CountChars >= 8 && ::memcmp(Data, L"\\\\?\\UNC\\", 16) == 0) { - // Convert \\?\UNC\foo\bar to \\foo\bar - CountChars -= 6; - Data += 6; - Data[0] = '\\'; - } else if (CountChars >= 4 && ::memcmp(Data, L"\\\\?\\", 8) == 0) { - // Convert \\?\c:\foo to c:\foo - CountChars -= 4; - Data += 4; - } - - // Convert the result from UTF-16 to UTF-8. - return UTF16ToUTF8(Data, CountChars, RealPath); -} - -std::error_code is_local(int FD, bool &Result) { - SmallVector<wchar_t, 128> FinalPath; - HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); - - if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) - return EC; - - return is_local_internal(FinalPath, Result); -} - -static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { +//===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Windows specific implementation of the Path API. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Windows code that +//=== is guaranteed to work on *all* Windows variants. +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/WindowsError.h" +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + +// These two headers must be included last, and make sure shlobj is required +// after Windows.h to make sure it picks up our definition of _WIN32_WINNT +#include "llvm/Support/Windows/WindowsSupport.h" +#include <shellapi.h> +#include <shlobj.h> + +#undef max + +// MinGW doesn't define this. +#ifndef _ERRNO_T_DEFINED +#define _ERRNO_T_DEFINED +typedef int errno_t; +#endif + +#ifdef _MSC_VER +# pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW. +# pragma comment(lib, "ole32.lib") // This provides CoTaskMemFree +#endif + +using namespace llvm; + +using llvm::sys::windows::UTF8ToUTF16; +using llvm::sys::windows::CurCPToUTF16; +using llvm::sys::windows::UTF16ToUTF8; +using llvm::sys::windows::widenPath; + +static bool is_separator(const wchar_t value) { + switch (value) { + case L'\\': + case L'/': + return true; + default: + return false; + } +} + +namespace llvm { +namespace sys { +namespace windows { + +// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the path +// is longer than the limit that the Win32 Unicode File API can tolerate, make +// it an absolute normalized path prefixed by '\\?\'. +std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16, + size_t MaxPathLen) { + assert(MaxPathLen <= MAX_PATH); + + // Several operations would convert Path8 to SmallString; more efficient to do + // it once up front. + SmallString<MAX_PATH> Path8Str; + Path8.toVector(Path8Str); + + if (std::error_code EC = UTF8ToUTF16(Path8Str, Path16)) + return EC; + + const bool IsAbsolute = llvm::sys::path::is_absolute(Path8); + size_t CurPathLen; + if (IsAbsolute) + CurPathLen = 0; // No contribution from current_path needed. + else { + CurPathLen = ::GetCurrentDirectoryW( + 0, NULL); // Returns the size including the null terminator. + if (CurPathLen == 0) + return mapWindowsError(::GetLastError()); + } + + const char *const LongPathPrefix = "\\\\?\\"; + + if ((Path16.size() + CurPathLen) < MaxPathLen || + Path8Str.startswith(LongPathPrefix)) + return std::error_code(); + + if (!IsAbsolute) { + if (std::error_code EC = llvm::sys::fs::make_absolute(Path8Str)) + return EC; + } + + // Remove '.' and '..' because long paths treat these as real path components. + llvm::sys::path::native(Path8Str, path::Style::windows); + llvm::sys::path::remove_dots(Path8Str, true); + + const StringRef RootName = llvm::sys::path::root_name(Path8Str); + assert(!RootName.empty() && + "Root name cannot be empty for an absolute path!"); + + SmallString<2 * MAX_PATH> FullPath(LongPathPrefix); + if (RootName[1] != ':') { // Check if UNC. + FullPath.append("UNC\\"); + FullPath.append(Path8Str.begin() + 2, Path8Str.end()); + } else + FullPath.append(Path8Str); + + return UTF8ToUTF16(FullPath, Path16); +} + +} // end namespace windows + +namespace fs { + +const file_t kInvalidFile = INVALID_HANDLE_VALUE; + +std::string getMainExecutable(const char *argv0, void *MainExecAddr) { + SmallVector<wchar_t, MAX_PATH> PathName; + DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); + + // A zero return value indicates a failure other than insufficient space. + if (Size == 0) + return ""; + + // Insufficient space is determined by a return value equal to the size of + // the buffer passed in. + if (Size == PathName.capacity()) + return ""; + + // On success, GetModuleFileNameW returns the number of characters written to + // the buffer not including the NULL terminator. + PathName.set_size(Size); + + // Convert the result from UTF-16 to UTF-8. + SmallVector<char, MAX_PATH> PathNameUTF8; + if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8)) + return ""; + + return std::string(PathNameUTF8.data()); +} + +UniqueID file_status::getUniqueID() const { + // The file is uniquely identified by the volume serial number along + // with the 64-bit file identifier. + uint64_t FileID = (static_cast<uint64_t>(FileIndexHigh) << 32ULL) | + static_cast<uint64_t>(FileIndexLow); + + return UniqueID(VolumeSerialNumber, FileID); +} + +ErrorOr<space_info> disk_space(const Twine &Path) { + ULARGE_INTEGER Avail, Total, Free; + if (!::GetDiskFreeSpaceExA(Path.str().c_str(), &Avail, &Total, &Free)) + return mapWindowsError(::GetLastError()); + space_info SpaceInfo; + SpaceInfo.capacity = + (static_cast<uint64_t>(Total.HighPart) << 32) + Total.LowPart; + SpaceInfo.free = (static_cast<uint64_t>(Free.HighPart) << 32) + Free.LowPart; + SpaceInfo.available = + (static_cast<uint64_t>(Avail.HighPart) << 32) + Avail.LowPart; + return SpaceInfo; +} + +TimePoint<> basic_file_status::getLastAccessedTime() const { + FILETIME Time; + Time.dwLowDateTime = LastAccessedTimeLow; + Time.dwHighDateTime = LastAccessedTimeHigh; + return toTimePoint(Time); +} + +TimePoint<> basic_file_status::getLastModificationTime() const { + FILETIME Time; + Time.dwLowDateTime = LastWriteTimeLow; + Time.dwHighDateTime = LastWriteTimeHigh; + return toTimePoint(Time); +} + +uint32_t file_status::getLinkCount() const { + return NumLinks; +} + +std::error_code current_path(SmallVectorImpl<char> &result) { + SmallVector<wchar_t, MAX_PATH> cur_path; + DWORD len = MAX_PATH; + + do { + cur_path.reserve(len); + len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); + + // A zero return value indicates a failure other than insufficient space. + if (len == 0) + return mapWindowsError(::GetLastError()); + + // If there's insufficient space, the len returned is larger than the len + // given. + } while (len > cur_path.capacity()); + + // On success, GetCurrentDirectoryW returns the number of characters not + // including the null-terminator. + cur_path.set_size(len); + return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); +} + +std::error_code set_current_path(const Twine &path) { + // Convert to utf-16. + SmallVector<wchar_t, 128> wide_path; + if (std::error_code ec = widenPath(path, wide_path)) + return ec; + + if (!::SetCurrentDirectoryW(wide_path.begin())) + return mapWindowsError(::GetLastError()); + + return std::error_code(); +} + +std::error_code create_directory(const Twine &path, bool IgnoreExisting, + perms Perms) { + SmallVector<wchar_t, 128> path_utf16; + + // CreateDirectoryW has a lower maximum path length as it must leave room for + // an 8.3 filename. + if (std::error_code ec = widenPath(path, path_utf16, MAX_PATH - 12)) + return ec; + + if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { + DWORD LastError = ::GetLastError(); + if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting) + return mapWindowsError(LastError); + } + + return std::error_code(); +} + +// We can't use symbolic links for windows. +std::error_code create_link(const Twine &to, const Twine &from) { + // Convert to utf-16. + SmallVector<wchar_t, 128> wide_from; + SmallVector<wchar_t, 128> wide_to; + if (std::error_code ec = widenPath(from, wide_from)) + return ec; + if (std::error_code ec = widenPath(to, wide_to)) + return ec; + + if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) + return mapWindowsError(::GetLastError()); + + return std::error_code(); +} + +std::error_code create_hard_link(const Twine &to, const Twine &from) { + return create_link(to, from); +} + +std::error_code remove(const Twine &path, bool IgnoreNonExisting) { + SmallVector<wchar_t, 128> path_utf16; + + if (std::error_code ec = widenPath(path, path_utf16)) + return ec; + + // We don't know whether this is a file or a directory, and remove() can + // accept both. The usual way to delete a file or directory is to use one of + // the DeleteFile or RemoveDirectory functions, but that requires you to know + // which one it is. We could stat() the file to determine that, but that would + // cost us additional system calls, which can be slow in a directory + // containing a large number of files. So instead we call CreateFile directly. + // The important part is the FILE_FLAG_DELETE_ON_CLOSE flag, which causes the + // file to be deleted once it is closed. We also use the flags + // FILE_FLAG_BACKUP_SEMANTICS (which allows us to open directories), and + // FILE_FLAG_OPEN_REPARSE_POINT (don't follow symlinks). + ScopedFileHandle h(::CreateFileW( + c_str(path_utf16), DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_DELETE_ON_CLOSE, + NULL)); + if (!h) { + std::error_code EC = mapWindowsError(::GetLastError()); + if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) + return EC; + } + + return std::error_code(); +} + +static std::error_code is_local_internal(SmallVectorImpl<wchar_t> &Path, + bool &Result) { + SmallVector<wchar_t, 128> VolumePath; + size_t Len = 128; + while (true) { + VolumePath.resize(Len); + BOOL Success = + ::GetVolumePathNameW(Path.data(), VolumePath.data(), VolumePath.size()); + + if (Success) + break; + + DWORD Err = ::GetLastError(); + if (Err != ERROR_INSUFFICIENT_BUFFER) + return mapWindowsError(Err); + + Len *= 2; + } + // If the output buffer has exactly enough space for the path name, but not + // the null terminator, it will leave the output unterminated. Push a null + // terminator onto the end to ensure that this never happens. + VolumePath.push_back(L'\0'); + VolumePath.set_size(wcslen(VolumePath.data())); + const wchar_t *P = VolumePath.data(); + + UINT Type = ::GetDriveTypeW(P); + switch (Type) { + case DRIVE_FIXED: + Result = true; + return std::error_code(); + case DRIVE_REMOTE: + case DRIVE_CDROM: + case DRIVE_RAMDISK: + case DRIVE_REMOVABLE: + Result = false; + return std::error_code(); + default: + return make_error_code(errc::no_such_file_or_directory); + } + llvm_unreachable("Unreachable!"); +} + +std::error_code is_local(const Twine &path, bool &result) { + if (!llvm::sys::fs::exists(path) || !llvm::sys::path::has_root_path(path)) + return make_error_code(errc::no_such_file_or_directory); + + SmallString<128> Storage; + StringRef P = path.toStringRef(Storage); + + // Convert to utf-16. + SmallVector<wchar_t, 128> WidePath; + if (std::error_code ec = widenPath(P, WidePath)) + return ec; + return is_local_internal(WidePath, result); +} + +static std::error_code realPathFromHandle(HANDLE H, + SmallVectorImpl<wchar_t> &Buffer) { + DWORD CountChars = ::GetFinalPathNameByHandleW( + H, Buffer.begin(), Buffer.capacity(), FILE_NAME_NORMALIZED); + if (CountChars && CountChars >= Buffer.capacity()) { + // The buffer wasn't big enough, try again. In this case the return value + // *does* indicate the size of the null terminator. + Buffer.reserve(CountChars); + CountChars = ::GetFinalPathNameByHandleW( + H, Buffer.begin(), Buffer.capacity(), FILE_NAME_NORMALIZED); + } + if (CountChars == 0) + return mapWindowsError(GetLastError()); + Buffer.set_size(CountChars); + return std::error_code(); +} + +static std::error_code realPathFromHandle(HANDLE H, + SmallVectorImpl<char> &RealPath) { + RealPath.clear(); + SmallVector<wchar_t, MAX_PATH> Buffer; + if (std::error_code EC = realPathFromHandle(H, Buffer)) + return EC; + + // Strip the \\?\ prefix. We don't want it ending up in output, and such + // paths don't get canonicalized by file APIs. + wchar_t *Data = Buffer.data(); + DWORD CountChars = Buffer.size(); + if (CountChars >= 8 && ::memcmp(Data, L"\\\\?\\UNC\\", 16) == 0) { + // Convert \\?\UNC\foo\bar to \\foo\bar + CountChars -= 6; + Data += 6; + Data[0] = '\\'; + } else if (CountChars >= 4 && ::memcmp(Data, L"\\\\?\\", 8) == 0) { + // Convert \\?\c:\foo to c:\foo + CountChars -= 4; + Data += 4; + } + + // Convert the result from UTF-16 to UTF-8. + return UTF16ToUTF8(Data, CountChars, RealPath); +} + +std::error_code is_local(int FD, bool &Result) { + SmallVector<wchar_t, 128> FinalPath; + HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + + if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) + return EC; + + return is_local_internal(FinalPath, Result); +} + +static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { // Clear the FILE_DISPOSITION_INFO flag first, before checking if it's a // network file. On Windows 7 the function realPathFromHandle() below fails // if the FILE_DISPOSITION_INFO flag was already set to 'DeleteFile = true' by @@ -418,875 +418,875 @@ static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { // continue when DeleteFile is true, since it prevents opening the file for // writes. Note -- this will leak temporary files on disk, but only when the // target file is on a network drive. - SmallVector<wchar_t, 128> FinalPath; - if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) - return EC; - - bool IsLocal; - if (std::error_code EC = is_local_internal(FinalPath, IsLocal)) - return EC; - - if (!IsLocal) - return std::error_code(); - + SmallVector<wchar_t, 128> FinalPath; + if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) + return EC; + + bool IsLocal; + if (std::error_code EC = is_local_internal(FinalPath, IsLocal)) + return EC; + + if (!IsLocal) + return std::error_code(); + // The file is on a local drive, we can safely set FILE_DISPOSITION_INFO's // flag. Disposition.DeleteFile = true; - if (!SetFileInformationByHandle(Handle, FileDispositionInfo, &Disposition, - sizeof(Disposition))) - return mapWindowsError(::GetLastError()); - return std::error_code(); -} - -static std::error_code rename_internal(HANDLE FromHandle, const Twine &To, - bool ReplaceIfExists) { - SmallVector<wchar_t, 0> ToWide; - if (auto EC = widenPath(To, ToWide)) - return EC; - - std::vector<char> RenameInfoBuf(sizeof(FILE_RENAME_INFO) - sizeof(wchar_t) + - (ToWide.size() * sizeof(wchar_t))); - FILE_RENAME_INFO &RenameInfo = - *reinterpret_cast<FILE_RENAME_INFO *>(RenameInfoBuf.data()); - RenameInfo.ReplaceIfExists = ReplaceIfExists; - RenameInfo.RootDirectory = 0; - RenameInfo.FileNameLength = ToWide.size() * sizeof(wchar_t); - std::copy(ToWide.begin(), ToWide.end(), &RenameInfo.FileName[0]); - - SetLastError(ERROR_SUCCESS); - if (!SetFileInformationByHandle(FromHandle, FileRenameInfo, &RenameInfo, - RenameInfoBuf.size())) { - unsigned Error = GetLastError(); - if (Error == ERROR_SUCCESS) - Error = ERROR_CALL_NOT_IMPLEMENTED; // Wine doesn't always set error code. - return mapWindowsError(Error); - } - - return std::error_code(); -} - -static std::error_code rename_handle(HANDLE FromHandle, const Twine &To) { - SmallVector<wchar_t, 128> WideTo; - if (std::error_code EC = widenPath(To, WideTo)) - return EC; - - // We normally expect this loop to succeed after a few iterations. If it - // requires more than 200 tries, it's more likely that the failures are due to - // a true error, so stop trying. - for (unsigned Retry = 0; Retry != 200; ++Retry) { - auto EC = rename_internal(FromHandle, To, true); - - if (EC == - std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category())) { - // Wine doesn't support SetFileInformationByHandle in rename_internal. - // Fall back to MoveFileEx. - SmallVector<wchar_t, MAX_PATH> WideFrom; - if (std::error_code EC2 = realPathFromHandle(FromHandle, WideFrom)) - return EC2; - if (::MoveFileExW(WideFrom.begin(), WideTo.begin(), - MOVEFILE_REPLACE_EXISTING)) - return std::error_code(); - return mapWindowsError(GetLastError()); - } - - if (!EC || EC != errc::permission_denied) - return EC; - - // The destination file probably exists and is currently open in another - // process, either because the file was opened without FILE_SHARE_DELETE or - // it is mapped into memory (e.g. using MemoryBuffer). Rename it in order to - // move it out of the way of the source file. Use FILE_FLAG_DELETE_ON_CLOSE - // to arrange for the destination file to be deleted when the other process - // closes it. - ScopedFileHandle ToHandle( - ::CreateFileW(WideTo.begin(), GENERIC_READ | DELETE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)); - if (!ToHandle) { - auto EC = mapWindowsError(GetLastError()); - // Another process might have raced with us and moved the existing file - // out of the way before we had a chance to open it. If that happens, try - // to rename the source file again. - if (EC == errc::no_such_file_or_directory) - continue; - return EC; - } - - BY_HANDLE_FILE_INFORMATION FI; - if (!GetFileInformationByHandle(ToHandle, &FI)) - return mapWindowsError(GetLastError()); - - // Try to find a unique new name for the destination file. - for (unsigned UniqueId = 0; UniqueId != 200; ++UniqueId) { - std::string TmpFilename = (To + ".tmp" + utostr(UniqueId)).str(); - if (auto EC = rename_internal(ToHandle, TmpFilename, false)) { - if (EC == errc::file_exists || EC == errc::permission_denied) { - // Again, another process might have raced with us and moved the file - // before we could move it. Check whether this is the case, as it - // might have caused the permission denied error. If that was the - // case, we don't need to move it ourselves. - ScopedFileHandle ToHandle2(::CreateFileW( - WideTo.begin(), 0, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); - if (!ToHandle2) { - auto EC = mapWindowsError(GetLastError()); - if (EC == errc::no_such_file_or_directory) - break; - return EC; - } - BY_HANDLE_FILE_INFORMATION FI2; - if (!GetFileInformationByHandle(ToHandle2, &FI2)) - return mapWindowsError(GetLastError()); - if (FI.nFileIndexHigh != FI2.nFileIndexHigh || - FI.nFileIndexLow != FI2.nFileIndexLow || - FI.dwVolumeSerialNumber != FI2.dwVolumeSerialNumber) - break; - continue; - } - return EC; - } - break; - } - - // Okay, the old destination file has probably been moved out of the way at - // this point, so try to rename the source file again. Still, another - // process might have raced with us to create and open the destination - // file, so we need to keep doing this until we succeed. - } - - // The most likely root cause. - return errc::permission_denied; -} - -static std::error_code rename_fd(int FromFD, const Twine &To) { - HANDLE FromHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FromFD)); - return rename_handle(FromHandle, To); -} - -std::error_code rename(const Twine &From, const Twine &To) { - // Convert to utf-16. - SmallVector<wchar_t, 128> WideFrom; - if (std::error_code EC = widenPath(From, WideFrom)) - return EC; - - ScopedFileHandle FromHandle; - // Retry this a few times to defeat badly behaved file system scanners. - for (unsigned Retry = 0; Retry != 200; ++Retry) { - if (Retry != 0) - ::Sleep(10); - FromHandle = - ::CreateFileW(WideFrom.begin(), GENERIC_READ | DELETE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (FromHandle) - break; - - // We don't want to loop if the file doesn't exist. - auto EC = mapWindowsError(GetLastError()); - if (EC == errc::no_such_file_or_directory) - return EC; - } - if (!FromHandle) - return mapWindowsError(GetLastError()); - - return rename_handle(FromHandle, To); -} - -std::error_code resize_file(int FD, uint64_t Size) { -#ifdef HAVE__CHSIZE_S - errno_t error = ::_chsize_s(FD, Size); -#else - errno_t error = ::_chsize(FD, Size); -#endif - return std::error_code(error, std::generic_category()); -} - -std::error_code access(const Twine &Path, AccessMode Mode) { - SmallVector<wchar_t, 128> PathUtf16; - - if (std::error_code EC = widenPath(Path, PathUtf16)) - return EC; - - DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin()); - - if (Attributes == INVALID_FILE_ATTRIBUTES) { - // See if the file didn't actually exist. - DWORD LastError = ::GetLastError(); - if (LastError != ERROR_FILE_NOT_FOUND && - LastError != ERROR_PATH_NOT_FOUND) - return mapWindowsError(LastError); - return errc::no_such_file_or_directory; - } - - if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY)) - return errc::permission_denied; - - return std::error_code(); -} - -bool can_execute(const Twine &Path) { - return !access(Path, AccessMode::Execute) || - !access(Path + ".exe", AccessMode::Execute); -} - -bool equivalent(file_status A, file_status B) { - assert(status_known(A) && status_known(B)); - return A.FileIndexHigh == B.FileIndexHigh && - A.FileIndexLow == B.FileIndexLow && - A.FileSizeHigh == B.FileSizeHigh && - A.FileSizeLow == B.FileSizeLow && - A.LastAccessedTimeHigh == B.LastAccessedTimeHigh && - A.LastAccessedTimeLow == B.LastAccessedTimeLow && - A.LastWriteTimeHigh == B.LastWriteTimeHigh && - A.LastWriteTimeLow == B.LastWriteTimeLow && - A.VolumeSerialNumber == B.VolumeSerialNumber; -} - -std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { - file_status fsA, fsB; - if (std::error_code ec = status(A, fsA)) - return ec; - if (std::error_code ec = status(B, fsB)) - return ec; - result = equivalent(fsA, fsB); - return std::error_code(); -} - -static bool isReservedName(StringRef path) { - // This list of reserved names comes from MSDN, at: - // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx - static const char *const sReservedNames[] = { "nul", "con", "prn", "aux", - "com1", "com2", "com3", "com4", - "com5", "com6", "com7", "com8", - "com9", "lpt1", "lpt2", "lpt3", - "lpt4", "lpt5", "lpt6", "lpt7", - "lpt8", "lpt9" }; - - // First, check to see if this is a device namespace, which always - // starts with \\.\, since device namespaces are not legal file paths. - if (path.startswith("\\\\.\\")) - return true; - - // Then compare against the list of ancient reserved names. - for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) { - if (path.equals_lower(sReservedNames[i])) - return true; - } - - // The path isn't what we consider reserved. - return false; -} - -static file_type file_type_from_attrs(DWORD Attrs) { - return (Attrs & FILE_ATTRIBUTE_DIRECTORY) ? file_type::directory_file - : file_type::regular_file; -} - -static perms perms_from_attrs(DWORD Attrs) { - return (Attrs & FILE_ATTRIBUTE_READONLY) ? (all_read | all_exe) : all_all; -} - -static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { - if (FileHandle == INVALID_HANDLE_VALUE) - goto handle_status_error; - - switch (::GetFileType(FileHandle)) { - default: - llvm_unreachable("Don't know anything about this file type"); - case FILE_TYPE_UNKNOWN: { - DWORD Err = ::GetLastError(); - if (Err != NO_ERROR) - return mapWindowsError(Err); - Result = file_status(file_type::type_unknown); - return std::error_code(); - } - case FILE_TYPE_DISK: - break; - case FILE_TYPE_CHAR: - Result = file_status(file_type::character_file); - return std::error_code(); - case FILE_TYPE_PIPE: - Result = file_status(file_type::fifo_file); - return std::error_code(); - } - - BY_HANDLE_FILE_INFORMATION Info; - if (!::GetFileInformationByHandle(FileHandle, &Info)) - goto handle_status_error; - - Result = file_status( - file_type_from_attrs(Info.dwFileAttributes), - perms_from_attrs(Info.dwFileAttributes), Info.nNumberOfLinks, - Info.ftLastAccessTime.dwHighDateTime, Info.ftLastAccessTime.dwLowDateTime, - Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, - Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, - Info.nFileIndexHigh, Info.nFileIndexLow); - return std::error_code(); - -handle_status_error: - DWORD LastError = ::GetLastError(); - if (LastError == ERROR_FILE_NOT_FOUND || - LastError == ERROR_PATH_NOT_FOUND) - Result = file_status(file_type::file_not_found); - else if (LastError == ERROR_SHARING_VIOLATION) - Result = file_status(file_type::type_unknown); - else - Result = file_status(file_type::status_error); - return mapWindowsError(LastError); -} - -std::error_code status(const Twine &path, file_status &result, bool Follow) { - SmallString<128> path_storage; - SmallVector<wchar_t, 128> path_utf16; - - StringRef path8 = path.toStringRef(path_storage); - if (isReservedName(path8)) { - result = file_status(file_type::character_file); - return std::error_code(); - } - - if (std::error_code ec = widenPath(path8, path_utf16)) - return ec; - - DWORD attr = ::GetFileAttributesW(path_utf16.begin()); - if (attr == INVALID_FILE_ATTRIBUTES) - return getStatus(INVALID_HANDLE_VALUE, result); - - DWORD Flags = FILE_FLAG_BACKUP_SEMANTICS; - // Handle reparse points. - if (!Follow && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) - Flags |= FILE_FLAG_OPEN_REPARSE_POINT; - - ScopedFileHandle h( - ::CreateFileW(path_utf16.begin(), 0, // Attributes only. - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, Flags, 0)); - if (!h) - return getStatus(INVALID_HANDLE_VALUE, result); - - return getStatus(h, result); -} - -std::error_code status(int FD, file_status &Result) { - HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); - return getStatus(FileHandle, Result); -} - -std::error_code status(file_t FileHandle, file_status &Result) { - return getStatus(FileHandle, Result); -} - -unsigned getUmask() { - return 0; -} - -std::error_code setPermissions(const Twine &Path, perms Permissions) { - SmallVector<wchar_t, 128> PathUTF16; - if (std::error_code EC = widenPath(Path, PathUTF16)) - return EC; - - DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin()); - if (Attributes == INVALID_FILE_ATTRIBUTES) - return mapWindowsError(GetLastError()); - - // There are many Windows file attributes that are not to do with the file - // permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve - // them. - if (Permissions & all_write) { - Attributes &= ~FILE_ATTRIBUTE_READONLY; - if (Attributes == 0) - // FILE_ATTRIBUTE_NORMAL indicates no other attributes are set. - Attributes |= FILE_ATTRIBUTE_NORMAL; - } - else { - Attributes |= FILE_ATTRIBUTE_READONLY; - // FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so - // remove it, if it is present. - Attributes &= ~FILE_ATTRIBUTE_NORMAL; - } - - if (!::SetFileAttributesW(PathUTF16.begin(), Attributes)) - return mapWindowsError(GetLastError()); - - return std::error_code(); -} - -std::error_code setPermissions(int FD, perms Permissions) { - // FIXME Not implemented. - return std::make_error_code(std::errc::not_supported); -} - -std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, - TimePoint<> ModificationTime) { - FILETIME AccessFT = toFILETIME(AccessTime); - FILETIME ModifyFT = toFILETIME(ModificationTime); - HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); - if (!SetFileTime(FileHandle, NULL, &AccessFT, &ModifyFT)) - return mapWindowsError(::GetLastError()); - return std::error_code(); -} - -std::error_code mapped_file_region::init(sys::fs::file_t OrigFileHandle, - uint64_t Offset, mapmode Mode) { - this->Mode = Mode; - if (OrigFileHandle == INVALID_HANDLE_VALUE) - return make_error_code(errc::bad_file_descriptor); - - DWORD flprotect; - switch (Mode) { - case readonly: flprotect = PAGE_READONLY; break; - case readwrite: flprotect = PAGE_READWRITE; break; - case priv: flprotect = PAGE_WRITECOPY; break; - } - - HANDLE FileMappingHandle = - ::CreateFileMappingW(OrigFileHandle, 0, flprotect, - Hi_32(Size), - Lo_32(Size), - 0); - if (FileMappingHandle == NULL) { - std::error_code ec = mapWindowsError(GetLastError()); - return ec; - } - - DWORD dwDesiredAccess; - switch (Mode) { - case readonly: dwDesiredAccess = FILE_MAP_READ; break; - case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break; - case priv: dwDesiredAccess = FILE_MAP_COPY; break; - } - Mapping = ::MapViewOfFile(FileMappingHandle, - dwDesiredAccess, - Offset >> 32, - Offset & 0xffffffff, - Size); - if (Mapping == NULL) { - std::error_code ec = mapWindowsError(GetLastError()); - ::CloseHandle(FileMappingHandle); - return ec; - } - - if (Size == 0) { - MEMORY_BASIC_INFORMATION mbi; - SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); - if (Result == 0) { - std::error_code ec = mapWindowsError(GetLastError()); - ::UnmapViewOfFile(Mapping); - ::CloseHandle(FileMappingHandle); - return ec; - } - Size = mbi.RegionSize; - } - - // Close the file mapping handle, as it's kept alive by the file mapping. But - // neither the file mapping nor the file mapping handle keep the file handle - // alive, so we need to keep a reference to the file in case all other handles - // are closed and the file is deleted, which may cause invalid data to be read - // from the file. - ::CloseHandle(FileMappingHandle); - if (!::DuplicateHandle(::GetCurrentProcess(), OrigFileHandle, - ::GetCurrentProcess(), &FileHandle, 0, 0, - DUPLICATE_SAME_ACCESS)) { - std::error_code ec = mapWindowsError(GetLastError()); - ::UnmapViewOfFile(Mapping); - return ec; - } - - return std::error_code(); -} - -mapped_file_region::mapped_file_region(sys::fs::file_t fd, mapmode mode, - size_t length, uint64_t offset, - std::error_code &ec) - : Size(length), Mapping() { - ec = init(fd, offset, mode); - if (ec) - Mapping = 0; -} - -static bool hasFlushBufferKernelBug() { - static bool Ret{GetWindowsOSVersion() < llvm::VersionTuple(10, 0, 0, 17763)}; - return Ret; -} - -static bool isEXE(StringRef Magic) { - static const char PEMagic[] = {'P', 'E', '\0', '\0'}; - if (Magic.startswith(StringRef("MZ")) && Magic.size() >= 0x3c + 4) { - uint32_t off = read32le(Magic.data() + 0x3c); - // PE/COFF file, either EXE or DLL. - if (Magic.substr(off).startswith(StringRef(PEMagic, sizeof(PEMagic)))) - return true; - } - return false; -} - -mapped_file_region::~mapped_file_region() { - if (Mapping) { - - bool Exe = isEXE(StringRef((char *)Mapping, Size)); - - ::UnmapViewOfFile(Mapping); - - if (Mode == mapmode::readwrite && Exe && hasFlushBufferKernelBug()) { - // There is a Windows kernel bug, the exact trigger conditions of which - // are not well understood. When triggered, dirty pages are not properly - // flushed and subsequent process's attempts to read a file can return - // invalid data. Calling FlushFileBuffers on the write handle is - // sufficient to ensure that this bug is not triggered. - // The bug only occurs when writing an executable and executing it right - // after, under high I/O pressure. - ::FlushFileBuffers(FileHandle); - } - - ::CloseHandle(FileHandle); - } -} - -size_t mapped_file_region::size() const { - assert(Mapping && "Mapping failed but used anyway!"); - return Size; -} - -char *mapped_file_region::data() const { - assert(Mapping && "Mapping failed but used anyway!"); - return reinterpret_cast<char*>(Mapping); -} - -const char *mapped_file_region::const_data() const { - assert(Mapping && "Mapping failed but used anyway!"); - return reinterpret_cast<const char*>(Mapping); -} - -int mapped_file_region::alignment() { - SYSTEM_INFO SysInfo; - ::GetSystemInfo(&SysInfo); - return SysInfo.dwAllocationGranularity; -} - -static basic_file_status status_from_find_data(WIN32_FIND_DATAW *FindData) { - return basic_file_status(file_type_from_attrs(FindData->dwFileAttributes), - perms_from_attrs(FindData->dwFileAttributes), - FindData->ftLastAccessTime.dwHighDateTime, - FindData->ftLastAccessTime.dwLowDateTime, - FindData->ftLastWriteTime.dwHighDateTime, - FindData->ftLastWriteTime.dwLowDateTime, - FindData->nFileSizeHigh, FindData->nFileSizeLow); -} - -std::error_code detail::directory_iterator_construct(detail::DirIterState &IT, - StringRef Path, - bool FollowSymlinks) { - SmallVector<wchar_t, 128> PathUTF16; - - if (std::error_code EC = widenPath(Path, PathUTF16)) - return EC; - - // Convert path to the format that Windows is happy with. - size_t PathUTF16Len = PathUTF16.size(); - if (PathUTF16Len > 0 && !is_separator(PathUTF16[PathUTF16Len - 1]) && - PathUTF16[PathUTF16Len - 1] != L':') { - PathUTF16.push_back(L'\\'); - PathUTF16.push_back(L'*'); - } else { - PathUTF16.push_back(L'*'); - } - - // Get the first directory entry. - WIN32_FIND_DATAW FirstFind; - ScopedFindHandle FindHandle(::FindFirstFileExW( - c_str(PathUTF16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch, - NULL, FIND_FIRST_EX_LARGE_FETCH)); - if (!FindHandle) - return mapWindowsError(::GetLastError()); - - size_t FilenameLen = ::wcslen(FirstFind.cFileName); - while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || - (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && - FirstFind.cFileName[1] == L'.')) - if (!::FindNextFileW(FindHandle, &FirstFind)) { - DWORD LastError = ::GetLastError(); - // Check for end. - if (LastError == ERROR_NO_MORE_FILES) - return detail::directory_iterator_destruct(IT); - return mapWindowsError(LastError); - } else - FilenameLen = ::wcslen(FirstFind.cFileName); - - // Construct the current directory entry. - SmallString<128> DirectoryEntryNameUTF8; - if (std::error_code EC = - UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName), - DirectoryEntryNameUTF8)) - return EC; - - IT.IterationHandle = intptr_t(FindHandle.take()); - SmallString<128> DirectoryEntryPath(Path); - path::append(DirectoryEntryPath, DirectoryEntryNameUTF8); - IT.CurrentEntry = - directory_entry(DirectoryEntryPath, FollowSymlinks, - file_type_from_attrs(FirstFind.dwFileAttributes), - status_from_find_data(&FirstFind)); - - return std::error_code(); -} - -std::error_code detail::directory_iterator_destruct(detail::DirIterState &IT) { - if (IT.IterationHandle != 0) - // Closes the handle if it's valid. - ScopedFindHandle close(HANDLE(IT.IterationHandle)); - IT.IterationHandle = 0; - IT.CurrentEntry = directory_entry(); - return std::error_code(); -} - -std::error_code detail::directory_iterator_increment(detail::DirIterState &IT) { - WIN32_FIND_DATAW FindData; - if (!::FindNextFileW(HANDLE(IT.IterationHandle), &FindData)) { - DWORD LastError = ::GetLastError(); - // Check for end. - if (LastError == ERROR_NO_MORE_FILES) - return detail::directory_iterator_destruct(IT); - return mapWindowsError(LastError); - } - - size_t FilenameLen = ::wcslen(FindData.cFileName); - if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || - (FilenameLen == 2 && FindData.cFileName[0] == L'.' && - FindData.cFileName[1] == L'.')) - return directory_iterator_increment(IT); - - SmallString<128> DirectoryEntryPathUTF8; - if (std::error_code EC = - UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName), - DirectoryEntryPathUTF8)) - return EC; - - IT.CurrentEntry.replace_filename( - Twine(DirectoryEntryPathUTF8), - file_type_from_attrs(FindData.dwFileAttributes), - status_from_find_data(&FindData)); - return std::error_code(); -} - -ErrorOr<basic_file_status> directory_entry::status() const { - return Status; -} - -static std::error_code nativeFileToFd(Expected<HANDLE> H, int &ResultFD, - OpenFlags Flags) { - int CrtOpenFlags = 0; - if (Flags & OF_Append) - CrtOpenFlags |= _O_APPEND; - - if (Flags & OF_Text) - CrtOpenFlags |= _O_TEXT; - - ResultFD = -1; - if (!H) - return errorToErrorCode(H.takeError()); - - ResultFD = ::_open_osfhandle(intptr_t(*H), CrtOpenFlags); - if (ResultFD == -1) { - ::CloseHandle(*H); - return mapWindowsError(ERROR_INVALID_HANDLE); - } - return std::error_code(); -} - -static DWORD nativeDisposition(CreationDisposition Disp, OpenFlags Flags) { - // This is a compatibility hack. Really we should respect the creation - // disposition, but a lot of old code relied on the implicit assumption that - // OF_Append implied it would open an existing file. Since the disposition is - // now explicit and defaults to CD_CreateAlways, this assumption would cause - // any usage of OF_Append to append to a new file, even if the file already - // existed. A better solution might have two new creation dispositions: - // CD_AppendAlways and CD_AppendNew. This would also address the problem of - // OF_Append being used on a read-only descriptor, which doesn't make sense. - if (Flags & OF_Append) - return OPEN_ALWAYS; - - switch (Disp) { - case CD_CreateAlways: - return CREATE_ALWAYS; - case CD_CreateNew: - return CREATE_NEW; - case CD_OpenAlways: - return OPEN_ALWAYS; - case CD_OpenExisting: - return OPEN_EXISTING; - } - llvm_unreachable("unreachable!"); -} - -static DWORD nativeAccess(FileAccess Access, OpenFlags Flags) { - DWORD Result = 0; - if (Access & FA_Read) - Result |= GENERIC_READ; - if (Access & FA_Write) - Result |= GENERIC_WRITE; - if (Flags & OF_Delete) - Result |= DELETE; - if (Flags & OF_UpdateAtime) - Result |= FILE_WRITE_ATTRIBUTES; - return Result; -} - -static std::error_code openNativeFileInternal(const Twine &Name, - file_t &ResultFile, DWORD Disp, - DWORD Access, DWORD Flags, - bool Inherit = false) { - SmallVector<wchar_t, 128> PathUTF16; - if (std::error_code EC = widenPath(Name, PathUTF16)) - return EC; - - SECURITY_ATTRIBUTES SA; - SA.nLength = sizeof(SA); - SA.lpSecurityDescriptor = nullptr; - SA.bInheritHandle = Inherit; - - HANDLE H = - ::CreateFileW(PathUTF16.begin(), Access, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &SA, - Disp, Flags, NULL); - if (H == INVALID_HANDLE_VALUE) { - DWORD LastError = ::GetLastError(); - std::error_code EC = mapWindowsError(LastError); - // Provide a better error message when trying to open directories. - // This only runs if we failed to open the file, so there is probably - // no performances issues. - if (LastError != ERROR_ACCESS_DENIED) - return EC; - if (is_directory(Name)) - return make_error_code(errc::is_a_directory); - return EC; - } - ResultFile = H; - return std::error_code(); -} - -Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp, - FileAccess Access, OpenFlags Flags, - unsigned Mode) { - // Verify that we don't have both "append" and "excl". - assert((!(Disp == CD_CreateNew) || !(Flags & OF_Append)) && - "Cannot specify both 'CreateNew' and 'Append' file creation flags!"); - - DWORD NativeDisp = nativeDisposition(Disp, Flags); - DWORD NativeAccess = nativeAccess(Access, Flags); - - bool Inherit = false; - if (Flags & OF_ChildInherit) - Inherit = true; - - file_t Result; - std::error_code EC = openNativeFileInternal( - Name, Result, NativeDisp, NativeAccess, FILE_ATTRIBUTE_NORMAL, Inherit); - if (EC) - return errorCodeToError(EC); - - if (Flags & OF_UpdateAtime) { - FILETIME FileTime; - SYSTEMTIME SystemTime; - GetSystemTime(&SystemTime); - if (SystemTimeToFileTime(&SystemTime, &FileTime) == 0 || - SetFileTime(Result, NULL, &FileTime, NULL) == 0) { - DWORD LastError = ::GetLastError(); - ::CloseHandle(Result); - return errorCodeToError(mapWindowsError(LastError)); - } - } - - if (Flags & OF_Delete) { - if ((EC = setDeleteDisposition(Result, true))) { - ::CloseHandle(Result); - return errorCodeToError(EC); - } - } - return Result; -} - -std::error_code openFile(const Twine &Name, int &ResultFD, - CreationDisposition Disp, FileAccess Access, - OpenFlags Flags, unsigned int Mode) { - Expected<file_t> Result = openNativeFile(Name, Disp, Access, Flags); - if (!Result) - return errorToErrorCode(Result.takeError()); - - return nativeFileToFd(*Result, ResultFD, Flags); -} - -static std::error_code directoryRealPath(const Twine &Name, - SmallVectorImpl<char> &RealPath) { - file_t File; - std::error_code EC = openNativeFileInternal( - Name, File, OPEN_EXISTING, GENERIC_READ, FILE_FLAG_BACKUP_SEMANTICS); - if (EC) - return EC; - - EC = realPathFromHandle(File, RealPath); - ::CloseHandle(File); - return EC; -} - -std::error_code openFileForRead(const Twine &Name, int &ResultFD, - OpenFlags Flags, - SmallVectorImpl<char> *RealPath) { - Expected<HANDLE> NativeFile = openNativeFileForRead(Name, Flags, RealPath); - return nativeFileToFd(std::move(NativeFile), ResultFD, OF_None); -} - -Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags, - SmallVectorImpl<char> *RealPath) { - Expected<file_t> Result = - openNativeFile(Name, CD_OpenExisting, FA_Read, Flags); - - // Fetch the real name of the file, if the user asked - if (Result && RealPath) - realPathFromHandle(*Result, *RealPath); - - return Result; -} - -file_t convertFDToNativeFile(int FD) { - return reinterpret_cast<HANDLE>(::_get_osfhandle(FD)); -} - -file_t getStdinHandle() { return ::GetStdHandle(STD_INPUT_HANDLE); } -file_t getStdoutHandle() { return ::GetStdHandle(STD_OUTPUT_HANDLE); } -file_t getStderrHandle() { return ::GetStdHandle(STD_ERROR_HANDLE); } - -Expected<size_t> readNativeFileImpl(file_t FileHandle, - MutableArrayRef<char> Buf, - OVERLAPPED *Overlap) { - // ReadFile can only read 2GB at a time. The caller should check the number of - // bytes and read in a loop until termination. - DWORD BytesToRead = - std::min(size_t(std::numeric_limits<DWORD>::max()), Buf.size()); - DWORD BytesRead = 0; - if (::ReadFile(FileHandle, Buf.data(), BytesToRead, &BytesRead, Overlap)) - return BytesRead; - DWORD Err = ::GetLastError(); - // EOF is not an error. - if (Err == ERROR_BROKEN_PIPE || Err == ERROR_HANDLE_EOF) - return BytesRead; - return errorCodeToError(mapWindowsError(Err)); -} - -Expected<size_t> readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf) { - return readNativeFileImpl(FileHandle, Buf, /*Overlap=*/nullptr); -} - -Expected<size_t> readNativeFileSlice(file_t FileHandle, - MutableArrayRef<char> Buf, - uint64_t Offset) { - OVERLAPPED Overlapped = {}; - Overlapped.Offset = uint32_t(Offset); - Overlapped.OffsetHigh = uint32_t(Offset >> 32); - return readNativeFileImpl(FileHandle, Buf, &Overlapped); -} - + if (!SetFileInformationByHandle(Handle, FileDispositionInfo, &Disposition, + sizeof(Disposition))) + return mapWindowsError(::GetLastError()); + return std::error_code(); +} + +static std::error_code rename_internal(HANDLE FromHandle, const Twine &To, + bool ReplaceIfExists) { + SmallVector<wchar_t, 0> ToWide; + if (auto EC = widenPath(To, ToWide)) + return EC; + + std::vector<char> RenameInfoBuf(sizeof(FILE_RENAME_INFO) - sizeof(wchar_t) + + (ToWide.size() * sizeof(wchar_t))); + FILE_RENAME_INFO &RenameInfo = + *reinterpret_cast<FILE_RENAME_INFO *>(RenameInfoBuf.data()); + RenameInfo.ReplaceIfExists = ReplaceIfExists; + RenameInfo.RootDirectory = 0; + RenameInfo.FileNameLength = ToWide.size() * sizeof(wchar_t); + std::copy(ToWide.begin(), ToWide.end(), &RenameInfo.FileName[0]); + + SetLastError(ERROR_SUCCESS); + if (!SetFileInformationByHandle(FromHandle, FileRenameInfo, &RenameInfo, + RenameInfoBuf.size())) { + unsigned Error = GetLastError(); + if (Error == ERROR_SUCCESS) + Error = ERROR_CALL_NOT_IMPLEMENTED; // Wine doesn't always set error code. + return mapWindowsError(Error); + } + + return std::error_code(); +} + +static std::error_code rename_handle(HANDLE FromHandle, const Twine &To) { + SmallVector<wchar_t, 128> WideTo; + if (std::error_code EC = widenPath(To, WideTo)) + return EC; + + // We normally expect this loop to succeed after a few iterations. If it + // requires more than 200 tries, it's more likely that the failures are due to + // a true error, so stop trying. + for (unsigned Retry = 0; Retry != 200; ++Retry) { + auto EC = rename_internal(FromHandle, To, true); + + if (EC == + std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category())) { + // Wine doesn't support SetFileInformationByHandle in rename_internal. + // Fall back to MoveFileEx. + SmallVector<wchar_t, MAX_PATH> WideFrom; + if (std::error_code EC2 = realPathFromHandle(FromHandle, WideFrom)) + return EC2; + if (::MoveFileExW(WideFrom.begin(), WideTo.begin(), + MOVEFILE_REPLACE_EXISTING)) + return std::error_code(); + return mapWindowsError(GetLastError()); + } + + if (!EC || EC != errc::permission_denied) + return EC; + + // The destination file probably exists and is currently open in another + // process, either because the file was opened without FILE_SHARE_DELETE or + // it is mapped into memory (e.g. using MemoryBuffer). Rename it in order to + // move it out of the way of the source file. Use FILE_FLAG_DELETE_ON_CLOSE + // to arrange for the destination file to be deleted when the other process + // closes it. + ScopedFileHandle ToHandle( + ::CreateFileW(WideTo.begin(), GENERIC_READ | DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)); + if (!ToHandle) { + auto EC = mapWindowsError(GetLastError()); + // Another process might have raced with us and moved the existing file + // out of the way before we had a chance to open it. If that happens, try + // to rename the source file again. + if (EC == errc::no_such_file_or_directory) + continue; + return EC; + } + + BY_HANDLE_FILE_INFORMATION FI; + if (!GetFileInformationByHandle(ToHandle, &FI)) + return mapWindowsError(GetLastError()); + + // Try to find a unique new name for the destination file. + for (unsigned UniqueId = 0; UniqueId != 200; ++UniqueId) { + std::string TmpFilename = (To + ".tmp" + utostr(UniqueId)).str(); + if (auto EC = rename_internal(ToHandle, TmpFilename, false)) { + if (EC == errc::file_exists || EC == errc::permission_denied) { + // Again, another process might have raced with us and moved the file + // before we could move it. Check whether this is the case, as it + // might have caused the permission denied error. If that was the + // case, we don't need to move it ourselves. + ScopedFileHandle ToHandle2(::CreateFileW( + WideTo.begin(), 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); + if (!ToHandle2) { + auto EC = mapWindowsError(GetLastError()); + if (EC == errc::no_such_file_or_directory) + break; + return EC; + } + BY_HANDLE_FILE_INFORMATION FI2; + if (!GetFileInformationByHandle(ToHandle2, &FI2)) + return mapWindowsError(GetLastError()); + if (FI.nFileIndexHigh != FI2.nFileIndexHigh || + FI.nFileIndexLow != FI2.nFileIndexLow || + FI.dwVolumeSerialNumber != FI2.dwVolumeSerialNumber) + break; + continue; + } + return EC; + } + break; + } + + // Okay, the old destination file has probably been moved out of the way at + // this point, so try to rename the source file again. Still, another + // process might have raced with us to create and open the destination + // file, so we need to keep doing this until we succeed. + } + + // The most likely root cause. + return errc::permission_denied; +} + +static std::error_code rename_fd(int FromFD, const Twine &To) { + HANDLE FromHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FromFD)); + return rename_handle(FromHandle, To); +} + +std::error_code rename(const Twine &From, const Twine &To) { + // Convert to utf-16. + SmallVector<wchar_t, 128> WideFrom; + if (std::error_code EC = widenPath(From, WideFrom)) + return EC; + + ScopedFileHandle FromHandle; + // Retry this a few times to defeat badly behaved file system scanners. + for (unsigned Retry = 0; Retry != 200; ++Retry) { + if (Retry != 0) + ::Sleep(10); + FromHandle = + ::CreateFileW(WideFrom.begin(), GENERIC_READ | DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (FromHandle) + break; + + // We don't want to loop if the file doesn't exist. + auto EC = mapWindowsError(GetLastError()); + if (EC == errc::no_such_file_or_directory) + return EC; + } + if (!FromHandle) + return mapWindowsError(GetLastError()); + + return rename_handle(FromHandle, To); +} + +std::error_code resize_file(int FD, uint64_t Size) { +#ifdef HAVE__CHSIZE_S + errno_t error = ::_chsize_s(FD, Size); +#else + errno_t error = ::_chsize(FD, Size); +#endif + return std::error_code(error, std::generic_category()); +} + +std::error_code access(const Twine &Path, AccessMode Mode) { + SmallVector<wchar_t, 128> PathUtf16; + + if (std::error_code EC = widenPath(Path, PathUtf16)) + return EC; + + DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin()); + + if (Attributes == INVALID_FILE_ATTRIBUTES) { + // See if the file didn't actually exist. + DWORD LastError = ::GetLastError(); + if (LastError != ERROR_FILE_NOT_FOUND && + LastError != ERROR_PATH_NOT_FOUND) + return mapWindowsError(LastError); + return errc::no_such_file_or_directory; + } + + if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY)) + return errc::permission_denied; + + return std::error_code(); +} + +bool can_execute(const Twine &Path) { + return !access(Path, AccessMode::Execute) || + !access(Path + ".exe", AccessMode::Execute); +} + +bool equivalent(file_status A, file_status B) { + assert(status_known(A) && status_known(B)); + return A.FileIndexHigh == B.FileIndexHigh && + A.FileIndexLow == B.FileIndexLow && + A.FileSizeHigh == B.FileSizeHigh && + A.FileSizeLow == B.FileSizeLow && + A.LastAccessedTimeHigh == B.LastAccessedTimeHigh && + A.LastAccessedTimeLow == B.LastAccessedTimeLow && + A.LastWriteTimeHigh == B.LastWriteTimeHigh && + A.LastWriteTimeLow == B.LastWriteTimeLow && + A.VolumeSerialNumber == B.VolumeSerialNumber; +} + +std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { + file_status fsA, fsB; + if (std::error_code ec = status(A, fsA)) + return ec; + if (std::error_code ec = status(B, fsB)) + return ec; + result = equivalent(fsA, fsB); + return std::error_code(); +} + +static bool isReservedName(StringRef path) { + // This list of reserved names comes from MSDN, at: + // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx + static const char *const sReservedNames[] = { "nul", "con", "prn", "aux", + "com1", "com2", "com3", "com4", + "com5", "com6", "com7", "com8", + "com9", "lpt1", "lpt2", "lpt3", + "lpt4", "lpt5", "lpt6", "lpt7", + "lpt8", "lpt9" }; + + // First, check to see if this is a device namespace, which always + // starts with \\.\, since device namespaces are not legal file paths. + if (path.startswith("\\\\.\\")) + return true; + + // Then compare against the list of ancient reserved names. + for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) { + if (path.equals_lower(sReservedNames[i])) + return true; + } + + // The path isn't what we consider reserved. + return false; +} + +static file_type file_type_from_attrs(DWORD Attrs) { + return (Attrs & FILE_ATTRIBUTE_DIRECTORY) ? file_type::directory_file + : file_type::regular_file; +} + +static perms perms_from_attrs(DWORD Attrs) { + return (Attrs & FILE_ATTRIBUTE_READONLY) ? (all_read | all_exe) : all_all; +} + +static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { + if (FileHandle == INVALID_HANDLE_VALUE) + goto handle_status_error; + + switch (::GetFileType(FileHandle)) { + default: + llvm_unreachable("Don't know anything about this file type"); + case FILE_TYPE_UNKNOWN: { + DWORD Err = ::GetLastError(); + if (Err != NO_ERROR) + return mapWindowsError(Err); + Result = file_status(file_type::type_unknown); + return std::error_code(); + } + case FILE_TYPE_DISK: + break; + case FILE_TYPE_CHAR: + Result = file_status(file_type::character_file); + return std::error_code(); + case FILE_TYPE_PIPE: + Result = file_status(file_type::fifo_file); + return std::error_code(); + } + + BY_HANDLE_FILE_INFORMATION Info; + if (!::GetFileInformationByHandle(FileHandle, &Info)) + goto handle_status_error; + + Result = file_status( + file_type_from_attrs(Info.dwFileAttributes), + perms_from_attrs(Info.dwFileAttributes), Info.nNumberOfLinks, + Info.ftLastAccessTime.dwHighDateTime, Info.ftLastAccessTime.dwLowDateTime, + Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, + Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, + Info.nFileIndexHigh, Info.nFileIndexLow); + return std::error_code(); + +handle_status_error: + DWORD LastError = ::GetLastError(); + if (LastError == ERROR_FILE_NOT_FOUND || + LastError == ERROR_PATH_NOT_FOUND) + Result = file_status(file_type::file_not_found); + else if (LastError == ERROR_SHARING_VIOLATION) + Result = file_status(file_type::type_unknown); + else + Result = file_status(file_type::status_error); + return mapWindowsError(LastError); +} + +std::error_code status(const Twine &path, file_status &result, bool Follow) { + SmallString<128> path_storage; + SmallVector<wchar_t, 128> path_utf16; + + StringRef path8 = path.toStringRef(path_storage); + if (isReservedName(path8)) { + result = file_status(file_type::character_file); + return std::error_code(); + } + + if (std::error_code ec = widenPath(path8, path_utf16)) + return ec; + + DWORD attr = ::GetFileAttributesW(path_utf16.begin()); + if (attr == INVALID_FILE_ATTRIBUTES) + return getStatus(INVALID_HANDLE_VALUE, result); + + DWORD Flags = FILE_FLAG_BACKUP_SEMANTICS; + // Handle reparse points. + if (!Follow && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) + Flags |= FILE_FLAG_OPEN_REPARSE_POINT; + + ScopedFileHandle h( + ::CreateFileW(path_utf16.begin(), 0, // Attributes only. + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, Flags, 0)); + if (!h) + return getStatus(INVALID_HANDLE_VALUE, result); + + return getStatus(h, result); +} + +std::error_code status(int FD, file_status &Result) { + HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + return getStatus(FileHandle, Result); +} + +std::error_code status(file_t FileHandle, file_status &Result) { + return getStatus(FileHandle, Result); +} + +unsigned getUmask() { + return 0; +} + +std::error_code setPermissions(const Twine &Path, perms Permissions) { + SmallVector<wchar_t, 128> PathUTF16; + if (std::error_code EC = widenPath(Path, PathUTF16)) + return EC; + + DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin()); + if (Attributes == INVALID_FILE_ATTRIBUTES) + return mapWindowsError(GetLastError()); + + // There are many Windows file attributes that are not to do with the file + // permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve + // them. + if (Permissions & all_write) { + Attributes &= ~FILE_ATTRIBUTE_READONLY; + if (Attributes == 0) + // FILE_ATTRIBUTE_NORMAL indicates no other attributes are set. + Attributes |= FILE_ATTRIBUTE_NORMAL; + } + else { + Attributes |= FILE_ATTRIBUTE_READONLY; + // FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so + // remove it, if it is present. + Attributes &= ~FILE_ATTRIBUTE_NORMAL; + } + + if (!::SetFileAttributesW(PathUTF16.begin(), Attributes)) + return mapWindowsError(GetLastError()); + + return std::error_code(); +} + +std::error_code setPermissions(int FD, perms Permissions) { + // FIXME Not implemented. + return std::make_error_code(std::errc::not_supported); +} + +std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, + TimePoint<> ModificationTime) { + FILETIME AccessFT = toFILETIME(AccessTime); + FILETIME ModifyFT = toFILETIME(ModificationTime); + HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + if (!SetFileTime(FileHandle, NULL, &AccessFT, &ModifyFT)) + return mapWindowsError(::GetLastError()); + return std::error_code(); +} + +std::error_code mapped_file_region::init(sys::fs::file_t OrigFileHandle, + uint64_t Offset, mapmode Mode) { + this->Mode = Mode; + if (OrigFileHandle == INVALID_HANDLE_VALUE) + return make_error_code(errc::bad_file_descriptor); + + DWORD flprotect; + switch (Mode) { + case readonly: flprotect = PAGE_READONLY; break; + case readwrite: flprotect = PAGE_READWRITE; break; + case priv: flprotect = PAGE_WRITECOPY; break; + } + + HANDLE FileMappingHandle = + ::CreateFileMappingW(OrigFileHandle, 0, flprotect, + Hi_32(Size), + Lo_32(Size), + 0); + if (FileMappingHandle == NULL) { + std::error_code ec = mapWindowsError(GetLastError()); + return ec; + } + + DWORD dwDesiredAccess; + switch (Mode) { + case readonly: dwDesiredAccess = FILE_MAP_READ; break; + case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break; + case priv: dwDesiredAccess = FILE_MAP_COPY; break; + } + Mapping = ::MapViewOfFile(FileMappingHandle, + dwDesiredAccess, + Offset >> 32, + Offset & 0xffffffff, + Size); + if (Mapping == NULL) { + std::error_code ec = mapWindowsError(GetLastError()); + ::CloseHandle(FileMappingHandle); + return ec; + } + + if (Size == 0) { + MEMORY_BASIC_INFORMATION mbi; + SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); + if (Result == 0) { + std::error_code ec = mapWindowsError(GetLastError()); + ::UnmapViewOfFile(Mapping); + ::CloseHandle(FileMappingHandle); + return ec; + } + Size = mbi.RegionSize; + } + + // Close the file mapping handle, as it's kept alive by the file mapping. But + // neither the file mapping nor the file mapping handle keep the file handle + // alive, so we need to keep a reference to the file in case all other handles + // are closed and the file is deleted, which may cause invalid data to be read + // from the file. + ::CloseHandle(FileMappingHandle); + if (!::DuplicateHandle(::GetCurrentProcess(), OrigFileHandle, + ::GetCurrentProcess(), &FileHandle, 0, 0, + DUPLICATE_SAME_ACCESS)) { + std::error_code ec = mapWindowsError(GetLastError()); + ::UnmapViewOfFile(Mapping); + return ec; + } + + return std::error_code(); +} + +mapped_file_region::mapped_file_region(sys::fs::file_t fd, mapmode mode, + size_t length, uint64_t offset, + std::error_code &ec) + : Size(length), Mapping() { + ec = init(fd, offset, mode); + if (ec) + Mapping = 0; +} + +static bool hasFlushBufferKernelBug() { + static bool Ret{GetWindowsOSVersion() < llvm::VersionTuple(10, 0, 0, 17763)}; + return Ret; +} + +static bool isEXE(StringRef Magic) { + static const char PEMagic[] = {'P', 'E', '\0', '\0'}; + if (Magic.startswith(StringRef("MZ")) && Magic.size() >= 0x3c + 4) { + uint32_t off = read32le(Magic.data() + 0x3c); + // PE/COFF file, either EXE or DLL. + if (Magic.substr(off).startswith(StringRef(PEMagic, sizeof(PEMagic)))) + return true; + } + return false; +} + +mapped_file_region::~mapped_file_region() { + if (Mapping) { + + bool Exe = isEXE(StringRef((char *)Mapping, Size)); + + ::UnmapViewOfFile(Mapping); + + if (Mode == mapmode::readwrite && Exe && hasFlushBufferKernelBug()) { + // There is a Windows kernel bug, the exact trigger conditions of which + // are not well understood. When triggered, dirty pages are not properly + // flushed and subsequent process's attempts to read a file can return + // invalid data. Calling FlushFileBuffers on the write handle is + // sufficient to ensure that this bug is not triggered. + // The bug only occurs when writing an executable and executing it right + // after, under high I/O pressure. + ::FlushFileBuffers(FileHandle); + } + + ::CloseHandle(FileHandle); + } +} + +size_t mapped_file_region::size() const { + assert(Mapping && "Mapping failed but used anyway!"); + return Size; +} + +char *mapped_file_region::data() const { + assert(Mapping && "Mapping failed but used anyway!"); + return reinterpret_cast<char*>(Mapping); +} + +const char *mapped_file_region::const_data() const { + assert(Mapping && "Mapping failed but used anyway!"); + return reinterpret_cast<const char*>(Mapping); +} + +int mapped_file_region::alignment() { + SYSTEM_INFO SysInfo; + ::GetSystemInfo(&SysInfo); + return SysInfo.dwAllocationGranularity; +} + +static basic_file_status status_from_find_data(WIN32_FIND_DATAW *FindData) { + return basic_file_status(file_type_from_attrs(FindData->dwFileAttributes), + perms_from_attrs(FindData->dwFileAttributes), + FindData->ftLastAccessTime.dwHighDateTime, + FindData->ftLastAccessTime.dwLowDateTime, + FindData->ftLastWriteTime.dwHighDateTime, + FindData->ftLastWriteTime.dwLowDateTime, + FindData->nFileSizeHigh, FindData->nFileSizeLow); +} + +std::error_code detail::directory_iterator_construct(detail::DirIterState &IT, + StringRef Path, + bool FollowSymlinks) { + SmallVector<wchar_t, 128> PathUTF16; + + if (std::error_code EC = widenPath(Path, PathUTF16)) + return EC; + + // Convert path to the format that Windows is happy with. + size_t PathUTF16Len = PathUTF16.size(); + if (PathUTF16Len > 0 && !is_separator(PathUTF16[PathUTF16Len - 1]) && + PathUTF16[PathUTF16Len - 1] != L':') { + PathUTF16.push_back(L'\\'); + PathUTF16.push_back(L'*'); + } else { + PathUTF16.push_back(L'*'); + } + + // Get the first directory entry. + WIN32_FIND_DATAW FirstFind; + ScopedFindHandle FindHandle(::FindFirstFileExW( + c_str(PathUTF16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch, + NULL, FIND_FIRST_EX_LARGE_FETCH)); + if (!FindHandle) + return mapWindowsError(::GetLastError()); + + size_t FilenameLen = ::wcslen(FirstFind.cFileName); + while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || + (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && + FirstFind.cFileName[1] == L'.')) + if (!::FindNextFileW(FindHandle, &FirstFind)) { + DWORD LastError = ::GetLastError(); + // Check for end. + if (LastError == ERROR_NO_MORE_FILES) + return detail::directory_iterator_destruct(IT); + return mapWindowsError(LastError); + } else + FilenameLen = ::wcslen(FirstFind.cFileName); + + // Construct the current directory entry. + SmallString<128> DirectoryEntryNameUTF8; + if (std::error_code EC = + UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName), + DirectoryEntryNameUTF8)) + return EC; + + IT.IterationHandle = intptr_t(FindHandle.take()); + SmallString<128> DirectoryEntryPath(Path); + path::append(DirectoryEntryPath, DirectoryEntryNameUTF8); + IT.CurrentEntry = + directory_entry(DirectoryEntryPath, FollowSymlinks, + file_type_from_attrs(FirstFind.dwFileAttributes), + status_from_find_data(&FirstFind)); + + return std::error_code(); +} + +std::error_code detail::directory_iterator_destruct(detail::DirIterState &IT) { + if (IT.IterationHandle != 0) + // Closes the handle if it's valid. + ScopedFindHandle close(HANDLE(IT.IterationHandle)); + IT.IterationHandle = 0; + IT.CurrentEntry = directory_entry(); + return std::error_code(); +} + +std::error_code detail::directory_iterator_increment(detail::DirIterState &IT) { + WIN32_FIND_DATAW FindData; + if (!::FindNextFileW(HANDLE(IT.IterationHandle), &FindData)) { + DWORD LastError = ::GetLastError(); + // Check for end. + if (LastError == ERROR_NO_MORE_FILES) + return detail::directory_iterator_destruct(IT); + return mapWindowsError(LastError); + } + + size_t FilenameLen = ::wcslen(FindData.cFileName); + if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || + (FilenameLen == 2 && FindData.cFileName[0] == L'.' && + FindData.cFileName[1] == L'.')) + return directory_iterator_increment(IT); + + SmallString<128> DirectoryEntryPathUTF8; + if (std::error_code EC = + UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName), + DirectoryEntryPathUTF8)) + return EC; + + IT.CurrentEntry.replace_filename( + Twine(DirectoryEntryPathUTF8), + file_type_from_attrs(FindData.dwFileAttributes), + status_from_find_data(&FindData)); + return std::error_code(); +} + +ErrorOr<basic_file_status> directory_entry::status() const { + return Status; +} + +static std::error_code nativeFileToFd(Expected<HANDLE> H, int &ResultFD, + OpenFlags Flags) { + int CrtOpenFlags = 0; + if (Flags & OF_Append) + CrtOpenFlags |= _O_APPEND; + + if (Flags & OF_Text) + CrtOpenFlags |= _O_TEXT; + + ResultFD = -1; + if (!H) + return errorToErrorCode(H.takeError()); + + ResultFD = ::_open_osfhandle(intptr_t(*H), CrtOpenFlags); + if (ResultFD == -1) { + ::CloseHandle(*H); + return mapWindowsError(ERROR_INVALID_HANDLE); + } + return std::error_code(); +} + +static DWORD nativeDisposition(CreationDisposition Disp, OpenFlags Flags) { + // This is a compatibility hack. Really we should respect the creation + // disposition, but a lot of old code relied on the implicit assumption that + // OF_Append implied it would open an existing file. Since the disposition is + // now explicit and defaults to CD_CreateAlways, this assumption would cause + // any usage of OF_Append to append to a new file, even if the file already + // existed. A better solution might have two new creation dispositions: + // CD_AppendAlways and CD_AppendNew. This would also address the problem of + // OF_Append being used on a read-only descriptor, which doesn't make sense. + if (Flags & OF_Append) + return OPEN_ALWAYS; + + switch (Disp) { + case CD_CreateAlways: + return CREATE_ALWAYS; + case CD_CreateNew: + return CREATE_NEW; + case CD_OpenAlways: + return OPEN_ALWAYS; + case CD_OpenExisting: + return OPEN_EXISTING; + } + llvm_unreachable("unreachable!"); +} + +static DWORD nativeAccess(FileAccess Access, OpenFlags Flags) { + DWORD Result = 0; + if (Access & FA_Read) + Result |= GENERIC_READ; + if (Access & FA_Write) + Result |= GENERIC_WRITE; + if (Flags & OF_Delete) + Result |= DELETE; + if (Flags & OF_UpdateAtime) + Result |= FILE_WRITE_ATTRIBUTES; + return Result; +} + +static std::error_code openNativeFileInternal(const Twine &Name, + file_t &ResultFile, DWORD Disp, + DWORD Access, DWORD Flags, + bool Inherit = false) { + SmallVector<wchar_t, 128> PathUTF16; + if (std::error_code EC = widenPath(Name, PathUTF16)) + return EC; + + SECURITY_ATTRIBUTES SA; + SA.nLength = sizeof(SA); + SA.lpSecurityDescriptor = nullptr; + SA.bInheritHandle = Inherit; + + HANDLE H = + ::CreateFileW(PathUTF16.begin(), Access, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &SA, + Disp, Flags, NULL); + if (H == INVALID_HANDLE_VALUE) { + DWORD LastError = ::GetLastError(); + std::error_code EC = mapWindowsError(LastError); + // Provide a better error message when trying to open directories. + // This only runs if we failed to open the file, so there is probably + // no performances issues. + if (LastError != ERROR_ACCESS_DENIED) + return EC; + if (is_directory(Name)) + return make_error_code(errc::is_a_directory); + return EC; + } + ResultFile = H; + return std::error_code(); +} + +Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp, + FileAccess Access, OpenFlags Flags, + unsigned Mode) { + // Verify that we don't have both "append" and "excl". + assert((!(Disp == CD_CreateNew) || !(Flags & OF_Append)) && + "Cannot specify both 'CreateNew' and 'Append' file creation flags!"); + + DWORD NativeDisp = nativeDisposition(Disp, Flags); + DWORD NativeAccess = nativeAccess(Access, Flags); + + bool Inherit = false; + if (Flags & OF_ChildInherit) + Inherit = true; + + file_t Result; + std::error_code EC = openNativeFileInternal( + Name, Result, NativeDisp, NativeAccess, FILE_ATTRIBUTE_NORMAL, Inherit); + if (EC) + return errorCodeToError(EC); + + if (Flags & OF_UpdateAtime) { + FILETIME FileTime; + SYSTEMTIME SystemTime; + GetSystemTime(&SystemTime); + if (SystemTimeToFileTime(&SystemTime, &FileTime) == 0 || + SetFileTime(Result, NULL, &FileTime, NULL) == 0) { + DWORD LastError = ::GetLastError(); + ::CloseHandle(Result); + return errorCodeToError(mapWindowsError(LastError)); + } + } + + if (Flags & OF_Delete) { + if ((EC = setDeleteDisposition(Result, true))) { + ::CloseHandle(Result); + return errorCodeToError(EC); + } + } + return Result; +} + +std::error_code openFile(const Twine &Name, int &ResultFD, + CreationDisposition Disp, FileAccess Access, + OpenFlags Flags, unsigned int Mode) { + Expected<file_t> Result = openNativeFile(Name, Disp, Access, Flags); + if (!Result) + return errorToErrorCode(Result.takeError()); + + return nativeFileToFd(*Result, ResultFD, Flags); +} + +static std::error_code directoryRealPath(const Twine &Name, + SmallVectorImpl<char> &RealPath) { + file_t File; + std::error_code EC = openNativeFileInternal( + Name, File, OPEN_EXISTING, GENERIC_READ, FILE_FLAG_BACKUP_SEMANTICS); + if (EC) + return EC; + + EC = realPathFromHandle(File, RealPath); + ::CloseHandle(File); + return EC; +} + +std::error_code openFileForRead(const Twine &Name, int &ResultFD, + OpenFlags Flags, + SmallVectorImpl<char> *RealPath) { + Expected<HANDLE> NativeFile = openNativeFileForRead(Name, Flags, RealPath); + return nativeFileToFd(std::move(NativeFile), ResultFD, OF_None); +} + +Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags, + SmallVectorImpl<char> *RealPath) { + Expected<file_t> Result = + openNativeFile(Name, CD_OpenExisting, FA_Read, Flags); + + // Fetch the real name of the file, if the user asked + if (Result && RealPath) + realPathFromHandle(*Result, *RealPath); + + return Result; +} + +file_t convertFDToNativeFile(int FD) { + return reinterpret_cast<HANDLE>(::_get_osfhandle(FD)); +} + +file_t getStdinHandle() { return ::GetStdHandle(STD_INPUT_HANDLE); } +file_t getStdoutHandle() { return ::GetStdHandle(STD_OUTPUT_HANDLE); } +file_t getStderrHandle() { return ::GetStdHandle(STD_ERROR_HANDLE); } + +Expected<size_t> readNativeFileImpl(file_t FileHandle, + MutableArrayRef<char> Buf, + OVERLAPPED *Overlap) { + // ReadFile can only read 2GB at a time. The caller should check the number of + // bytes and read in a loop until termination. + DWORD BytesToRead = + std::min(size_t(std::numeric_limits<DWORD>::max()), Buf.size()); + DWORD BytesRead = 0; + if (::ReadFile(FileHandle, Buf.data(), BytesToRead, &BytesRead, Overlap)) + return BytesRead; + DWORD Err = ::GetLastError(); + // EOF is not an error. + if (Err == ERROR_BROKEN_PIPE || Err == ERROR_HANDLE_EOF) + return BytesRead; + return errorCodeToError(mapWindowsError(Err)); +} + +Expected<size_t> readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf) { + return readNativeFileImpl(FileHandle, Buf, /*Overlap=*/nullptr); +} + +Expected<size_t> readNativeFileSlice(file_t FileHandle, + MutableArrayRef<char> Buf, + uint64_t Offset) { + OVERLAPPED Overlapped = {}; + Overlapped.Offset = uint32_t(Offset); + Overlapped.OffsetHigh = uint32_t(Offset >> 32); + return readNativeFileImpl(FileHandle, Buf, &Overlapped); +} + std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout) { DWORD Flags = LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY; OVERLAPPED OV = {}; @@ -1324,256 +1324,256 @@ std::error_code unlockFile(int FD) { return mapWindowsError(::GetLastError()); } -std::error_code closeFile(file_t &F) { - file_t TmpF = F; - F = kInvalidFile; - if (!::CloseHandle(TmpF)) - return mapWindowsError(::GetLastError()); - return std::error_code(); -} - -std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { - // Convert to utf-16. - SmallVector<wchar_t, 128> Path16; - std::error_code EC = widenPath(path, Path16); - if (EC && !IgnoreErrors) - return EC; - - // SHFileOperation() accepts a list of paths, and so must be double null- - // terminated to indicate the end of the list. The buffer is already null - // terminated, but since that null character is not considered part of the - // vector's size, pushing another one will just consume that byte. So we - // need to push 2 null terminators. - Path16.push_back(0); - Path16.push_back(0); - - SHFILEOPSTRUCTW shfos = {}; - shfos.wFunc = FO_DELETE; - shfos.pFrom = Path16.data(); - shfos.fFlags = FOF_NO_UI; - - int result = ::SHFileOperationW(&shfos); - if (result != 0 && !IgnoreErrors) - return mapWindowsError(result); - return std::error_code(); -} - -static void expandTildeExpr(SmallVectorImpl<char> &Path) { - // Path does not begin with a tilde expression. - if (Path.empty() || Path[0] != '~') - return; - - StringRef PathStr(Path.begin(), Path.size()); - PathStr = PathStr.drop_front(); - StringRef Expr = PathStr.take_until([](char c) { return path::is_separator(c); }); - - if (!Expr.empty()) { - // This is probably a ~username/ expression. Don't support this on Windows. - return; - } - - SmallString<128> HomeDir; - if (!path::home_directory(HomeDir)) { - // For some reason we couldn't get the home directory. Just exit. - return; - } - - // Overwrite the first character and insert the rest. - Path[0] = HomeDir[0]; - Path.insert(Path.begin() + 1, HomeDir.begin() + 1, HomeDir.end()); -} - -void expand_tilde(const Twine &path, SmallVectorImpl<char> &dest) { - dest.clear(); - if (path.isTriviallyEmpty()) - return; - - path.toVector(dest); - expandTildeExpr(dest); - - return; -} - -std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, - bool expand_tilde) { - dest.clear(); - if (path.isTriviallyEmpty()) - return std::error_code(); - - if (expand_tilde) { - SmallString<128> Storage; - path.toVector(Storage); - expandTildeExpr(Storage); - return real_path(Storage, dest, false); - } - - if (is_directory(path)) - return directoryRealPath(path, dest); - - int fd; - if (std::error_code EC = - llvm::sys::fs::openFileForRead(path, fd, OF_None, &dest)) - return EC; - ::close(fd); - return std::error_code(); -} - -} // end namespace fs - -namespace path { -static bool getKnownFolderPath(KNOWNFOLDERID folderId, - SmallVectorImpl<char> &result) { - wchar_t *path = nullptr; - if (::SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, nullptr, &path) != S_OK) - return false; - - bool ok = !UTF16ToUTF8(path, ::wcslen(path), result); - ::CoTaskMemFree(path); - return ok; -} - -bool home_directory(SmallVectorImpl<char> &result) { - return getKnownFolderPath(FOLDERID_Profile, result); -} - -bool user_config_directory(SmallVectorImpl<char> &result) { - // Either local or roaming appdata may be suitable in some cases, depending - // on the data. Local is more conservative, Roaming may not always be correct. - return getKnownFolderPath(FOLDERID_LocalAppData, result); -} - -bool cache_directory(SmallVectorImpl<char> &result) { - return getKnownFolderPath(FOLDERID_LocalAppData, result); -} - -static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl<char> &Res) { - SmallVector<wchar_t, 1024> Buf; - size_t Size = 1024; - do { - Buf.reserve(Size); - Size = GetEnvironmentVariableW(Var, Buf.data(), Buf.capacity()); - if (Size == 0) - return false; - - // Try again with larger buffer. - } while (Size > Buf.capacity()); - Buf.set_size(Size); - - return !windows::UTF16ToUTF8(Buf.data(), Size, Res); -} - -static bool getTempDirEnvVar(SmallVectorImpl<char> &Res) { - const wchar_t *EnvironmentVariables[] = {L"TMP", L"TEMP", L"USERPROFILE"}; - for (auto *Env : EnvironmentVariables) { - if (getTempDirEnvVar(Env, Res)) - return true; - } - return false; -} - -void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) { - (void)ErasedOnReboot; - Result.clear(); - - // Check whether the temporary directory is specified by an environment var. - // This matches GetTempPath logic to some degree. GetTempPath is not used - // directly as it cannot handle evn var longer than 130 chars on Windows 7 - // (fixed on Windows 8). - if (getTempDirEnvVar(Result)) { - assert(!Result.empty() && "Unexpected empty path"); - native(Result); // Some Unix-like shells use Unix path separator in $TMP. - fs::make_absolute(Result); // Make it absolute if not already. - return; - } - - // Fall back to a system default. - const char *DefaultResult = "C:\\Temp"; - Result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); -} -} // end namespace path - -namespace windows { -std::error_code CodePageToUTF16(unsigned codepage, - llvm::StringRef original, - llvm::SmallVectorImpl<wchar_t> &utf16) { - if (!original.empty()) { - int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(), - original.size(), utf16.begin(), 0); - - if (len == 0) { - return mapWindowsError(::GetLastError()); - } - - utf16.reserve(len + 1); - utf16.set_size(len); - - len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(), - original.size(), utf16.begin(), utf16.size()); - - if (len == 0) { - return mapWindowsError(::GetLastError()); - } - } - - // Make utf16 null terminated. - utf16.push_back(0); - utf16.pop_back(); - - return std::error_code(); -} - -std::error_code UTF8ToUTF16(llvm::StringRef utf8, - llvm::SmallVectorImpl<wchar_t> &utf16) { - return CodePageToUTF16(CP_UTF8, utf8, utf16); -} - -std::error_code CurCPToUTF16(llvm::StringRef curcp, - llvm::SmallVectorImpl<wchar_t> &utf16) { - return CodePageToUTF16(CP_ACP, curcp, utf16); -} - -static -std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, - size_t utf16_len, - llvm::SmallVectorImpl<char> &converted) { - if (utf16_len) { - // Get length. - int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.begin(), - 0, NULL, NULL); - - if (len == 0) { - return mapWindowsError(::GetLastError()); - } - - converted.reserve(len); - converted.set_size(len); - - // Now do the actual conversion. - len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.data(), - converted.size(), NULL, NULL); - - if (len == 0) { - return mapWindowsError(::GetLastError()); - } - } - - // Make the new string null terminated. - converted.push_back(0); - converted.pop_back(); - - return std::error_code(); -} - -std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, - llvm::SmallVectorImpl<char> &utf8) { - return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8); -} - -std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, - llvm::SmallVectorImpl<char> &curcp) { - return UTF16ToCodePage(CP_ACP, utf16, utf16_len, curcp); -} - -} // end namespace windows -} // end namespace sys -} // end namespace llvm +std::error_code closeFile(file_t &F) { + file_t TmpF = F; + F = kInvalidFile; + if (!::CloseHandle(TmpF)) + return mapWindowsError(::GetLastError()); + return std::error_code(); +} + +std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { + // Convert to utf-16. + SmallVector<wchar_t, 128> Path16; + std::error_code EC = widenPath(path, Path16); + if (EC && !IgnoreErrors) + return EC; + + // SHFileOperation() accepts a list of paths, and so must be double null- + // terminated to indicate the end of the list. The buffer is already null + // terminated, but since that null character is not considered part of the + // vector's size, pushing another one will just consume that byte. So we + // need to push 2 null terminators. + Path16.push_back(0); + Path16.push_back(0); + + SHFILEOPSTRUCTW shfos = {}; + shfos.wFunc = FO_DELETE; + shfos.pFrom = Path16.data(); + shfos.fFlags = FOF_NO_UI; + + int result = ::SHFileOperationW(&shfos); + if (result != 0 && !IgnoreErrors) + return mapWindowsError(result); + return std::error_code(); +} + +static void expandTildeExpr(SmallVectorImpl<char> &Path) { + // Path does not begin with a tilde expression. + if (Path.empty() || Path[0] != '~') + return; + + StringRef PathStr(Path.begin(), Path.size()); + PathStr = PathStr.drop_front(); + StringRef Expr = PathStr.take_until([](char c) { return path::is_separator(c); }); + + if (!Expr.empty()) { + // This is probably a ~username/ expression. Don't support this on Windows. + return; + } + + SmallString<128> HomeDir; + if (!path::home_directory(HomeDir)) { + // For some reason we couldn't get the home directory. Just exit. + return; + } + + // Overwrite the first character and insert the rest. + Path[0] = HomeDir[0]; + Path.insert(Path.begin() + 1, HomeDir.begin() + 1, HomeDir.end()); +} + +void expand_tilde(const Twine &path, SmallVectorImpl<char> &dest) { + dest.clear(); + if (path.isTriviallyEmpty()) + return; + + path.toVector(dest); + expandTildeExpr(dest); + + return; +} + +std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, + bool expand_tilde) { + dest.clear(); + if (path.isTriviallyEmpty()) + return std::error_code(); + + if (expand_tilde) { + SmallString<128> Storage; + path.toVector(Storage); + expandTildeExpr(Storage); + return real_path(Storage, dest, false); + } + + if (is_directory(path)) + return directoryRealPath(path, dest); + + int fd; + if (std::error_code EC = + llvm::sys::fs::openFileForRead(path, fd, OF_None, &dest)) + return EC; + ::close(fd); + return std::error_code(); +} + +} // end namespace fs + +namespace path { +static bool getKnownFolderPath(KNOWNFOLDERID folderId, + SmallVectorImpl<char> &result) { + wchar_t *path = nullptr; + if (::SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, nullptr, &path) != S_OK) + return false; + + bool ok = !UTF16ToUTF8(path, ::wcslen(path), result); + ::CoTaskMemFree(path); + return ok; +} + +bool home_directory(SmallVectorImpl<char> &result) { + return getKnownFolderPath(FOLDERID_Profile, result); +} + +bool user_config_directory(SmallVectorImpl<char> &result) { + // Either local or roaming appdata may be suitable in some cases, depending + // on the data. Local is more conservative, Roaming may not always be correct. + return getKnownFolderPath(FOLDERID_LocalAppData, result); +} + +bool cache_directory(SmallVectorImpl<char> &result) { + return getKnownFolderPath(FOLDERID_LocalAppData, result); +} + +static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl<char> &Res) { + SmallVector<wchar_t, 1024> Buf; + size_t Size = 1024; + do { + Buf.reserve(Size); + Size = GetEnvironmentVariableW(Var, Buf.data(), Buf.capacity()); + if (Size == 0) + return false; + + // Try again with larger buffer. + } while (Size > Buf.capacity()); + Buf.set_size(Size); + + return !windows::UTF16ToUTF8(Buf.data(), Size, Res); +} + +static bool getTempDirEnvVar(SmallVectorImpl<char> &Res) { + const wchar_t *EnvironmentVariables[] = {L"TMP", L"TEMP", L"USERPROFILE"}; + for (auto *Env : EnvironmentVariables) { + if (getTempDirEnvVar(Env, Res)) + return true; + } + return false; +} + +void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) { + (void)ErasedOnReboot; + Result.clear(); + + // Check whether the temporary directory is specified by an environment var. + // This matches GetTempPath logic to some degree. GetTempPath is not used + // directly as it cannot handle evn var longer than 130 chars on Windows 7 + // (fixed on Windows 8). + if (getTempDirEnvVar(Result)) { + assert(!Result.empty() && "Unexpected empty path"); + native(Result); // Some Unix-like shells use Unix path separator in $TMP. + fs::make_absolute(Result); // Make it absolute if not already. + return; + } + + // Fall back to a system default. + const char *DefaultResult = "C:\\Temp"; + Result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); +} +} // end namespace path + +namespace windows { +std::error_code CodePageToUTF16(unsigned codepage, + llvm::StringRef original, + llvm::SmallVectorImpl<wchar_t> &utf16) { + if (!original.empty()) { + int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(), + original.size(), utf16.begin(), 0); + + if (len == 0) { + return mapWindowsError(::GetLastError()); + } + + utf16.reserve(len + 1); + utf16.set_size(len); + + len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(), + original.size(), utf16.begin(), utf16.size()); + + if (len == 0) { + return mapWindowsError(::GetLastError()); + } + } + + // Make utf16 null terminated. + utf16.push_back(0); + utf16.pop_back(); + + return std::error_code(); +} + +std::error_code UTF8ToUTF16(llvm::StringRef utf8, + llvm::SmallVectorImpl<wchar_t> &utf16) { + return CodePageToUTF16(CP_UTF8, utf8, utf16); +} + +std::error_code CurCPToUTF16(llvm::StringRef curcp, + llvm::SmallVectorImpl<wchar_t> &utf16) { + return CodePageToUTF16(CP_ACP, curcp, utf16); +} + +static +std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, + size_t utf16_len, + llvm::SmallVectorImpl<char> &converted) { + if (utf16_len) { + // Get length. + int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.begin(), + 0, NULL, NULL); + + if (len == 0) { + return mapWindowsError(::GetLastError()); + } + + converted.reserve(len); + converted.set_size(len); + + // Now do the actual conversion. + len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.data(), + converted.size(), NULL, NULL); + + if (len == 0) { + return mapWindowsError(::GetLastError()); + } + } + + // Make the new string null terminated. + converted.push_back(0); + converted.pop_back(); + + return std::error_code(); +} + +std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, + llvm::SmallVectorImpl<char> &utf8) { + return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8); +} + +std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, + llvm::SmallVectorImpl<char> &curcp) { + return UTF16ToCodePage(CP_ACP, utf16, utf16_len, curcp); +} + +} // end namespace windows +} // end namespace sys +} // end namespace llvm diff --git a/contrib/libs/llvm12/lib/Support/Windows/Process.inc b/contrib/libs/llvm12/lib/Support/Windows/Process.inc index f6b6b7c433..910d2395d2 100644 --- a/contrib/libs/llvm12/lib/Support/Windows/Process.inc +++ b/contrib/libs/llvm12/lib/Support/Windows/Process.inc @@ -1,505 +1,505 @@ -//===- Win32/Process.cpp - Win32 Process Implementation ------- -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of the Process class. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/Allocator.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/StringSaver.h" -#include "llvm/Support/WindowsError.h" -#include <malloc.h> - -// The Windows.h header must be after LLVM and standard headers. -#include "llvm/Support/Windows/WindowsSupport.h" - -#include <direct.h> -#include <io.h> -#include <psapi.h> -#include <shellapi.h> - -#if !defined(__MINGW32__) - #pragma comment(lib, "psapi.lib") - #pragma comment(lib, "shell32.lib") -#endif - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -#ifdef __MINGW32__ -// This ban should be lifted when MinGW 1.0+ has defined this value. -# define _HEAPOK (-2) -#endif - -using namespace llvm; - -Process::Pid Process::getProcessId() { - static_assert(sizeof(Pid) >= sizeof(DWORD), - "Process::Pid should be big enough to store DWORD"); - return Pid(::GetCurrentProcessId()); -} - -// This function retrieves the page size using GetNativeSystemInfo() and is -// present solely so it can be called once to initialize the self_process member -// below. -static unsigned computePageSize() { - // GetNativeSystemInfo() provides the physical page size which may differ - // from GetSystemInfo() in 32-bit applications running under WOW64. - SYSTEM_INFO info; - GetNativeSystemInfo(&info); - // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize, - // but dwAllocationGranularity. - return static_cast<unsigned>(info.dwPageSize); -} - -Expected<unsigned> Process::getPageSize() { - static unsigned Ret = computePageSize(); - return Ret; -} - -size_t -Process::GetMallocUsage() -{ - _HEAPINFO hinfo; - hinfo._pentry = NULL; - - size_t size = 0; - - while (_heapwalk(&hinfo) == _HEAPOK) - size += hinfo._size; - - return size; -} - -void Process::GetTimeUsage(TimePoint<> &elapsed, std::chrono::nanoseconds &user_time, - std::chrono::nanoseconds &sys_time) { - elapsed = std::chrono::system_clock::now();; - - FILETIME ProcCreate, ProcExit, KernelTime, UserTime; - if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime, - &UserTime) == 0) - return; - - user_time = toDuration(UserTime); - sys_time = toDuration(KernelTime); -} - -// Some LLVM programs such as bugpoint produce core files as a normal part of -// their operation. To prevent the disk from filling up, this configuration -// item does what's necessary to prevent their generation. -void Process::PreventCoreFiles() { - // Windows does have the concept of core files, called minidumps. However, - // disabling minidumps for a particular application extends past the lifetime - // of that application, which is the incorrect behavior for this API. - // Additionally, the APIs require elevated privileges to disable and re- - // enable minidumps, which makes this untenable. For more information, see - // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and - // later). - // - // Windows also has modal pop-up message boxes. As this method is used by - // bugpoint, preventing these pop-ups is additionally important. - SetErrorMode(SEM_FAILCRITICALERRORS | - SEM_NOGPFAULTERRORBOX | - SEM_NOOPENFILEERRORBOX); - - coreFilesPrevented = true; -} - -/// Returns the environment variable \arg Name's value as a string encoded in -/// UTF-8. \arg Name is assumed to be in UTF-8 encoding. -Optional<std::string> Process::GetEnv(StringRef Name) { - // Convert the argument to UTF-16 to pass it to _wgetenv(). - SmallVector<wchar_t, 128> NameUTF16; - if (windows::UTF8ToUTF16(Name, NameUTF16)) - return None; - - // Environment variable can be encoded in non-UTF8 encoding, and there's no - // way to know what the encoding is. The only reliable way to look up - // multibyte environment variable is to use GetEnvironmentVariableW(). - SmallVector<wchar_t, MAX_PATH> Buf; - size_t Size = MAX_PATH; - do { - Buf.reserve(Size); - SetLastError(NO_ERROR); - Size = - GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); - if (Size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) - return None; - - // Try again with larger buffer. - } while (Size > Buf.capacity()); - Buf.set_size(Size); - - // Convert the result from UTF-16 to UTF-8. - SmallVector<char, MAX_PATH> Res; - if (windows::UTF16ToUTF8(Buf.data(), Size, Res)) - return None; - return std::string(Res.data()); -} - -/// Perform wildcard expansion of Arg, or just push it into Args if it doesn't -/// have wildcards or doesn't match any files. -static std::error_code WildcardExpand(StringRef Arg, - SmallVectorImpl<const char *> &Args, - StringSaver &Saver) { - std::error_code EC; - - // Don't expand Arg if it does not contain any wildcard characters. This is - // the common case. Also don't wildcard expand /?. Always treat it as an - // option. - if (Arg.find_first_of("*?") == StringRef::npos || Arg == "/?" || - Arg == "-?") { - Args.push_back(Arg.data()); - return EC; - } - - // Convert back to UTF-16 so we can call FindFirstFileW. - SmallVector<wchar_t, MAX_PATH> ArgW; - EC = windows::UTF8ToUTF16(Arg, ArgW); - if (EC) - return EC; - - // Search for matching files. - // FIXME: This assumes the wildcard is only in the file name and not in the - // directory portion of the file path. For example, it doesn't handle - // "*\foo.c" nor "s?c\bar.cpp". - WIN32_FIND_DATAW FileData; - HANDLE FindHandle = FindFirstFileW(ArgW.data(), &FileData); - if (FindHandle == INVALID_HANDLE_VALUE) { - Args.push_back(Arg.data()); - return EC; - } - - // Extract any directory part of the argument. - SmallString<MAX_PATH> Dir = Arg; - sys::path::remove_filename(Dir); - const int DirSize = Dir.size(); - - do { - SmallString<MAX_PATH> FileName; - EC = windows::UTF16ToUTF8(FileData.cFileName, wcslen(FileData.cFileName), - FileName); - if (EC) - break; - - // Append FileName to Dir, and remove it afterwards. - llvm::sys::path::append(Dir, FileName); - Args.push_back(Saver.save(StringRef(Dir)).data()); - Dir.resize(DirSize); - } while (FindNextFileW(FindHandle, &FileData)); - - FindClose(FindHandle); - return EC; -} - -static std::error_code GetExecutableName(SmallVectorImpl<char> &Filename) { - // The first argument may contain just the name of the executable (e.g., - // "clang") rather than the full path, so swap it with the full path. - wchar_t ModuleName[MAX_PATH]; - size_t Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH); - if (Length == 0 || Length == MAX_PATH) { - return mapWindowsError(GetLastError()); - } - - // If the first argument is a shortened (8.3) name (which is possible even - // if we got the module name), the driver will have trouble distinguishing it - // (e.g., clang.exe v. clang++.exe), so expand it now. - Length = GetLongPathNameW(ModuleName, ModuleName, MAX_PATH); - if (Length == 0) - return mapWindowsError(GetLastError()); - if (Length > MAX_PATH) { - // We're not going to try to deal with paths longer than MAX_PATH, so we'll - // treat this as an error. GetLastError() returns ERROR_SUCCESS, which - // isn't useful, so we'll hardcode an appropriate error value. - return mapWindowsError(ERROR_INSUFFICIENT_BUFFER); - } - - std::error_code EC = windows::UTF16ToUTF8(ModuleName, Length, Filename); - if (EC) - return EC; - +//===- Win32/Process.cpp - Win32 Process Implementation ------- -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Process class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Allocator.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/WindowsError.h" +#include <malloc.h> + +// The Windows.h header must be after LLVM and standard headers. +#include "llvm/Support/Windows/WindowsSupport.h" + +#include <direct.h> +#include <io.h> +#include <psapi.h> +#include <shellapi.h> + +#if !defined(__MINGW32__) + #pragma comment(lib, "psapi.lib") + #pragma comment(lib, "shell32.lib") +#endif + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +#ifdef __MINGW32__ +// This ban should be lifted when MinGW 1.0+ has defined this value. +# define _HEAPOK (-2) +#endif + +using namespace llvm; + +Process::Pid Process::getProcessId() { + static_assert(sizeof(Pid) >= sizeof(DWORD), + "Process::Pid should be big enough to store DWORD"); + return Pid(::GetCurrentProcessId()); +} + +// This function retrieves the page size using GetNativeSystemInfo() and is +// present solely so it can be called once to initialize the self_process member +// below. +static unsigned computePageSize() { + // GetNativeSystemInfo() provides the physical page size which may differ + // from GetSystemInfo() in 32-bit applications running under WOW64. + SYSTEM_INFO info; + GetNativeSystemInfo(&info); + // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize, + // but dwAllocationGranularity. + return static_cast<unsigned>(info.dwPageSize); +} + +Expected<unsigned> Process::getPageSize() { + static unsigned Ret = computePageSize(); + return Ret; +} + +size_t +Process::GetMallocUsage() +{ + _HEAPINFO hinfo; + hinfo._pentry = NULL; + + size_t size = 0; + + while (_heapwalk(&hinfo) == _HEAPOK) + size += hinfo._size; + + return size; +} + +void Process::GetTimeUsage(TimePoint<> &elapsed, std::chrono::nanoseconds &user_time, + std::chrono::nanoseconds &sys_time) { + elapsed = std::chrono::system_clock::now();; + + FILETIME ProcCreate, ProcExit, KernelTime, UserTime; + if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime, + &UserTime) == 0) + return; + + user_time = toDuration(UserTime); + sys_time = toDuration(KernelTime); +} + +// Some LLVM programs such as bugpoint produce core files as a normal part of +// their operation. To prevent the disk from filling up, this configuration +// item does what's necessary to prevent their generation. +void Process::PreventCoreFiles() { + // Windows does have the concept of core files, called minidumps. However, + // disabling minidumps for a particular application extends past the lifetime + // of that application, which is the incorrect behavior for this API. + // Additionally, the APIs require elevated privileges to disable and re- + // enable minidumps, which makes this untenable. For more information, see + // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and + // later). + // + // Windows also has modal pop-up message boxes. As this method is used by + // bugpoint, preventing these pop-ups is additionally important. + SetErrorMode(SEM_FAILCRITICALERRORS | + SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); + + coreFilesPrevented = true; +} + +/// Returns the environment variable \arg Name's value as a string encoded in +/// UTF-8. \arg Name is assumed to be in UTF-8 encoding. +Optional<std::string> Process::GetEnv(StringRef Name) { + // Convert the argument to UTF-16 to pass it to _wgetenv(). + SmallVector<wchar_t, 128> NameUTF16; + if (windows::UTF8ToUTF16(Name, NameUTF16)) + return None; + + // Environment variable can be encoded in non-UTF8 encoding, and there's no + // way to know what the encoding is. The only reliable way to look up + // multibyte environment variable is to use GetEnvironmentVariableW(). + SmallVector<wchar_t, MAX_PATH> Buf; + size_t Size = MAX_PATH; + do { + Buf.reserve(Size); + SetLastError(NO_ERROR); + Size = + GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); + if (Size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) + return None; + + // Try again with larger buffer. + } while (Size > Buf.capacity()); + Buf.set_size(Size); + + // Convert the result from UTF-16 to UTF-8. + SmallVector<char, MAX_PATH> Res; + if (windows::UTF16ToUTF8(Buf.data(), Size, Res)) + return None; + return std::string(Res.data()); +} + +/// Perform wildcard expansion of Arg, or just push it into Args if it doesn't +/// have wildcards or doesn't match any files. +static std::error_code WildcardExpand(StringRef Arg, + SmallVectorImpl<const char *> &Args, + StringSaver &Saver) { + std::error_code EC; + + // Don't expand Arg if it does not contain any wildcard characters. This is + // the common case. Also don't wildcard expand /?. Always treat it as an + // option. + if (Arg.find_first_of("*?") == StringRef::npos || Arg == "/?" || + Arg == "-?") { + Args.push_back(Arg.data()); + return EC; + } + + // Convert back to UTF-16 so we can call FindFirstFileW. + SmallVector<wchar_t, MAX_PATH> ArgW; + EC = windows::UTF8ToUTF16(Arg, ArgW); + if (EC) + return EC; + + // Search for matching files. + // FIXME: This assumes the wildcard is only in the file name and not in the + // directory portion of the file path. For example, it doesn't handle + // "*\foo.c" nor "s?c\bar.cpp". + WIN32_FIND_DATAW FileData; + HANDLE FindHandle = FindFirstFileW(ArgW.data(), &FileData); + if (FindHandle == INVALID_HANDLE_VALUE) { + Args.push_back(Arg.data()); + return EC; + } + + // Extract any directory part of the argument. + SmallString<MAX_PATH> Dir = Arg; + sys::path::remove_filename(Dir); + const int DirSize = Dir.size(); + + do { + SmallString<MAX_PATH> FileName; + EC = windows::UTF16ToUTF8(FileData.cFileName, wcslen(FileData.cFileName), + FileName); + if (EC) + break; + + // Append FileName to Dir, and remove it afterwards. + llvm::sys::path::append(Dir, FileName); + Args.push_back(Saver.save(StringRef(Dir)).data()); + Dir.resize(DirSize); + } while (FindNextFileW(FindHandle, &FileData)); + + FindClose(FindHandle); + return EC; +} + +static std::error_code GetExecutableName(SmallVectorImpl<char> &Filename) { + // The first argument may contain just the name of the executable (e.g., + // "clang") rather than the full path, so swap it with the full path. + wchar_t ModuleName[MAX_PATH]; + size_t Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH); + if (Length == 0 || Length == MAX_PATH) { + return mapWindowsError(GetLastError()); + } + + // If the first argument is a shortened (8.3) name (which is possible even + // if we got the module name), the driver will have trouble distinguishing it + // (e.g., clang.exe v. clang++.exe), so expand it now. + Length = GetLongPathNameW(ModuleName, ModuleName, MAX_PATH); + if (Length == 0) + return mapWindowsError(GetLastError()); + if (Length > MAX_PATH) { + // We're not going to try to deal with paths longer than MAX_PATH, so we'll + // treat this as an error. GetLastError() returns ERROR_SUCCESS, which + // isn't useful, so we'll hardcode an appropriate error value. + return mapWindowsError(ERROR_INSUFFICIENT_BUFFER); + } + + std::error_code EC = windows::UTF16ToUTF8(ModuleName, Length, Filename); + if (EC) + return EC; + // Make a copy of the filename since assign makes the StringRef invalid. std::string Base = sys::path::filename(Filename.data()).str(); - Filename.assign(Base.begin(), Base.end()); - return std::error_code(); -} - -std::error_code -windows::GetCommandLineArguments(SmallVectorImpl<const char *> &Args, - BumpPtrAllocator &Alloc) { - const wchar_t *CmdW = GetCommandLineW(); - assert(CmdW); - std::error_code EC; - SmallString<MAX_PATH> Cmd; - EC = windows::UTF16ToUTF8(CmdW, wcslen(CmdW), Cmd); - if (EC) - return EC; - - SmallVector<const char *, 20> TmpArgs; - StringSaver Saver(Alloc); - cl::TokenizeWindowsCommandLine(Cmd, Saver, TmpArgs, /*MarkEOLs=*/false); - - for (const char *Arg : TmpArgs) { - EC = WildcardExpand(Arg, Args, Saver); - if (EC) - return EC; - } - - SmallVector<char, MAX_PATH> Arg0(Args[0], Args[0] + strlen(Args[0])); - SmallVector<char, MAX_PATH> Filename; - sys::path::remove_filename(Arg0); - EC = GetExecutableName(Filename); - if (EC) - return EC; - sys::path::append(Arg0, Filename); - Args[0] = Saver.save(Arg0).data(); - return std::error_code(); -} - -std::error_code Process::FixupStandardFileDescriptors() { - return std::error_code(); -} - -std::error_code Process::SafelyCloseFileDescriptor(int FD) { - if (::close(FD) < 0) - return std::error_code(errno, std::generic_category()); - return std::error_code(); -} - -bool Process::StandardInIsUserInput() { - return FileDescriptorIsDisplayed(0); -} - -bool Process::StandardOutIsDisplayed() { - return FileDescriptorIsDisplayed(1); -} - -bool Process::StandardErrIsDisplayed() { - return FileDescriptorIsDisplayed(2); -} - -bool Process::FileDescriptorIsDisplayed(int fd) { - DWORD Mode; // Unused - return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0); -} - -unsigned Process::StandardOutColumns() { - unsigned Columns = 0; - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) - Columns = csbi.dwSize.X; - return Columns; -} - -unsigned Process::StandardErrColumns() { - unsigned Columns = 0; - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) - Columns = csbi.dwSize.X; - return Columns; -} - -// The terminal always has colors. -bool Process::FileDescriptorHasColors(int fd) { - return FileDescriptorIsDisplayed(fd); -} - -bool Process::StandardOutHasColors() { - return FileDescriptorHasColors(1); -} - -bool Process::StandardErrHasColors() { - return FileDescriptorHasColors(2); -} - -static bool UseANSI = false; -void Process::UseANSIEscapeCodes(bool enable) { -#if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) - if (enable) { - HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD Mode; - GetConsoleMode(Console, &Mode); - Mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - SetConsoleMode(Console, Mode); - } -#endif - UseANSI = enable; -} - -namespace { -class DefaultColors -{ - private: - WORD defaultColor; - public: - DefaultColors() - :defaultColor(GetCurrentColor()) {} - static unsigned GetCurrentColor() { - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) - return csbi.wAttributes; - return 0; - } - WORD operator()() const { return defaultColor; } -}; - -DefaultColors defaultColors; - -WORD fg_color(WORD color) { - return color & (FOREGROUND_BLUE | FOREGROUND_GREEN | - FOREGROUND_INTENSITY | FOREGROUND_RED); -} - -WORD bg_color(WORD color) { - return color & (BACKGROUND_BLUE | BACKGROUND_GREEN | - BACKGROUND_INTENSITY | BACKGROUND_RED); -} -} - -bool Process::ColorNeedsFlush() { - return !UseANSI; -} - -const char *Process::OutputBold(bool bg) { - if (UseANSI) return "\033[1m"; - - WORD colors = DefaultColors::GetCurrentColor(); - if (bg) - colors |= BACKGROUND_INTENSITY; - else - colors |= FOREGROUND_INTENSITY; - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); - return 0; -} - -const char *Process::OutputColor(char code, bool bold, bool bg) { - if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7]; - - WORD current = DefaultColors::GetCurrentColor(); - WORD colors; - if (bg) { - colors = ((code&1) ? BACKGROUND_RED : 0) | - ((code&2) ? BACKGROUND_GREEN : 0 ) | - ((code&4) ? BACKGROUND_BLUE : 0); - if (bold) - colors |= BACKGROUND_INTENSITY; - colors |= fg_color(current); - } else { - colors = ((code&1) ? FOREGROUND_RED : 0) | - ((code&2) ? FOREGROUND_GREEN : 0 ) | - ((code&4) ? FOREGROUND_BLUE : 0); - if (bold) - colors |= FOREGROUND_INTENSITY; - colors |= bg_color(current); - } - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); - return 0; -} - -static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) { - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info); - return info.wAttributes; -} - -const char *Process::OutputReverse() { - if (UseANSI) return "\033[7m"; - - const WORD attributes - = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE)); - - const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | - FOREGROUND_RED | FOREGROUND_INTENSITY; - const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | - BACKGROUND_RED | BACKGROUND_INTENSITY; - const WORD color_mask = foreground_mask | background_mask; - - WORD new_attributes = - ((attributes & FOREGROUND_BLUE )?BACKGROUND_BLUE :0) | - ((attributes & FOREGROUND_GREEN )?BACKGROUND_GREEN :0) | - ((attributes & FOREGROUND_RED )?BACKGROUND_RED :0) | - ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) | - ((attributes & BACKGROUND_BLUE )?FOREGROUND_BLUE :0) | - ((attributes & BACKGROUND_GREEN )?FOREGROUND_GREEN :0) | - ((attributes & BACKGROUND_RED )?FOREGROUND_RED :0) | - ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) | - 0; - new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask); - - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes); - return 0; -} - -const char *Process::ResetColor() { - if (UseANSI) return "\033[0m"; - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); - return 0; -} - -static unsigned GetRandomNumberSeed() { - // Generate a random number seed from the millisecond-resolution Windows - // system clock and the current process id. - FILETIME Time; - GetSystemTimeAsFileTime(&Time); - DWORD Pid = GetCurrentProcessId(); - return hash_combine(Time.dwHighDateTime, Time.dwLowDateTime, Pid); -} - -static unsigned GetPseudoRandomNumber() { - // Arrange to call srand once when this function is first used, and - // otherwise (if GetRandomNumber always succeeds in using - // CryptGenRandom) don't bother at all. - static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0); - (void)x; - return ::rand(); -} - -unsigned Process::GetRandomNumber() { - // Try to use CryptGenRandom. - HCRYPTPROV HCPC; - if (::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) { - ScopedCryptContext CryptoProvider(HCPC); - unsigned Ret; - if (::CryptGenRandom(CryptoProvider, sizeof(Ret), - reinterpret_cast<BYTE *>(&Ret))) - return Ret; - } - - // If that fails, fall back to pseudo-random numbers. - return GetPseudoRandomNumber(); -} - -typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); -#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) - -llvm::VersionTuple llvm::GetWindowsOSVersion() { - HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); - if (hMod) { - auto getVer = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); - if (getVer) { - RTL_OSVERSIONINFOEXW info{}; - info.dwOSVersionInfoSize = sizeof(info); - if (getVer((PRTL_OSVERSIONINFOW)&info) == STATUS_SUCCESS) { - return llvm::VersionTuple(info.dwMajorVersion, info.dwMinorVersion, 0, - info.dwBuildNumber); - } - } - } - return llvm::VersionTuple(0, 0, 0, 0); -} - -bool llvm::RunningWindows8OrGreater() { - // Windows 8 is version 6.2, service pack 0. - return GetWindowsOSVersion() >= llvm::VersionTuple(6, 2, 0, 0); -} + Filename.assign(Base.begin(), Base.end()); + return std::error_code(); +} + +std::error_code +windows::GetCommandLineArguments(SmallVectorImpl<const char *> &Args, + BumpPtrAllocator &Alloc) { + const wchar_t *CmdW = GetCommandLineW(); + assert(CmdW); + std::error_code EC; + SmallString<MAX_PATH> Cmd; + EC = windows::UTF16ToUTF8(CmdW, wcslen(CmdW), Cmd); + if (EC) + return EC; + + SmallVector<const char *, 20> TmpArgs; + StringSaver Saver(Alloc); + cl::TokenizeWindowsCommandLine(Cmd, Saver, TmpArgs, /*MarkEOLs=*/false); + + for (const char *Arg : TmpArgs) { + EC = WildcardExpand(Arg, Args, Saver); + if (EC) + return EC; + } + + SmallVector<char, MAX_PATH> Arg0(Args[0], Args[0] + strlen(Args[0])); + SmallVector<char, MAX_PATH> Filename; + sys::path::remove_filename(Arg0); + EC = GetExecutableName(Filename); + if (EC) + return EC; + sys::path::append(Arg0, Filename); + Args[0] = Saver.save(Arg0).data(); + return std::error_code(); +} + +std::error_code Process::FixupStandardFileDescriptors() { + return std::error_code(); +} + +std::error_code Process::SafelyCloseFileDescriptor(int FD) { + if (::close(FD) < 0) + return std::error_code(errno, std::generic_category()); + return std::error_code(); +} + +bool Process::StandardInIsUserInput() { + return FileDescriptorIsDisplayed(0); +} + +bool Process::StandardOutIsDisplayed() { + return FileDescriptorIsDisplayed(1); +} + +bool Process::StandardErrIsDisplayed() { + return FileDescriptorIsDisplayed(2); +} + +bool Process::FileDescriptorIsDisplayed(int fd) { + DWORD Mode; // Unused + return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0); +} + +unsigned Process::StandardOutColumns() { + unsigned Columns = 0; + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) + Columns = csbi.dwSize.X; + return Columns; +} + +unsigned Process::StandardErrColumns() { + unsigned Columns = 0; + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) + Columns = csbi.dwSize.X; + return Columns; +} + +// The terminal always has colors. +bool Process::FileDescriptorHasColors(int fd) { + return FileDescriptorIsDisplayed(fd); +} + +bool Process::StandardOutHasColors() { + return FileDescriptorHasColors(1); +} + +bool Process::StandardErrHasColors() { + return FileDescriptorHasColors(2); +} + +static bool UseANSI = false; +void Process::UseANSIEscapeCodes(bool enable) { +#if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) + if (enable) { + HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD Mode; + GetConsoleMode(Console, &Mode); + Mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(Console, Mode); + } +#endif + UseANSI = enable; +} + +namespace { +class DefaultColors +{ + private: + WORD defaultColor; + public: + DefaultColors() + :defaultColor(GetCurrentColor()) {} + static unsigned GetCurrentColor() { + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) + return csbi.wAttributes; + return 0; + } + WORD operator()() const { return defaultColor; } +}; + +DefaultColors defaultColors; + +WORD fg_color(WORD color) { + return color & (FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_INTENSITY | FOREGROUND_RED); +} + +WORD bg_color(WORD color) { + return color & (BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_INTENSITY | BACKGROUND_RED); +} +} + +bool Process::ColorNeedsFlush() { + return !UseANSI; +} + +const char *Process::OutputBold(bool bg) { + if (UseANSI) return "\033[1m"; + + WORD colors = DefaultColors::GetCurrentColor(); + if (bg) + colors |= BACKGROUND_INTENSITY; + else + colors |= FOREGROUND_INTENSITY; + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); + return 0; +} + +const char *Process::OutputColor(char code, bool bold, bool bg) { + if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7]; + + WORD current = DefaultColors::GetCurrentColor(); + WORD colors; + if (bg) { + colors = ((code&1) ? BACKGROUND_RED : 0) | + ((code&2) ? BACKGROUND_GREEN : 0 ) | + ((code&4) ? BACKGROUND_BLUE : 0); + if (bold) + colors |= BACKGROUND_INTENSITY; + colors |= fg_color(current); + } else { + colors = ((code&1) ? FOREGROUND_RED : 0) | + ((code&2) ? FOREGROUND_GREEN : 0 ) | + ((code&4) ? FOREGROUND_BLUE : 0); + if (bold) + colors |= FOREGROUND_INTENSITY; + colors |= bg_color(current); + } + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); + return 0; +} + +static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) { + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info); + return info.wAttributes; +} + +const char *Process::OutputReverse() { + if (UseANSI) return "\033[7m"; + + const WORD attributes + = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE)); + + const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED | FOREGROUND_INTENSITY; + const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY; + const WORD color_mask = foreground_mask | background_mask; + + WORD new_attributes = + ((attributes & FOREGROUND_BLUE )?BACKGROUND_BLUE :0) | + ((attributes & FOREGROUND_GREEN )?BACKGROUND_GREEN :0) | + ((attributes & FOREGROUND_RED )?BACKGROUND_RED :0) | + ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) | + ((attributes & BACKGROUND_BLUE )?FOREGROUND_BLUE :0) | + ((attributes & BACKGROUND_GREEN )?FOREGROUND_GREEN :0) | + ((attributes & BACKGROUND_RED )?FOREGROUND_RED :0) | + ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) | + 0; + new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask); + + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes); + return 0; +} + +const char *Process::ResetColor() { + if (UseANSI) return "\033[0m"; + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); + return 0; +} + +static unsigned GetRandomNumberSeed() { + // Generate a random number seed from the millisecond-resolution Windows + // system clock and the current process id. + FILETIME Time; + GetSystemTimeAsFileTime(&Time); + DWORD Pid = GetCurrentProcessId(); + return hash_combine(Time.dwHighDateTime, Time.dwLowDateTime, Pid); +} + +static unsigned GetPseudoRandomNumber() { + // Arrange to call srand once when this function is first used, and + // otherwise (if GetRandomNumber always succeeds in using + // CryptGenRandom) don't bother at all. + static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0); + (void)x; + return ::rand(); +} + +unsigned Process::GetRandomNumber() { + // Try to use CryptGenRandom. + HCRYPTPROV HCPC; + if (::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + ScopedCryptContext CryptoProvider(HCPC); + unsigned Ret; + if (::CryptGenRandom(CryptoProvider, sizeof(Ret), + reinterpret_cast<BYTE *>(&Ret))) + return Ret; + } + + // If that fails, fall back to pseudo-random numbers. + return GetPseudoRandomNumber(); +} + +typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) + +llvm::VersionTuple llvm::GetWindowsOSVersion() { + HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); + if (hMod) { + auto getVer = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); + if (getVer) { + RTL_OSVERSIONINFOEXW info{}; + info.dwOSVersionInfoSize = sizeof(info); + if (getVer((PRTL_OSVERSIONINFOW)&info) == STATUS_SUCCESS) { + return llvm::VersionTuple(info.dwMajorVersion, info.dwMinorVersion, 0, + info.dwBuildNumber); + } + } + } + return llvm::VersionTuple(0, 0, 0, 0); +} + +bool llvm::RunningWindows8OrGreater() { + // Windows 8 is version 6.2, service pack 0. + return GetWindowsOSVersion() >= llvm::VersionTuple(6, 2, 0, 0); +} diff --git a/contrib/libs/llvm12/lib/Support/Windows/Program.inc b/contrib/libs/llvm12/lib/Support/Windows/Program.inc index 43e1ec33e6..f1d612cf3c 100644 --- a/contrib/libs/llvm12/lib/Support/Windows/Program.inc +++ b/contrib/libs/llvm12/lib/Support/Windows/Program.inc @@ -1,195 +1,195 @@ -//===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of the Program class. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Windows/WindowsSupport.h" -#include "llvm/Support/WindowsError.h" -#include "llvm/Support/raw_ostream.h" -#include <psapi.h> -#include <cstdio> -#include <fcntl.h> -#include <io.h> -#include <malloc.h> -#include <numeric> - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -namespace llvm { - -ProcessInfo::ProcessInfo() : Pid(0), Process(0), ReturnCode(0) {} - -ErrorOr<std::string> sys::findProgramByName(StringRef Name, - ArrayRef<StringRef> Paths) { - assert(!Name.empty() && "Must have a name!"); - - if (Name.find_first_of("/\\") != StringRef::npos) - return std::string(Name); - - const wchar_t *Path = nullptr; - std::wstring PathStorage; - if (!Paths.empty()) { - PathStorage.reserve(Paths.size() * MAX_PATH); - for (unsigned i = 0; i < Paths.size(); ++i) { - if (i) - PathStorage.push_back(L';'); - StringRef P = Paths[i]; - SmallVector<wchar_t, MAX_PATH> TmpPath; - if (std::error_code EC = windows::UTF8ToUTF16(P, TmpPath)) - return EC; - PathStorage.append(TmpPath.begin(), TmpPath.end()); - } - Path = PathStorage.c_str(); - } - - SmallVector<wchar_t, MAX_PATH> U16Name; - if (std::error_code EC = windows::UTF8ToUTF16(Name, U16Name)) - return EC; - - SmallVector<StringRef, 12> PathExts; - PathExts.push_back(""); - PathExts.push_back(".exe"); // FIXME: This must be in %PATHEXT%. - if (const char *PathExtEnv = std::getenv("PATHEXT")) - SplitString(PathExtEnv, PathExts, ";"); - - SmallVector<wchar_t, MAX_PATH> U16Result; - DWORD Len = MAX_PATH; - for (StringRef Ext : PathExts) { - SmallVector<wchar_t, MAX_PATH> U16Ext; - if (std::error_code EC = windows::UTF8ToUTF16(Ext, U16Ext)) - return EC; - - do { - U16Result.reserve(Len); - // Lets attach the extension manually. That is needed for files - // with a point in name like aaa.bbb. SearchPathW will not add extension - // from its argument to such files because it thinks they already had one. - SmallVector<wchar_t, MAX_PATH> U16NameExt; - if (std::error_code EC = - windows::UTF8ToUTF16(Twine(Name + Ext).str(), U16NameExt)) - return EC; - - Len = ::SearchPathW(Path, c_str(U16NameExt), nullptr, - U16Result.capacity(), U16Result.data(), nullptr); - } while (Len > U16Result.capacity()); - - if (Len != 0) - break; // Found it. - } - - if (Len == 0) - return mapWindowsError(::GetLastError()); - - U16Result.set_size(Len); - - SmallVector<char, MAX_PATH> U8Result; - if (std::error_code EC = - windows::UTF16ToUTF8(U16Result.data(), U16Result.size(), U8Result)) - return EC; - - return std::string(U8Result.begin(), U8Result.end()); -} - -bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) { - if (!ErrMsg) - return true; - char *buffer = NULL; - DWORD LastError = GetLastError(); - DWORD R = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_MAX_WIDTH_MASK, - NULL, LastError, 0, (LPSTR)&buffer, 1, NULL); - if (R) - *ErrMsg = prefix + ": " + buffer; - else - *ErrMsg = prefix + ": Unknown error"; - *ErrMsg += " (0x" + llvm::utohexstr(LastError) + ")"; - - LocalFree(buffer); - return R != 0; -} - -static HANDLE RedirectIO(Optional<StringRef> Path, int fd, - std::string *ErrMsg) { - HANDLE h; - if (!Path) { - if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), - GetCurrentProcess(), &h, - 0, TRUE, DUPLICATE_SAME_ACCESS)) - return INVALID_HANDLE_VALUE; - return h; - } - - std::string fname; - if (Path->empty()) - fname = "NUL"; - else - fname = std::string(*Path); - - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = 0; - sa.bInheritHandle = TRUE; - - SmallVector<wchar_t, 128> fnameUnicode; - if (Path->empty()) { - // Don't play long-path tricks on "NUL". - if (windows::UTF8ToUTF16(fname, fnameUnicode)) - return INVALID_HANDLE_VALUE; - } else { - if (sys::windows::widenPath(fname, fnameUnicode)) - return INVALID_HANDLE_VALUE; - } - h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ, - FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) { - MakeErrMsg(ErrMsg, fname + ": Can't open file for " + - (fd ? "input" : "output")); - } - - return h; -} - -} - -static bool Execute(ProcessInfo &PI, StringRef Program, - ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env, - ArrayRef<Optional<StringRef>> Redirects, +//===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Program class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Windows/WindowsSupport.h" +#include "llvm/Support/WindowsError.h" +#include "llvm/Support/raw_ostream.h" +#include <psapi.h> +#include <cstdio> +#include <fcntl.h> +#include <io.h> +#include <malloc.h> +#include <numeric> + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +namespace llvm { + +ProcessInfo::ProcessInfo() : Pid(0), Process(0), ReturnCode(0) {} + +ErrorOr<std::string> sys::findProgramByName(StringRef Name, + ArrayRef<StringRef> Paths) { + assert(!Name.empty() && "Must have a name!"); + + if (Name.find_first_of("/\\") != StringRef::npos) + return std::string(Name); + + const wchar_t *Path = nullptr; + std::wstring PathStorage; + if (!Paths.empty()) { + PathStorage.reserve(Paths.size() * MAX_PATH); + for (unsigned i = 0; i < Paths.size(); ++i) { + if (i) + PathStorage.push_back(L';'); + StringRef P = Paths[i]; + SmallVector<wchar_t, MAX_PATH> TmpPath; + if (std::error_code EC = windows::UTF8ToUTF16(P, TmpPath)) + return EC; + PathStorage.append(TmpPath.begin(), TmpPath.end()); + } + Path = PathStorage.c_str(); + } + + SmallVector<wchar_t, MAX_PATH> U16Name; + if (std::error_code EC = windows::UTF8ToUTF16(Name, U16Name)) + return EC; + + SmallVector<StringRef, 12> PathExts; + PathExts.push_back(""); + PathExts.push_back(".exe"); // FIXME: This must be in %PATHEXT%. + if (const char *PathExtEnv = std::getenv("PATHEXT")) + SplitString(PathExtEnv, PathExts, ";"); + + SmallVector<wchar_t, MAX_PATH> U16Result; + DWORD Len = MAX_PATH; + for (StringRef Ext : PathExts) { + SmallVector<wchar_t, MAX_PATH> U16Ext; + if (std::error_code EC = windows::UTF8ToUTF16(Ext, U16Ext)) + return EC; + + do { + U16Result.reserve(Len); + // Lets attach the extension manually. That is needed for files + // with a point in name like aaa.bbb. SearchPathW will not add extension + // from its argument to such files because it thinks they already had one. + SmallVector<wchar_t, MAX_PATH> U16NameExt; + if (std::error_code EC = + windows::UTF8ToUTF16(Twine(Name + Ext).str(), U16NameExt)) + return EC; + + Len = ::SearchPathW(Path, c_str(U16NameExt), nullptr, + U16Result.capacity(), U16Result.data(), nullptr); + } while (Len > U16Result.capacity()); + + if (Len != 0) + break; // Found it. + } + + if (Len == 0) + return mapWindowsError(::GetLastError()); + + U16Result.set_size(Len); + + SmallVector<char, MAX_PATH> U8Result; + if (std::error_code EC = + windows::UTF16ToUTF8(U16Result.data(), U16Result.size(), U8Result)) + return EC; + + return std::string(U8Result.begin(), U8Result.end()); +} + +bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) { + if (!ErrMsg) + return true; + char *buffer = NULL; + DWORD LastError = GetLastError(); + DWORD R = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, LastError, 0, (LPSTR)&buffer, 1, NULL); + if (R) + *ErrMsg = prefix + ": " + buffer; + else + *ErrMsg = prefix + ": Unknown error"; + *ErrMsg += " (0x" + llvm::utohexstr(LastError) + ")"; + + LocalFree(buffer); + return R != 0; +} + +static HANDLE RedirectIO(Optional<StringRef> Path, int fd, + std::string *ErrMsg) { + HANDLE h; + if (!Path) { + if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), + GetCurrentProcess(), &h, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + return INVALID_HANDLE_VALUE; + return h; + } + + std::string fname; + if (Path->empty()) + fname = "NUL"; + else + fname = std::string(*Path); + + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = 0; + sa.bInheritHandle = TRUE; + + SmallVector<wchar_t, 128> fnameUnicode; + if (Path->empty()) { + // Don't play long-path tricks on "NUL". + if (windows::UTF8ToUTF16(fname, fnameUnicode)) + return INVALID_HANDLE_VALUE; + } else { + if (sys::windows::widenPath(fname, fnameUnicode)) + return INVALID_HANDLE_VALUE; + } + h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) { + MakeErrMsg(ErrMsg, fname + ": Can't open file for " + + (fd ? "input" : "output")); + } + + return h; +} + +} + +static bool Execute(ProcessInfo &PI, StringRef Program, + ArrayRef<StringRef> Args, Optional<ArrayRef<StringRef>> Env, + ArrayRef<Optional<StringRef>> Redirects, unsigned MemoryLimit, std::string *ErrMsg, BitVector *AffinityMask) { - if (!sys::fs::can_execute(Program)) { - if (ErrMsg) - *ErrMsg = "program not executable"; - return false; - } - - // can_execute may succeed by looking at Program + ".exe". CreateProcessW - // will implicitly add the .exe if we provide a command line without an - // executable path, but since we use an explicit executable, we have to add - // ".exe" ourselves. - SmallString<64> ProgramStorage; - if (!sys::fs::exists(Program)) - Program = Twine(Program + ".exe").toStringRef(ProgramStorage); - - // Windows wants a command line, not an array of args, to pass to the new - // process. We have to concatenate them all, while quoting the args that - // have embedded spaces (or are empty). + if (!sys::fs::can_execute(Program)) { + if (ErrMsg) + *ErrMsg = "program not executable"; + return false; + } + + // can_execute may succeed by looking at Program + ".exe". CreateProcessW + // will implicitly add the .exe if we provide a command line without an + // executable path, but since we use an explicit executable, we have to add + // ".exe" ourselves. + SmallString<64> ProgramStorage; + if (!sys::fs::exists(Program)) + Program = Twine(Program + ".exe").toStringRef(ProgramStorage); + + // Windows wants a command line, not an array of args, to pass to the new + // process. We have to concatenate them all, while quoting the args that + // have embedded spaces (or are empty). auto Result = flattenWindowsCommandLine(Args); if (std::error_code ec = Result.getError()) { SetLastError(ec.value()); @@ -197,143 +197,143 @@ static bool Execute(ProcessInfo &PI, StringRef Program, return false; } std::wstring Command = *Result; - - // The pointer to the environment block for the new process. - std::vector<wchar_t> EnvBlock; - - if (Env) { - // An environment block consists of a null-terminated block of - // null-terminated strings. Convert the array of environment variables to - // an environment block by concatenating them. - for (StringRef E : *Env) { - SmallVector<wchar_t, MAX_PATH> EnvString; - if (std::error_code ec = windows::UTF8ToUTF16(E, EnvString)) { - SetLastError(ec.value()); - MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16"); - return false; - } - + + // The pointer to the environment block for the new process. + std::vector<wchar_t> EnvBlock; + + if (Env) { + // An environment block consists of a null-terminated block of + // null-terminated strings. Convert the array of environment variables to + // an environment block by concatenating them. + for (StringRef E : *Env) { + SmallVector<wchar_t, MAX_PATH> EnvString; + if (std::error_code ec = windows::UTF8ToUTF16(E, EnvString)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16"); + return false; + } + llvm::append_range(EnvBlock, EnvString); - EnvBlock.push_back(0); - } - EnvBlock.push_back(0); - } - - // Create a child process. - STARTUPINFOW si; - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.hStdInput = INVALID_HANDLE_VALUE; - si.hStdOutput = INVALID_HANDLE_VALUE; - si.hStdError = INVALID_HANDLE_VALUE; - - if (!Redirects.empty()) { - si.dwFlags = STARTF_USESTDHANDLES; - - si.hStdInput = RedirectIO(Redirects[0], 0, ErrMsg); - if (si.hStdInput == INVALID_HANDLE_VALUE) { - MakeErrMsg(ErrMsg, "can't redirect stdin"); - return false; - } - si.hStdOutput = RedirectIO(Redirects[1], 1, ErrMsg); - if (si.hStdOutput == INVALID_HANDLE_VALUE) { - CloseHandle(si.hStdInput); - MakeErrMsg(ErrMsg, "can't redirect stdout"); - return false; - } - if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) { - // If stdout and stderr should go to the same place, redirect stderr - // to the handle already open for stdout. - if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput, - GetCurrentProcess(), &si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS)) { - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - MakeErrMsg(ErrMsg, "can't dup stderr to stdout"); - return false; - } - } else { - // Just redirect stderr - si.hStdError = RedirectIO(Redirects[2], 2, ErrMsg); - if (si.hStdError == INVALID_HANDLE_VALUE) { - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - MakeErrMsg(ErrMsg, "can't redirect stderr"); - return false; - } - } - } - - PROCESS_INFORMATION pi; - memset(&pi, 0, sizeof(pi)); - - fflush(stdout); - fflush(stderr); - - SmallVector<wchar_t, MAX_PATH> ProgramUtf16; - if (std::error_code ec = sys::windows::widenPath(Program, ProgramUtf16)) { - SetLastError(ec.value()); - MakeErrMsg(ErrMsg, - std::string("Unable to convert application name to UTF-16")); - return false; - } - + EnvBlock.push_back(0); + } + EnvBlock.push_back(0); + } + + // Create a child process. + STARTUPINFOW si; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.hStdInput = INVALID_HANDLE_VALUE; + si.hStdOutput = INVALID_HANDLE_VALUE; + si.hStdError = INVALID_HANDLE_VALUE; + + if (!Redirects.empty()) { + si.dwFlags = STARTF_USESTDHANDLES; + + si.hStdInput = RedirectIO(Redirects[0], 0, ErrMsg); + if (si.hStdInput == INVALID_HANDLE_VALUE) { + MakeErrMsg(ErrMsg, "can't redirect stdin"); + return false; + } + si.hStdOutput = RedirectIO(Redirects[1], 1, ErrMsg); + if (si.hStdOutput == INVALID_HANDLE_VALUE) { + CloseHandle(si.hStdInput); + MakeErrMsg(ErrMsg, "can't redirect stdout"); + return false; + } + if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) { + // If stdout and stderr should go to the same place, redirect stderr + // to the handle already open for stdout. + if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput, + GetCurrentProcess(), &si.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS)) { + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + MakeErrMsg(ErrMsg, "can't dup stderr to stdout"); + return false; + } + } else { + // Just redirect stderr + si.hStdError = RedirectIO(Redirects[2], 2, ErrMsg); + if (si.hStdError == INVALID_HANDLE_VALUE) { + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + MakeErrMsg(ErrMsg, "can't redirect stderr"); + return false; + } + } + } + + PROCESS_INFORMATION pi; + memset(&pi, 0, sizeof(pi)); + + fflush(stdout); + fflush(stderr); + + SmallVector<wchar_t, MAX_PATH> ProgramUtf16; + if (std::error_code ec = sys::windows::widenPath(Program, ProgramUtf16)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, + std::string("Unable to convert application name to UTF-16")); + return false; + } + unsigned CreateFlags = CREATE_UNICODE_ENVIRONMENT; if (AffinityMask) CreateFlags |= CREATE_SUSPENDED; - + std::vector<wchar_t> CommandUtf16(Command.size() + 1, 0); std::copy(Command.begin(), Command.end(), CommandUtf16.begin()); BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0, TRUE, CreateFlags, EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si, &pi); - DWORD err = GetLastError(); - - // Regardless of whether the process got created or not, we are done with - // the handles we created for it to inherit. - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - CloseHandle(si.hStdError); - - // Now return an error if the process didn't get created. - if (!rc) { - SetLastError(err); - MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + - Program.str() + "'"); - return false; - } - - PI.Pid = pi.dwProcessId; - PI.Process = pi.hProcess; - - // Make sure these get closed no matter what. - ScopedCommonHandle hThread(pi.hThread); - - // Assign the process to a job if a memory limit is defined. - ScopedJobHandle hJob; - if (MemoryLimit != 0) { - hJob = CreateJobObjectW(0, 0); - bool success = false; - if (hJob) { - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; - memset(&jeli, 0, sizeof(jeli)); - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; - jeli.ProcessMemoryLimit = uintptr_t(MemoryLimit) * 1048576; - if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, - &jeli, sizeof(jeli))) { - if (AssignProcessToJobObject(hJob, pi.hProcess)) - success = true; - } - } - if (!success) { - SetLastError(GetLastError()); - MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); - TerminateProcess(pi.hProcess, 1); - WaitForSingleObject(pi.hProcess, INFINITE); - return false; - } - } - + DWORD err = GetLastError(); + + // Regardless of whether the process got created or not, we are done with + // the handles we created for it to inherit. + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + // Now return an error if the process didn't get created. + if (!rc) { + SetLastError(err); + MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + + Program.str() + "'"); + return false; + } + + PI.Pid = pi.dwProcessId; + PI.Process = pi.hProcess; + + // Make sure these get closed no matter what. + ScopedCommonHandle hThread(pi.hThread); + + // Assign the process to a job if a memory limit is defined. + ScopedJobHandle hJob; + if (MemoryLimit != 0) { + hJob = CreateJobObjectW(0, 0); + bool success = false; + if (hJob) { + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; + memset(&jeli, 0, sizeof(jeli)); + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; + jeli.ProcessMemoryLimit = uintptr_t(MemoryLimit) * 1048576; + if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, + &jeli, sizeof(jeli))) { + if (AssignProcessToJobObject(hJob, pi.hProcess)) + success = true; + } + } + if (!success) { + SetLastError(GetLastError()); + MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); + TerminateProcess(pi.hProcess, 1); + WaitForSingleObject(pi.hProcess, INFINITE); + return false; + } + } + // Set the affinity mask if (AffinityMask) { ::SetProcessAffinityMask(pi.hProcess, @@ -341,222 +341,222 @@ static bool Execute(ProcessInfo &PI, StringRef Program, ::ResumeThread(pi.hThread); } - return true; -} - -static bool argNeedsQuotes(StringRef Arg) { - if (Arg.empty()) - return true; - return StringRef::npos != Arg.find_first_of("\t \"&\'()*<>\\`^|\n"); -} - -static std::string quoteSingleArg(StringRef Arg) { - std::string Result; - Result.push_back('"'); - - while (!Arg.empty()) { - size_t FirstNonBackslash = Arg.find_first_not_of('\\'); - size_t BackslashCount = FirstNonBackslash; - if (FirstNonBackslash == StringRef::npos) { - // The entire remainder of the argument is backslashes. Escape all of - // them and just early out. - BackslashCount = Arg.size(); - Result.append(BackslashCount * 2, '\\'); - break; - } - - if (Arg[FirstNonBackslash] == '\"') { - // This is an embedded quote. Escape all preceding backslashes, then - // add one additional backslash to escape the quote. - Result.append(BackslashCount * 2 + 1, '\\'); - Result.push_back('\"'); - } else { - // This is just a normal character. Don't escape any of the preceding - // backslashes, just append them as they are and then append the - // character. - Result.append(BackslashCount, '\\'); - Result.push_back(Arg[FirstNonBackslash]); - } - - // Drop all the backslashes, plus the following character. - Arg = Arg.drop_front(FirstNonBackslash + 1); - } - - Result.push_back('"'); - return Result; -} - -namespace llvm { + return true; +} + +static bool argNeedsQuotes(StringRef Arg) { + if (Arg.empty()) + return true; + return StringRef::npos != Arg.find_first_of("\t \"&\'()*<>\\`^|\n"); +} + +static std::string quoteSingleArg(StringRef Arg) { + std::string Result; + Result.push_back('"'); + + while (!Arg.empty()) { + size_t FirstNonBackslash = Arg.find_first_not_of('\\'); + size_t BackslashCount = FirstNonBackslash; + if (FirstNonBackslash == StringRef::npos) { + // The entire remainder of the argument is backslashes. Escape all of + // them and just early out. + BackslashCount = Arg.size(); + Result.append(BackslashCount * 2, '\\'); + break; + } + + if (Arg[FirstNonBackslash] == '\"') { + // This is an embedded quote. Escape all preceding backslashes, then + // add one additional backslash to escape the quote. + Result.append(BackslashCount * 2 + 1, '\\'); + Result.push_back('\"'); + } else { + // This is just a normal character. Don't escape any of the preceding + // backslashes, just append them as they are and then append the + // character. + Result.append(BackslashCount, '\\'); + Result.push_back(Arg[FirstNonBackslash]); + } + + // Drop all the backslashes, plus the following character. + Arg = Arg.drop_front(FirstNonBackslash + 1); + } + + Result.push_back('"'); + return Result; +} + +namespace llvm { ErrorOr<std::wstring> sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) { - std::string Command; - for (StringRef Arg : Args) { - if (argNeedsQuotes(Arg)) - Command += quoteSingleArg(Arg); - else - Command += Arg; - - Command.push_back(' '); - } - + std::string Command; + for (StringRef Arg : Args) { + if (argNeedsQuotes(Arg)) + Command += quoteSingleArg(Arg); + else + Command += Arg; + + Command.push_back(' '); + } + SmallVector<wchar_t, MAX_PATH> CommandUtf16; if (std::error_code ec = windows::UTF8ToUTF16(Command, CommandUtf16)) return ec; return std::wstring(CommandUtf16.begin(), CommandUtf16.end()); -} - -ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, - bool WaitUntilChildTerminates, std::string *ErrMsg, - Optional<ProcessStatistics> *ProcStat) { - assert(PI.Pid && "invalid pid to wait on, process not started?"); - assert((PI.Process && PI.Process != INVALID_HANDLE_VALUE) && - "invalid process handle to wait on, process not started?"); - DWORD milliSecondsToWait = 0; - if (WaitUntilChildTerminates) - milliSecondsToWait = INFINITE; - else if (SecondsToWait > 0) - milliSecondsToWait = SecondsToWait * 1000; - - ProcessInfo WaitResult = PI; - if (ProcStat) - ProcStat->reset(); - DWORD WaitStatus = WaitForSingleObject(PI.Process, milliSecondsToWait); - if (WaitStatus == WAIT_TIMEOUT) { - if (SecondsToWait) { - if (!TerminateProcess(PI.Process, 1)) { - if (ErrMsg) - MakeErrMsg(ErrMsg, "Failed to terminate timed-out program"); - - // -2 indicates a crash or timeout as opposed to failure to execute. - WaitResult.ReturnCode = -2; - CloseHandle(PI.Process); - return WaitResult; - } - WaitForSingleObject(PI.Process, INFINITE); - CloseHandle(PI.Process); - } else { - // Non-blocking wait. - return ProcessInfo(); - } - } - - // Get process execution statistics. - if (ProcStat) { - FILETIME CreationTime, ExitTime, KernelTime, UserTime; - PROCESS_MEMORY_COUNTERS MemInfo; - if (GetProcessTimes(PI.Process, &CreationTime, &ExitTime, &KernelTime, - &UserTime) && - GetProcessMemoryInfo(PI.Process, &MemInfo, sizeof(MemInfo))) { - auto UserT = std::chrono::duration_cast<std::chrono::microseconds>( - toDuration(UserTime)); - auto KernelT = std::chrono::duration_cast<std::chrono::microseconds>( - toDuration(KernelTime)); - uint64_t PeakMemory = MemInfo.PeakPagefileUsage / 1024; - *ProcStat = ProcessStatistics{UserT + KernelT, UserT, PeakMemory}; - } - } - - // Get its exit status. - DWORD status; - BOOL rc = GetExitCodeProcess(PI.Process, &status); - DWORD err = GetLastError(); - if (err != ERROR_INVALID_HANDLE) - CloseHandle(PI.Process); - - if (!rc) { - SetLastError(err); - if (ErrMsg) - MakeErrMsg(ErrMsg, "Failed getting status for program"); - - // -2 indicates a crash or timeout as opposed to failure to execute. - WaitResult.ReturnCode = -2; - return WaitResult; - } - - if (!status) - return WaitResult; - - // Pass 10(Warning) and 11(Error) to the callee as negative value. - if ((status & 0xBFFF0000U) == 0x80000000U) - WaitResult.ReturnCode = static_cast<int>(status); - else if (status & 0xFF) - WaitResult.ReturnCode = status & 0x7FFFFFFF; - else - WaitResult.ReturnCode = 1; - - return WaitResult; -} - -std::error_code sys::ChangeStdinToBinary() { - int result = _setmode(_fileno(stdin), _O_BINARY); - if (result == -1) - return std::error_code(errno, std::generic_category()); - return std::error_code(); -} - -std::error_code sys::ChangeStdoutToBinary() { - int result = _setmode(_fileno(stdout), _O_BINARY); - if (result == -1) - return std::error_code(errno, std::generic_category()); - return std::error_code(); -} - -std::error_code -llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, - WindowsEncodingMethod Encoding) { - std::error_code EC; - llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OF_Text); - if (EC) - return EC; - - if (Encoding == WEM_UTF8) { - OS << Contents; - } else if (Encoding == WEM_CurrentCodePage) { - SmallVector<wchar_t, 1> ArgsUTF16; - SmallVector<char, 1> ArgsCurCP; - - if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16))) - return EC; - - if ((EC = windows::UTF16ToCurCP( - ArgsUTF16.data(), ArgsUTF16.size(), ArgsCurCP))) - return EC; - - OS.write(ArgsCurCP.data(), ArgsCurCP.size()); - } else if (Encoding == WEM_UTF16) { - SmallVector<wchar_t, 1> ArgsUTF16; - - if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16))) - return EC; - - // Endianness guessing - char BOM[2]; - uint16_t src = UNI_UTF16_BYTE_ORDER_MARK_NATIVE; - memcpy(BOM, &src, 2); - OS.write(BOM, 2); - OS.write((char *)ArgsUTF16.data(), ArgsUTF16.size() << 1); - } else { - llvm_unreachable("Unknown encoding"); - } - - if (OS.has_error()) - return make_error_code(errc::io_error); - - return EC; -} - -bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, - ArrayRef<StringRef> Args) { +} + +ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, + bool WaitUntilChildTerminates, std::string *ErrMsg, + Optional<ProcessStatistics> *ProcStat) { + assert(PI.Pid && "invalid pid to wait on, process not started?"); + assert((PI.Process && PI.Process != INVALID_HANDLE_VALUE) && + "invalid process handle to wait on, process not started?"); + DWORD milliSecondsToWait = 0; + if (WaitUntilChildTerminates) + milliSecondsToWait = INFINITE; + else if (SecondsToWait > 0) + milliSecondsToWait = SecondsToWait * 1000; + + ProcessInfo WaitResult = PI; + if (ProcStat) + ProcStat->reset(); + DWORD WaitStatus = WaitForSingleObject(PI.Process, milliSecondsToWait); + if (WaitStatus == WAIT_TIMEOUT) { + if (SecondsToWait) { + if (!TerminateProcess(PI.Process, 1)) { + if (ErrMsg) + MakeErrMsg(ErrMsg, "Failed to terminate timed-out program"); + + // -2 indicates a crash or timeout as opposed to failure to execute. + WaitResult.ReturnCode = -2; + CloseHandle(PI.Process); + return WaitResult; + } + WaitForSingleObject(PI.Process, INFINITE); + CloseHandle(PI.Process); + } else { + // Non-blocking wait. + return ProcessInfo(); + } + } + + // Get process execution statistics. + if (ProcStat) { + FILETIME CreationTime, ExitTime, KernelTime, UserTime; + PROCESS_MEMORY_COUNTERS MemInfo; + if (GetProcessTimes(PI.Process, &CreationTime, &ExitTime, &KernelTime, + &UserTime) && + GetProcessMemoryInfo(PI.Process, &MemInfo, sizeof(MemInfo))) { + auto UserT = std::chrono::duration_cast<std::chrono::microseconds>( + toDuration(UserTime)); + auto KernelT = std::chrono::duration_cast<std::chrono::microseconds>( + toDuration(KernelTime)); + uint64_t PeakMemory = MemInfo.PeakPagefileUsage / 1024; + *ProcStat = ProcessStatistics{UserT + KernelT, UserT, PeakMemory}; + } + } + + // Get its exit status. + DWORD status; + BOOL rc = GetExitCodeProcess(PI.Process, &status); + DWORD err = GetLastError(); + if (err != ERROR_INVALID_HANDLE) + CloseHandle(PI.Process); + + if (!rc) { + SetLastError(err); + if (ErrMsg) + MakeErrMsg(ErrMsg, "Failed getting status for program"); + + // -2 indicates a crash or timeout as opposed to failure to execute. + WaitResult.ReturnCode = -2; + return WaitResult; + } + + if (!status) + return WaitResult; + + // Pass 10(Warning) and 11(Error) to the callee as negative value. + if ((status & 0xBFFF0000U) == 0x80000000U) + WaitResult.ReturnCode = static_cast<int>(status); + else if (status & 0xFF) + WaitResult.ReturnCode = status & 0x7FFFFFFF; + else + WaitResult.ReturnCode = 1; + + return WaitResult; +} + +std::error_code sys::ChangeStdinToBinary() { + int result = _setmode(_fileno(stdin), _O_BINARY); + if (result == -1) + return std::error_code(errno, std::generic_category()); + return std::error_code(); +} + +std::error_code sys::ChangeStdoutToBinary() { + int result = _setmode(_fileno(stdout), _O_BINARY); + if (result == -1) + return std::error_code(errno, std::generic_category()); + return std::error_code(); +} + +std::error_code +llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, + WindowsEncodingMethod Encoding) { + std::error_code EC; + llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OF_Text); + if (EC) + return EC; + + if (Encoding == WEM_UTF8) { + OS << Contents; + } else if (Encoding == WEM_CurrentCodePage) { + SmallVector<wchar_t, 1> ArgsUTF16; + SmallVector<char, 1> ArgsCurCP; + + if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16))) + return EC; + + if ((EC = windows::UTF16ToCurCP( + ArgsUTF16.data(), ArgsUTF16.size(), ArgsCurCP))) + return EC; + + OS.write(ArgsCurCP.data(), ArgsCurCP.size()); + } else if (Encoding == WEM_UTF16) { + SmallVector<wchar_t, 1> ArgsUTF16; + + if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16))) + return EC; + + // Endianness guessing + char BOM[2]; + uint16_t src = UNI_UTF16_BYTE_ORDER_MARK_NATIVE; + memcpy(BOM, &src, 2); + OS.write(BOM, 2); + OS.write((char *)ArgsUTF16.data(), ArgsUTF16.size() << 1); + } else { + llvm_unreachable("Unknown encoding"); + } + + if (OS.has_error()) + return make_error_code(errc::io_error); + + return EC; +} + +bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, + ArrayRef<StringRef> Args) { // The documentation on CreateProcessW states that the size of the argument // lpCommandLine must not be greater than 32767 characters, including the // Unicode terminating null character. We use smaller value to reduce risk // of getting invalid command line due to unaccounted factors. static const size_t MaxCommandStringLength = 32000; - SmallVector<StringRef, 8> FullArgs; - FullArgs.push_back(Program); - FullArgs.append(Args.begin(), Args.end()); + SmallVector<StringRef, 8> FullArgs; + FullArgs.push_back(Program); + FullArgs.append(Args.begin(), Args.end()); auto Result = flattenWindowsCommandLine(FullArgs); assert(!Result.getError()); return (Result->size() + 1) <= MaxCommandStringLength; -} -} +} +} diff --git a/contrib/libs/llvm12/lib/Support/Windows/Signals.inc b/contrib/libs/llvm12/lib/Support/Windows/Signals.inc index 6d6a7e3001..3758582b35 100644 --- a/contrib/libs/llvm12/lib/Support/Windows/Signals.inc +++ b/contrib/libs/llvm12/lib/Support/Windows/Signals.inc @@ -1,873 +1,873 @@ -//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of the Signals class. -// -//===----------------------------------------------------------------------===// -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/WindowsError.h" -#include <algorithm> -#include <io.h> -#include <signal.h> -#include <stdio.h> - -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" - -// The Windows.h header must be after LLVM and standard headers. -#include "llvm/Support/Windows/WindowsSupport.h" - -#ifdef __MINGW32__ - #include <imagehlp.h> -#else - #include <crtdbg.h> - #include <dbghelp.h> -#endif -#include <psapi.h> - -#ifdef _MSC_VER - #pragma comment(lib, "psapi.lib") -#elif __MINGW32__ - // The version of g++ that comes with MinGW does *not* properly understand - // the ll format specifier for printf. However, MinGW passes the format - // specifiers on to the MSVCRT entirely, and the CRT understands the ll - // specifier. So these warnings are spurious in this case. Since we compile - // with -Wall, this will generate these warnings which should be ignored. So - // we will turn off the warnings for this just file. However, MinGW also does - // not support push and pop for diagnostics, so we have to manually turn it - // back on at the end of the file. - #pragma GCC diagnostic ignored "-Wformat" - #pragma GCC diagnostic ignored "-Wformat-extra-args" - - #if !defined(__MINGW64_VERSION_MAJOR) - // MinGW.org does not have updated support for the 64-bit versions of the - // DebugHlp APIs. So we will have to load them manually. The structures and - // method signatures were pulled from DbgHelp.h in the Windows Platform SDK, - // and adjusted for brevity. - typedef struct _IMAGEHLP_LINE64 { - DWORD SizeOfStruct; - PVOID Key; - DWORD LineNumber; - PCHAR FileName; - DWORD64 Address; - } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; - - typedef struct _IMAGEHLP_SYMBOL64 { - DWORD SizeOfStruct; - DWORD64 Address; - DWORD Size; - DWORD Flags; - DWORD MaxNameLength; - CHAR Name[1]; - } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; - - typedef struct _tagADDRESS64 { - DWORD64 Offset; - WORD Segment; - ADDRESS_MODE Mode; - } ADDRESS64, *LPADDRESS64; - - typedef struct _KDHELP64 { - DWORD64 Thread; - DWORD ThCallbackStack; - DWORD ThCallbackBStore; - DWORD NextCallback; - DWORD FramePointer; - DWORD64 KiCallUserMode; - DWORD64 KeUserCallbackDispatcher; - DWORD64 SystemRangeStart; - DWORD64 KiUserExceptionDispatcher; - DWORD64 StackBase; - DWORD64 StackLimit; - DWORD64 Reserved[5]; - } KDHELP64, *PKDHELP64; - - typedef struct _tagSTACKFRAME64 { - ADDRESS64 AddrPC; - ADDRESS64 AddrReturn; - ADDRESS64 AddrFrame; - ADDRESS64 AddrStack; - ADDRESS64 AddrBStore; - PVOID FuncTableEntry; - DWORD64 Params[4]; - BOOL Far; - BOOL Virtual; - DWORD64 Reserved[3]; - KDHELP64 KdHelp; - } STACKFRAME64, *LPSTACKFRAME64; - #endif // !defined(__MINGW64_VERSION_MAJOR) -#endif // __MINGW32__ - -typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, - DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, - LPDWORD lpNumberOfBytesRead); - -typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess, - DWORD64 AddrBase); - -typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, - DWORD64 Address); - -typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, - HANDLE hThread, LPADDRESS64 lpaddr); - -typedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, - PMINIDUMP_EXCEPTION_INFORMATION, - PMINIDUMP_USER_STREAM_INFORMATION, - PMINIDUMP_CALLBACK_INFORMATION); -static fpMiniDumpWriteDump fMiniDumpWriteDump; - -typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, - PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, - PFUNCTION_TABLE_ACCESS_ROUTINE64, - PGET_MODULE_BASE_ROUTINE64, - PTRANSLATE_ADDRESS_ROUTINE64); -static fpStackWalk64 fStackWalk64; - -typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64); -static fpSymGetModuleBase64 fSymGetModuleBase64; - -typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, - PDWORD64, PIMAGEHLP_SYMBOL64); -static fpSymGetSymFromAddr64 fSymGetSymFromAddr64; - -typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, - PDWORD, PIMAGEHLP_LINE64); -static fpSymGetLineFromAddr64 fSymGetLineFromAddr64; - -typedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr, - PIMAGEHLP_MODULE64 ModuleInfo); -static fpSymGetModuleInfo64 fSymGetModuleInfo64; - -typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); -static fpSymFunctionTableAccess64 fSymFunctionTableAccess64; - -typedef DWORD (WINAPI *fpSymSetOptions)(DWORD); -static fpSymSetOptions fSymSetOptions; - -typedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL); -static fpSymInitialize fSymInitialize; - -typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); -static fpEnumerateLoadedModules fEnumerateLoadedModules; - -static bool load64BitDebugHelp(void) { - HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); - if (hLib) { - fMiniDumpWriteDump = (fpMiniDumpWriteDump) - ::GetProcAddress(hLib, "MiniDumpWriteDump"); - fStackWalk64 = (fpStackWalk64) - ::GetProcAddress(hLib, "StackWalk64"); - fSymGetModuleBase64 = (fpSymGetModuleBase64) - ::GetProcAddress(hLib, "SymGetModuleBase64"); - fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64) - ::GetProcAddress(hLib, "SymGetSymFromAddr64"); - fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64) - ::GetProcAddress(hLib, "SymGetLineFromAddr64"); - fSymGetModuleInfo64 = (fpSymGetModuleInfo64) - ::GetProcAddress(hLib, "SymGetModuleInfo64"); - fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64) - ::GetProcAddress(hLib, "SymFunctionTableAccess64"); - fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions"); - fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize"); - fEnumerateLoadedModules = (fpEnumerateLoadedModules) - ::GetProcAddress(hLib, "EnumerateLoadedModules64"); - } - return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; -} - -using namespace llvm; - -// Forward declare. -static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); -static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); - -// The function to call if ctrl-c is pressed. -static void (*InterruptFunction)() = 0; - -static std::vector<std::string> *FilesToRemove = NULL; -static bool RegisteredUnhandledExceptionFilter = false; -static bool CleanupExecuted = false; -static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; - -// Windows creates a new thread to execute the console handler when an event -// (such as CTRL/C) occurs. This causes concurrency issues with the above -// globals which this critical section addresses. -static CRITICAL_SECTION CriticalSection; -static bool CriticalSectionInitialized = false; - -static StringRef Argv0; - -enum { -#if defined(_M_X64) - NativeMachineType = IMAGE_FILE_MACHINE_AMD64 -#elif defined(_M_ARM64) - NativeMachineType = IMAGE_FILE_MACHINE_ARM64 -#elif defined(_M_IX86) - NativeMachineType = IMAGE_FILE_MACHINE_I386 -#elif defined(_M_ARM) - NativeMachineType = IMAGE_FILE_MACHINE_ARMNT -#else - NativeMachineType = IMAGE_FILE_MACHINE_UNKNOWN -#endif -}; - -static bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS, - HANDLE hProcess, HANDLE hThread, - STACKFRAME64 &StackFrameOrig, - CONTEXT *ContextOrig) { - // StackWalk64 modifies the incoming stack frame and context, so copy them. - STACKFRAME64 StackFrame = StackFrameOrig; - - // Copy the register context so that we don't modify it while we unwind. We - // could use InitializeContext + CopyContext, but that's only required to get - // at AVX registers, which typically aren't needed by StackWalk64. Reduce the - // flag set to indicate that there's less data. - CONTEXT Context = *ContextOrig; - Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; - - static void *StackTrace[256]; - size_t Depth = 0; - while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, - &Context, 0, fSymFunctionTableAccess64, - fSymGetModuleBase64, 0)) { - if (StackFrame.AddrFrame.Offset == 0) - break; - StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset; - if (Depth >= array_lengthof(StackTrace)) - break; - } - - return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS); -} - -namespace { -struct FindModuleData { - void **StackTrace; - int Depth; - const char **Modules; - intptr_t *Offsets; - StringSaver *StrPool; -}; -} - -static BOOL CALLBACK findModuleCallback(PCSTR ModuleName, - DWORD64 ModuleBase, ULONG ModuleSize, - void *VoidData) { - FindModuleData *Data = (FindModuleData*)VoidData; - intptr_t Beg = ModuleBase; - intptr_t End = Beg + ModuleSize; - for (int I = 0; I < Data->Depth; I++) { - if (Data->Modules[I]) - continue; - intptr_t Addr = (intptr_t)Data->StackTrace[I]; - if (Beg <= Addr && Addr < End) { - Data->Modules[I] = Data->StrPool->save(ModuleName).data(); - Data->Offsets[I] = Addr - Beg; - } - } - return TRUE; -} - -static bool findModulesAndOffsets(void **StackTrace, int Depth, - const char **Modules, intptr_t *Offsets, - const char *MainExecutableName, - StringSaver &StrPool) { - if (!fEnumerateLoadedModules) - return false; - FindModuleData Data; - Data.StackTrace = StackTrace; - Data.Depth = Depth; - Data.Modules = Modules; - Data.Offsets = Offsets; - Data.StrPool = &StrPool; - fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data); - return true; -} - -static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, - HANDLE hThread, STACKFRAME64 &StackFrame, - CONTEXT *Context) { - // Initialize the symbol handler. - fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); - fSymInitialize(hProcess, NULL, TRUE); - - // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs - // and DWARF, so it should do a good job regardless of what debug info or - // linker is in use. - if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame, - Context)) { - return; - } - - while (true) { - if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, - Context, 0, fSymFunctionTableAccess64, - fSymGetModuleBase64, 0)) { - break; - } - - if (StackFrame.AddrFrame.Offset == 0) - break; - - using namespace llvm; - // Print the PC in hexadecimal. - DWORD64 PC = StackFrame.AddrPC.Offset; -#if defined(_M_X64) || defined(_M_ARM64) - OS << format("0x%016llX", PC); -#elif defined(_M_IX86) || defined(_M_ARM) - OS << format("0x%08lX", static_cast<DWORD>(PC)); -#endif - -// Print the parameters. Assume there are four. -#if defined(_M_X64) || defined(_M_ARM64) - OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", - StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2], - StackFrame.Params[3]); -#elif defined(_M_IX86) || defined(_M_ARM) - OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", - static_cast<DWORD>(StackFrame.Params[0]), - static_cast<DWORD>(StackFrame.Params[1]), - static_cast<DWORD>(StackFrame.Params[2]), - static_cast<DWORD>(StackFrame.Params[3])); -#endif - // Verify the PC belongs to a module in this process. - if (!fSymGetModuleBase64(hProcess, PC)) { - OS << " <unknown module>\n"; - continue; - } - - // Print the symbol name. - char buffer[512]; - IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); - memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); - symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); - - DWORD64 dwDisp; - if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { - OS << '\n'; - continue; - } - - buffer[511] = 0; - if (dwDisp > 0) - OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name, - dwDisp); - else - OS << format(", %s", (const char*)symbol->Name); - - // Print the source file and line number information. - IMAGEHLP_LINE64 line = {}; - DWORD dwLineDisp; - line.SizeOfStruct = sizeof(line); - if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { - OS << format(", %s, line %lu", line.FileName, line.LineNumber); - if (dwLineDisp > 0) - OS << format(" + 0x%lX byte(s)", dwLineDisp); - } - - OS << '\n'; - } -} - -namespace llvm { - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -#ifdef _MSC_VER -/// Emulates hitting "retry" from an "abort, retry, ignore" CRT debug report -/// dialog. "retry" raises an exception which ultimately triggers our stack -/// dumper. -static LLVM_ATTRIBUTE_UNUSED int -AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { - // Set *Return to the retry code for the return value of _CrtDbgReport: - // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx - // This may also trigger just-in-time debugging via DebugBreak(). - if (Return) - *Return = 1; - // Don't call _CrtDbgReport. - return TRUE; -} - -#endif - -extern "C" void HandleAbort(int Sig) { - if (Sig == SIGABRT) { - LLVM_BUILTIN_TRAP; - } -} - -static void InitializeThreading() { - if (CriticalSectionInitialized) - return; - - // Now's the time to create the critical section. This is the first time - // through here, and there's only one thread. - InitializeCriticalSection(&CriticalSection); - CriticalSectionInitialized = true; -} - -static void RegisterHandler() { - // If we cannot load up the APIs (which would be unexpected as they should - // exist on every version of Windows we support), we will bail out since - // there would be nothing to report. - if (!load64BitDebugHelp()) { - assert(false && "These APIs should always be available"); - return; - } - - if (RegisteredUnhandledExceptionFilter) { - EnterCriticalSection(&CriticalSection); - return; - } - - InitializeThreading(); - - // Enter it immediately. Now if someone hits CTRL/C, the console handler - // can't proceed until the globals are updated. - EnterCriticalSection(&CriticalSection); - - RegisteredUnhandledExceptionFilter = true; - OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); - SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); - - // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or - // else multi-threading problems will ensue. -} - -// The public API -bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { - RegisterHandler(); - - if (CleanupExecuted) { - if (ErrMsg) - *ErrMsg = "Process terminating -- cannot register for removal"; - return true; - } - - if (FilesToRemove == NULL) - FilesToRemove = new std::vector<std::string>; - - FilesToRemove->push_back(std::string(Filename)); - - LeaveCriticalSection(&CriticalSection); - return false; -} - -// The public API -void sys::DontRemoveFileOnSignal(StringRef Filename) { - if (FilesToRemove == NULL) - return; - - RegisterHandler(); - - std::vector<std::string>::reverse_iterator I = - find(reverse(*FilesToRemove), Filename); - if (I != FilesToRemove->rend()) - FilesToRemove->erase(I.base()-1); - - LeaveCriticalSection(&CriticalSection); -} - -void sys::DisableSystemDialogsOnCrash() { - // Crash to stack trace handler on abort. - signal(SIGABRT, HandleAbort); - - // The following functions are not reliably accessible on MinGW. -#ifdef _MSC_VER - // We're already handling writing a "something went wrong" message. - _set_abort_behavior(0, _WRITE_ABORT_MSG); - // Disable Dr. Watson. - _set_abort_behavior(0, _CALL_REPORTFAULT); - _CrtSetReportHook(AvoidMessageBoxHook); -#endif - - // Disable standard error dialog box. - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | - SEM_NOOPENFILEERRORBOX); - _set_error_mode(_OUT_TO_STDERR); -} - -/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the -/// process, print a stack trace and then exit. -void sys::PrintStackTraceOnErrorSignal(StringRef Argv0, - bool DisableCrashReporting) { - ::Argv0 = Argv0; - - if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) - Process::PreventCoreFiles(); - - DisableSystemDialogsOnCrash(); - RegisterHandler(); - LeaveCriticalSection(&CriticalSection); -} -} - -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is -// missing it but mingw-w64 has it. -extern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord); -#endif - -static void LocalPrintStackTrace(raw_ostream &OS, PCONTEXT C) { - STACKFRAME64 StackFrame{}; - CONTEXT Context{}; - if (!C) { - ::RtlCaptureContext(&Context); - C = &Context; - } -#if defined(_M_X64) - StackFrame.AddrPC.Offset = Context.Rip; - StackFrame.AddrStack.Offset = Context.Rsp; - StackFrame.AddrFrame.Offset = Context.Rbp; -#elif defined(_M_IX86) - StackFrame.AddrPC.Offset = Context.Eip; - StackFrame.AddrStack.Offset = Context.Esp; - StackFrame.AddrFrame.Offset = Context.Ebp; -#elif defined(_M_ARM64) - StackFrame.AddrPC.Offset = Context.Pc; - StackFrame.AddrStack.Offset = Context.Sp; - StackFrame.AddrFrame.Offset = Context.Fp; -#elif defined(_M_ARM) - StackFrame.AddrPC.Offset = Context.Pc; - StackFrame.AddrStack.Offset = Context.Sp; - StackFrame.AddrFrame.Offset = Context.R11; -#endif - StackFrame.AddrPC.Mode = AddrModeFlat; - StackFrame.AddrStack.Mode = AddrModeFlat; - StackFrame.AddrFrame.Mode = AddrModeFlat; - PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(), - StackFrame, C); -} - +//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Signals class. +// +//===----------------------------------------------------------------------===// +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/WindowsError.h" +#include <algorithm> +#include <io.h> +#include <signal.h> +#include <stdio.h> + +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +// The Windows.h header must be after LLVM and standard headers. +#include "llvm/Support/Windows/WindowsSupport.h" + +#ifdef __MINGW32__ + #include <imagehlp.h> +#else + #include <crtdbg.h> + #include <dbghelp.h> +#endif +#include <psapi.h> + +#ifdef _MSC_VER + #pragma comment(lib, "psapi.lib") +#elif __MINGW32__ + // The version of g++ that comes with MinGW does *not* properly understand + // the ll format specifier for printf. However, MinGW passes the format + // specifiers on to the MSVCRT entirely, and the CRT understands the ll + // specifier. So these warnings are spurious in this case. Since we compile + // with -Wall, this will generate these warnings which should be ignored. So + // we will turn off the warnings for this just file. However, MinGW also does + // not support push and pop for diagnostics, so we have to manually turn it + // back on at the end of the file. + #pragma GCC diagnostic ignored "-Wformat" + #pragma GCC diagnostic ignored "-Wformat-extra-args" + + #if !defined(__MINGW64_VERSION_MAJOR) + // MinGW.org does not have updated support for the 64-bit versions of the + // DebugHlp APIs. So we will have to load them manually. The structures and + // method signatures were pulled from DbgHelp.h in the Windows Platform SDK, + // and adjusted for brevity. + typedef struct _IMAGEHLP_LINE64 { + DWORD SizeOfStruct; + PVOID Key; + DWORD LineNumber; + PCHAR FileName; + DWORD64 Address; + } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; + + typedef struct _IMAGEHLP_SYMBOL64 { + DWORD SizeOfStruct; + DWORD64 Address; + DWORD Size; + DWORD Flags; + DWORD MaxNameLength; + CHAR Name[1]; + } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; + + typedef struct _tagADDRESS64 { + DWORD64 Offset; + WORD Segment; + ADDRESS_MODE Mode; + } ADDRESS64, *LPADDRESS64; + + typedef struct _KDHELP64 { + DWORD64 Thread; + DWORD ThCallbackStack; + DWORD ThCallbackBStore; + DWORD NextCallback; + DWORD FramePointer; + DWORD64 KiCallUserMode; + DWORD64 KeUserCallbackDispatcher; + DWORD64 SystemRangeStart; + DWORD64 KiUserExceptionDispatcher; + DWORD64 StackBase; + DWORD64 StackLimit; + DWORD64 Reserved[5]; + } KDHELP64, *PKDHELP64; + + typedef struct _tagSTACKFRAME64 { + ADDRESS64 AddrPC; + ADDRESS64 AddrReturn; + ADDRESS64 AddrFrame; + ADDRESS64 AddrStack; + ADDRESS64 AddrBStore; + PVOID FuncTableEntry; + DWORD64 Params[4]; + BOOL Far; + BOOL Virtual; + DWORD64 Reserved[3]; + KDHELP64 KdHelp; + } STACKFRAME64, *LPSTACKFRAME64; + #endif // !defined(__MINGW64_VERSION_MAJOR) +#endif // __MINGW32__ + +typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, + DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, + LPDWORD lpNumberOfBytesRead); + +typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess, + DWORD64 AddrBase); + +typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, + DWORD64 Address); + +typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, + HANDLE hThread, LPADDRESS64 lpaddr); + +typedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, + PMINIDUMP_EXCEPTION_INFORMATION, + PMINIDUMP_USER_STREAM_INFORMATION, + PMINIDUMP_CALLBACK_INFORMATION); +static fpMiniDumpWriteDump fMiniDumpWriteDump; + +typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, + PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, + PFUNCTION_TABLE_ACCESS_ROUTINE64, + PGET_MODULE_BASE_ROUTINE64, + PTRANSLATE_ADDRESS_ROUTINE64); +static fpStackWalk64 fStackWalk64; + +typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64); +static fpSymGetModuleBase64 fSymGetModuleBase64; + +typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, + PDWORD64, PIMAGEHLP_SYMBOL64); +static fpSymGetSymFromAddr64 fSymGetSymFromAddr64; + +typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, + PDWORD, PIMAGEHLP_LINE64); +static fpSymGetLineFromAddr64 fSymGetLineFromAddr64; + +typedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr, + PIMAGEHLP_MODULE64 ModuleInfo); +static fpSymGetModuleInfo64 fSymGetModuleInfo64; + +typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); +static fpSymFunctionTableAccess64 fSymFunctionTableAccess64; + +typedef DWORD (WINAPI *fpSymSetOptions)(DWORD); +static fpSymSetOptions fSymSetOptions; + +typedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL); +static fpSymInitialize fSymInitialize; + +typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); +static fpEnumerateLoadedModules fEnumerateLoadedModules; + +static bool load64BitDebugHelp(void) { + HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); + if (hLib) { + fMiniDumpWriteDump = (fpMiniDumpWriteDump) + ::GetProcAddress(hLib, "MiniDumpWriteDump"); + fStackWalk64 = (fpStackWalk64) + ::GetProcAddress(hLib, "StackWalk64"); + fSymGetModuleBase64 = (fpSymGetModuleBase64) + ::GetProcAddress(hLib, "SymGetModuleBase64"); + fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64) + ::GetProcAddress(hLib, "SymGetSymFromAddr64"); + fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64) + ::GetProcAddress(hLib, "SymGetLineFromAddr64"); + fSymGetModuleInfo64 = (fpSymGetModuleInfo64) + ::GetProcAddress(hLib, "SymGetModuleInfo64"); + fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64) + ::GetProcAddress(hLib, "SymFunctionTableAccess64"); + fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions"); + fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize"); + fEnumerateLoadedModules = (fpEnumerateLoadedModules) + ::GetProcAddress(hLib, "EnumerateLoadedModules64"); + } + return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; +} + +using namespace llvm; + +// Forward declare. +static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); +static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); + +// The function to call if ctrl-c is pressed. +static void (*InterruptFunction)() = 0; + +static std::vector<std::string> *FilesToRemove = NULL; +static bool RegisteredUnhandledExceptionFilter = false; +static bool CleanupExecuted = false; +static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; + +// Windows creates a new thread to execute the console handler when an event +// (such as CTRL/C) occurs. This causes concurrency issues with the above +// globals which this critical section addresses. +static CRITICAL_SECTION CriticalSection; +static bool CriticalSectionInitialized = false; + +static StringRef Argv0; + +enum { +#if defined(_M_X64) + NativeMachineType = IMAGE_FILE_MACHINE_AMD64 +#elif defined(_M_ARM64) + NativeMachineType = IMAGE_FILE_MACHINE_ARM64 +#elif defined(_M_IX86) + NativeMachineType = IMAGE_FILE_MACHINE_I386 +#elif defined(_M_ARM) + NativeMachineType = IMAGE_FILE_MACHINE_ARMNT +#else + NativeMachineType = IMAGE_FILE_MACHINE_UNKNOWN +#endif +}; + +static bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS, + HANDLE hProcess, HANDLE hThread, + STACKFRAME64 &StackFrameOrig, + CONTEXT *ContextOrig) { + // StackWalk64 modifies the incoming stack frame and context, so copy them. + STACKFRAME64 StackFrame = StackFrameOrig; + + // Copy the register context so that we don't modify it while we unwind. We + // could use InitializeContext + CopyContext, but that's only required to get + // at AVX registers, which typically aren't needed by StackWalk64. Reduce the + // flag set to indicate that there's less data. + CONTEXT Context = *ContextOrig; + Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + + static void *StackTrace[256]; + size_t Depth = 0; + while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, + &Context, 0, fSymFunctionTableAccess64, + fSymGetModuleBase64, 0)) { + if (StackFrame.AddrFrame.Offset == 0) + break; + StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset; + if (Depth >= array_lengthof(StackTrace)) + break; + } + + return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS); +} + +namespace { +struct FindModuleData { + void **StackTrace; + int Depth; + const char **Modules; + intptr_t *Offsets; + StringSaver *StrPool; +}; +} + +static BOOL CALLBACK findModuleCallback(PCSTR ModuleName, + DWORD64 ModuleBase, ULONG ModuleSize, + void *VoidData) { + FindModuleData *Data = (FindModuleData*)VoidData; + intptr_t Beg = ModuleBase; + intptr_t End = Beg + ModuleSize; + for (int I = 0; I < Data->Depth; I++) { + if (Data->Modules[I]) + continue; + intptr_t Addr = (intptr_t)Data->StackTrace[I]; + if (Beg <= Addr && Addr < End) { + Data->Modules[I] = Data->StrPool->save(ModuleName).data(); + Data->Offsets[I] = Addr - Beg; + } + } + return TRUE; +} + +static bool findModulesAndOffsets(void **StackTrace, int Depth, + const char **Modules, intptr_t *Offsets, + const char *MainExecutableName, + StringSaver &StrPool) { + if (!fEnumerateLoadedModules) + return false; + FindModuleData Data; + Data.StackTrace = StackTrace; + Data.Depth = Depth; + Data.Modules = Modules; + Data.Offsets = Offsets; + Data.StrPool = &StrPool; + fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data); + return true; +} + +static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, + HANDLE hThread, STACKFRAME64 &StackFrame, + CONTEXT *Context) { + // Initialize the symbol handler. + fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); + fSymInitialize(hProcess, NULL, TRUE); + + // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs + // and DWARF, so it should do a good job regardless of what debug info or + // linker is in use. + if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame, + Context)) { + return; + } + + while (true) { + if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, + Context, 0, fSymFunctionTableAccess64, + fSymGetModuleBase64, 0)) { + break; + } + + if (StackFrame.AddrFrame.Offset == 0) + break; + + using namespace llvm; + // Print the PC in hexadecimal. + DWORD64 PC = StackFrame.AddrPC.Offset; +#if defined(_M_X64) || defined(_M_ARM64) + OS << format("0x%016llX", PC); +#elif defined(_M_IX86) || defined(_M_ARM) + OS << format("0x%08lX", static_cast<DWORD>(PC)); +#endif + +// Print the parameters. Assume there are four. +#if defined(_M_X64) || defined(_M_ARM64) + OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", + StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2], + StackFrame.Params[3]); +#elif defined(_M_IX86) || defined(_M_ARM) + OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", + static_cast<DWORD>(StackFrame.Params[0]), + static_cast<DWORD>(StackFrame.Params[1]), + static_cast<DWORD>(StackFrame.Params[2]), + static_cast<DWORD>(StackFrame.Params[3])); +#endif + // Verify the PC belongs to a module in this process. + if (!fSymGetModuleBase64(hProcess, PC)) { + OS << " <unknown module>\n"; + continue; + } + + // Print the symbol name. + char buffer[512]; + IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); + memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); + symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); + + DWORD64 dwDisp; + if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { + OS << '\n'; + continue; + } + + buffer[511] = 0; + if (dwDisp > 0) + OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name, + dwDisp); + else + OS << format(", %s", (const char*)symbol->Name); + + // Print the source file and line number information. + IMAGEHLP_LINE64 line = {}; + DWORD dwLineDisp; + line.SizeOfStruct = sizeof(line); + if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { + OS << format(", %s, line %lu", line.FileName, line.LineNumber); + if (dwLineDisp > 0) + OS << format(" + 0x%lX byte(s)", dwLineDisp); + } + + OS << '\n'; + } +} + +namespace llvm { + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +#ifdef _MSC_VER +/// Emulates hitting "retry" from an "abort, retry, ignore" CRT debug report +/// dialog. "retry" raises an exception which ultimately triggers our stack +/// dumper. +static LLVM_ATTRIBUTE_UNUSED int +AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { + // Set *Return to the retry code for the return value of _CrtDbgReport: + // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx + // This may also trigger just-in-time debugging via DebugBreak(). + if (Return) + *Return = 1; + // Don't call _CrtDbgReport. + return TRUE; +} + +#endif + +extern "C" void HandleAbort(int Sig) { + if (Sig == SIGABRT) { + LLVM_BUILTIN_TRAP; + } +} + +static void InitializeThreading() { + if (CriticalSectionInitialized) + return; + + // Now's the time to create the critical section. This is the first time + // through here, and there's only one thread. + InitializeCriticalSection(&CriticalSection); + CriticalSectionInitialized = true; +} + +static void RegisterHandler() { + // If we cannot load up the APIs (which would be unexpected as they should + // exist on every version of Windows we support), we will bail out since + // there would be nothing to report. + if (!load64BitDebugHelp()) { + assert(false && "These APIs should always be available"); + return; + } + + if (RegisteredUnhandledExceptionFilter) { + EnterCriticalSection(&CriticalSection); + return; + } + + InitializeThreading(); + + // Enter it immediately. Now if someone hits CTRL/C, the console handler + // can't proceed until the globals are updated. + EnterCriticalSection(&CriticalSection); + + RegisteredUnhandledExceptionFilter = true; + OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); + SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); + + // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or + // else multi-threading problems will ensue. +} + +// The public API +bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { + RegisterHandler(); + + if (CleanupExecuted) { + if (ErrMsg) + *ErrMsg = "Process terminating -- cannot register for removal"; + return true; + } + + if (FilesToRemove == NULL) + FilesToRemove = new std::vector<std::string>; + + FilesToRemove->push_back(std::string(Filename)); + + LeaveCriticalSection(&CriticalSection); + return false; +} + +// The public API +void sys::DontRemoveFileOnSignal(StringRef Filename) { + if (FilesToRemove == NULL) + return; + + RegisterHandler(); + + std::vector<std::string>::reverse_iterator I = + find(reverse(*FilesToRemove), Filename); + if (I != FilesToRemove->rend()) + FilesToRemove->erase(I.base()-1); + + LeaveCriticalSection(&CriticalSection); +} + +void sys::DisableSystemDialogsOnCrash() { + // Crash to stack trace handler on abort. + signal(SIGABRT, HandleAbort); + + // The following functions are not reliably accessible on MinGW. +#ifdef _MSC_VER + // We're already handling writing a "something went wrong" message. + _set_abort_behavior(0, _WRITE_ABORT_MSG); + // Disable Dr. Watson. + _set_abort_behavior(0, _CALL_REPORTFAULT); + _CrtSetReportHook(AvoidMessageBoxHook); +#endif + + // Disable standard error dialog box. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); + _set_error_mode(_OUT_TO_STDERR); +} + +/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the +/// process, print a stack trace and then exit. +void sys::PrintStackTraceOnErrorSignal(StringRef Argv0, + bool DisableCrashReporting) { + ::Argv0 = Argv0; + + if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) + Process::PreventCoreFiles(); + + DisableSystemDialogsOnCrash(); + RegisterHandler(); + LeaveCriticalSection(&CriticalSection); +} +} + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +// Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is +// missing it but mingw-w64 has it. +extern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord); +#endif + +static void LocalPrintStackTrace(raw_ostream &OS, PCONTEXT C) { + STACKFRAME64 StackFrame{}; + CONTEXT Context{}; + if (!C) { + ::RtlCaptureContext(&Context); + C = &Context; + } +#if defined(_M_X64) + StackFrame.AddrPC.Offset = Context.Rip; + StackFrame.AddrStack.Offset = Context.Rsp; + StackFrame.AddrFrame.Offset = Context.Rbp; +#elif defined(_M_IX86) + StackFrame.AddrPC.Offset = Context.Eip; + StackFrame.AddrStack.Offset = Context.Esp; + StackFrame.AddrFrame.Offset = Context.Ebp; +#elif defined(_M_ARM64) + StackFrame.AddrPC.Offset = Context.Pc; + StackFrame.AddrStack.Offset = Context.Sp; + StackFrame.AddrFrame.Offset = Context.Fp; +#elif defined(_M_ARM) + StackFrame.AddrPC.Offset = Context.Pc; + StackFrame.AddrStack.Offset = Context.Sp; + StackFrame.AddrFrame.Offset = Context.R11; +#endif + StackFrame.AddrPC.Mode = AddrModeFlat; + StackFrame.AddrStack.Mode = AddrModeFlat; + StackFrame.AddrFrame.Mode = AddrModeFlat; + PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(), + StackFrame, C); +} + void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) { // FIXME: Handle "Depth" parameter to print stack trace upto specified Depth - LocalPrintStackTrace(OS, nullptr); -} - -void llvm::sys::SetInterruptFunction(void (*IF)()) { - RegisterHandler(); - InterruptFunction = IF; - LeaveCriticalSection(&CriticalSection); -} - -void llvm::sys::SetInfoSignalFunction(void (*Handler)()) { - // Unimplemented. -} - -void llvm::sys::SetOneShotPipeSignalFunction(void (*Handler)()) { - // Unimplemented. -} - -void llvm::sys::DefaultOneShotPipeSignalHandler() { - // Unimplemented. -} - -/// Add a function to be called when a signal is delivered to the process. The -/// handler can have a cookie passed to it to identify what instance of the -/// handler it is. -void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, - void *Cookie) { - insertSignalHandler(FnPtr, Cookie); - RegisterHandler(); - LeaveCriticalSection(&CriticalSection); -} - -static void Cleanup(bool ExecuteSignalHandlers) { - if (CleanupExecuted) - return; - - EnterCriticalSection(&CriticalSection); - - // Prevent other thread from registering new files and directories for - // removal, should we be executing because of the console handler callback. - CleanupExecuted = true; - - // FIXME: open files cannot be deleted. - if (FilesToRemove != NULL) - while (!FilesToRemove->empty()) { - llvm::sys::fs::remove(FilesToRemove->back()); - FilesToRemove->pop_back(); - } - - if (ExecuteSignalHandlers) - llvm::sys::RunSignalHandlers(); - - LeaveCriticalSection(&CriticalSection); -} - -void llvm::sys::RunInterruptHandlers() { - // The interrupt handler may be called from an interrupt, but it may also be - // called manually (such as the case of report_fatal_error with no registered - // error handler). We must ensure that the critical section is properly - // initialized. - InitializeThreading(); - Cleanup(true); -} - -/// Find the Windows Registry Key for a given location. -/// -/// \returns a valid HKEY if the location exists, else NULL. -static HKEY FindWERKey(const llvm::Twine &RegistryLocation) { - HKEY Key; - if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, - RegistryLocation.str().c_str(), 0, - KEY_QUERY_VALUE | KEY_READ, &Key)) - return NULL; - - return Key; -} - -/// Populate ResultDirectory with the value for "DumpFolder" for a given -/// Windows Registry key. -/// -/// \returns true if a valid value for DumpFolder exists, false otherwise. -static bool GetDumpFolder(HKEY Key, - llvm::SmallVectorImpl<char> &ResultDirectory) { - using llvm::sys::windows::UTF16ToUTF8; - - if (!Key) - return false; - - DWORD BufferLengthBytes = 0; - - if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, - NULL, NULL, &BufferLengthBytes)) - return false; - - SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes); - - if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, - NULL, Buffer.data(), &BufferLengthBytes)) - return false; - - DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0); - - if (!ExpandBufferSize) - return false; - - SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize); - - if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(), - ExpandBuffer.data(), - ExpandBufferSize)) - return false; - - if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory)) - return false; - - return true; -} - -/// Populate ResultType with a valid MINIDUMP_TYPE based on the value of -/// "DumpType" for a given Windows Registry key. -/// -/// According to -/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx -/// valid values for DumpType are: -/// * 0: Custom dump -/// * 1: Mini dump -/// * 2: Full dump -/// If "Custom dump" is specified then the "CustomDumpFlags" field is read -/// containing a bitwise combination of MINIDUMP_TYPE values. -/// -/// \returns true if a valid value for ResultType can be set, false otherwise. -static bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) { - if (!Key) - return false; - - DWORD DumpType; - DWORD TypeSize = sizeof(DumpType); - if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD, - NULL, &DumpType, - &TypeSize)) - return false; - - switch (DumpType) { - case 0: { - DWORD Flags = 0; - if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags", - RRF_RT_REG_DWORD, NULL, &Flags, - &TypeSize)) - return false; - - ResultType = static_cast<MINIDUMP_TYPE>(Flags); - break; - } - case 1: - ResultType = MiniDumpNormal; - break; - case 2: - ResultType = MiniDumpWithFullMemory; - break; - default: - return false; - } - return true; -} - -/// Write a Windows dump file containing process information that can be -/// used for post-mortem debugging. -/// -/// \returns zero error code if a mini dump created, actual error code -/// otherwise. -static std::error_code WINAPI -WriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) { - using namespace llvm; - using namespace llvm::sys; - - std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr); - StringRef ProgramName; - - if (MainExecutableName.empty()) { - // If we can't get the executable filename, - // things are in worse shape than we realize - // and we should just bail out. - return mapWindowsError(::GetLastError()); - } - - ProgramName = path::filename(MainExecutableName.c_str()); - - // The Windows Registry location as specified at - // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx - // "Collecting User-Mode Dumps" that may optionally be set to collect crash - // dumps in a specified location. - StringRef LocalDumpsRegistryLocation = - "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps"; - - // The key pointing to the Registry location that may contain global crash - // dump settings. This will be NULL if the location can not be found. - ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation)); - - // The key pointing to the Registry location that may contain - // application-specific crash dump settings. This will be NULL if the - // location can not be found. - ScopedRegHandle AppSpecificKey( - FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName)); - - // Look to see if a dump type is specified in the registry; first with the - // app-specific key and failing that with the global key. If none are found - // default to a normal dump (GetDumpType will return false either if the key - // is NULL or if there is no valid DumpType value at its location). - MINIDUMP_TYPE DumpType; - if (!GetDumpType(AppSpecificKey, DumpType)) - if (!GetDumpType(DefaultLocalDumpsKey, DumpType)) - DumpType = MiniDumpNormal; - - // Look to see if a dump location is specified in the registry; first with the - // app-specific key and failing that with the global key. If none are found - // we'll just create the dump file in the default temporary file location - // (GetDumpFolder will return false either if the key is NULL or if there is - // no valid DumpFolder value at its location). - bool ExplicitDumpDirectorySet = true; - SmallString<MAX_PATH> DumpDirectory; - if (!GetDumpFolder(AppSpecificKey, DumpDirectory)) - if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory)) - ExplicitDumpDirectorySet = false; - - int FD; - SmallString<MAX_PATH> DumpPath; - - if (ExplicitDumpDirectorySet) { - if (std::error_code EC = fs::create_directories(DumpDirectory)) - return EC; - if (std::error_code EC = fs::createUniqueFile( - Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD, - DumpPath)) - return EC; - } else if (std::error_code EC = - fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath)) - return EC; - - // Our support functions return a file descriptor but Windows wants a handle. - ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD))); - - if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), - FileHandle, DumpType, ExceptionInfo, NULL, NULL)) - return mapWindowsError(::GetLastError()); - - llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n"; - return std::error_code(); -} - -void sys::CleanupOnSignal(uintptr_t Context) { - LLVMUnhandledExceptionFilter((LPEXCEPTION_POINTERS)Context); -} - -static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { - Cleanup(true); - - // We'll automatically write a Minidump file here to help diagnose - // the nasty sorts of crashes that aren't 100% reproducible from a set of - // inputs (or in the event that the user is unable or unwilling to provide a - // reproducible case). - if (!llvm::sys::Process::AreCoreFilesPrevented()) { - MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo; - ExceptionInfo.ThreadId = ::GetCurrentThreadId(); - ExceptionInfo.ExceptionPointers = ep; - ExceptionInfo.ClientPointers = FALSE; - - if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo)) - llvm::errs() << "Could not write crash dump file: " << EC.message() - << "\n"; - } - - // Stack unwinding appears to modify the context. Copy it to preserve the - // caller's context. - CONTEXT ContextCopy; - if (ep) - memcpy(&ContextCopy, ep->ContextRecord, sizeof(ContextCopy)); - - LocalPrintStackTrace(llvm::errs(), ep ? &ContextCopy : nullptr); - - return EXCEPTION_EXECUTE_HANDLER; -} - -static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { - // We are running in our very own thread, courtesy of Windows. - EnterCriticalSection(&CriticalSection); - // This function is only ever called when a CTRL-C or similar control signal - // is fired. Killing a process in this way is normal, so don't trigger the - // signal handlers. - Cleanup(false); - - // If an interrupt function has been set, go and run one it; otherwise, - // the process dies. - void (*IF)() = InterruptFunction; - InterruptFunction = 0; // Don't run it on another CTRL-C. - - if (IF) { - // Note: if the interrupt function throws an exception, there is nothing - // to catch it in this thread so it will kill the process. - IF(); // Run it now. - LeaveCriticalSection(&CriticalSection); - return TRUE; // Don't kill the process. - } - - // Allow normal processing to take place; i.e., the process dies. - LeaveCriticalSection(&CriticalSection); - return FALSE; -} - -#if __MINGW32__ - // We turned these warnings off for this file so that MinGW-g++ doesn't - // complain about the ll format specifiers used. Now we are turning the - // warnings back on. If MinGW starts to support diagnostic stacks, we can - // replace this with a pop. - #pragma GCC diagnostic warning "-Wformat" - #pragma GCC diagnostic warning "-Wformat-extra-args" -#endif + LocalPrintStackTrace(OS, nullptr); +} + +void llvm::sys::SetInterruptFunction(void (*IF)()) { + RegisterHandler(); + InterruptFunction = IF; + LeaveCriticalSection(&CriticalSection); +} + +void llvm::sys::SetInfoSignalFunction(void (*Handler)()) { + // Unimplemented. +} + +void llvm::sys::SetOneShotPipeSignalFunction(void (*Handler)()) { + // Unimplemented. +} + +void llvm::sys::DefaultOneShotPipeSignalHandler() { + // Unimplemented. +} + +/// Add a function to be called when a signal is delivered to the process. The +/// handler can have a cookie passed to it to identify what instance of the +/// handler it is. +void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, + void *Cookie) { + insertSignalHandler(FnPtr, Cookie); + RegisterHandler(); + LeaveCriticalSection(&CriticalSection); +} + +static void Cleanup(bool ExecuteSignalHandlers) { + if (CleanupExecuted) + return; + + EnterCriticalSection(&CriticalSection); + + // Prevent other thread from registering new files and directories for + // removal, should we be executing because of the console handler callback. + CleanupExecuted = true; + + // FIXME: open files cannot be deleted. + if (FilesToRemove != NULL) + while (!FilesToRemove->empty()) { + llvm::sys::fs::remove(FilesToRemove->back()); + FilesToRemove->pop_back(); + } + + if (ExecuteSignalHandlers) + llvm::sys::RunSignalHandlers(); + + LeaveCriticalSection(&CriticalSection); +} + +void llvm::sys::RunInterruptHandlers() { + // The interrupt handler may be called from an interrupt, but it may also be + // called manually (such as the case of report_fatal_error with no registered + // error handler). We must ensure that the critical section is properly + // initialized. + InitializeThreading(); + Cleanup(true); +} + +/// Find the Windows Registry Key for a given location. +/// +/// \returns a valid HKEY if the location exists, else NULL. +static HKEY FindWERKey(const llvm::Twine &RegistryLocation) { + HKEY Key; + if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, + RegistryLocation.str().c_str(), 0, + KEY_QUERY_VALUE | KEY_READ, &Key)) + return NULL; + + return Key; +} + +/// Populate ResultDirectory with the value for "DumpFolder" for a given +/// Windows Registry key. +/// +/// \returns true if a valid value for DumpFolder exists, false otherwise. +static bool GetDumpFolder(HKEY Key, + llvm::SmallVectorImpl<char> &ResultDirectory) { + using llvm::sys::windows::UTF16ToUTF8; + + if (!Key) + return false; + + DWORD BufferLengthBytes = 0; + + if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, + NULL, NULL, &BufferLengthBytes)) + return false; + + SmallVector<wchar_t, MAX_PATH> Buffer(BufferLengthBytes); + + if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, + NULL, Buffer.data(), &BufferLengthBytes)) + return false; + + DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0); + + if (!ExpandBufferSize) + return false; + + SmallVector<wchar_t, MAX_PATH> ExpandBuffer(ExpandBufferSize); + + if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(), + ExpandBuffer.data(), + ExpandBufferSize)) + return false; + + if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory)) + return false; + + return true; +} + +/// Populate ResultType with a valid MINIDUMP_TYPE based on the value of +/// "DumpType" for a given Windows Registry key. +/// +/// According to +/// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx +/// valid values for DumpType are: +/// * 0: Custom dump +/// * 1: Mini dump +/// * 2: Full dump +/// If "Custom dump" is specified then the "CustomDumpFlags" field is read +/// containing a bitwise combination of MINIDUMP_TYPE values. +/// +/// \returns true if a valid value for ResultType can be set, false otherwise. +static bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) { + if (!Key) + return false; + + DWORD DumpType; + DWORD TypeSize = sizeof(DumpType); + if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD, + NULL, &DumpType, + &TypeSize)) + return false; + + switch (DumpType) { + case 0: { + DWORD Flags = 0; + if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags", + RRF_RT_REG_DWORD, NULL, &Flags, + &TypeSize)) + return false; + + ResultType = static_cast<MINIDUMP_TYPE>(Flags); + break; + } + case 1: + ResultType = MiniDumpNormal; + break; + case 2: + ResultType = MiniDumpWithFullMemory; + break; + default: + return false; + } + return true; +} + +/// Write a Windows dump file containing process information that can be +/// used for post-mortem debugging. +/// +/// \returns zero error code if a mini dump created, actual error code +/// otherwise. +static std::error_code WINAPI +WriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) { + using namespace llvm; + using namespace llvm::sys; + + std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr); + StringRef ProgramName; + + if (MainExecutableName.empty()) { + // If we can't get the executable filename, + // things are in worse shape than we realize + // and we should just bail out. + return mapWindowsError(::GetLastError()); + } + + ProgramName = path::filename(MainExecutableName.c_str()); + + // The Windows Registry location as specified at + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx + // "Collecting User-Mode Dumps" that may optionally be set to collect crash + // dumps in a specified location. + StringRef LocalDumpsRegistryLocation = + "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps"; + + // The key pointing to the Registry location that may contain global crash + // dump settings. This will be NULL if the location can not be found. + ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation)); + + // The key pointing to the Registry location that may contain + // application-specific crash dump settings. This will be NULL if the + // location can not be found. + ScopedRegHandle AppSpecificKey( + FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName)); + + // Look to see if a dump type is specified in the registry; first with the + // app-specific key and failing that with the global key. If none are found + // default to a normal dump (GetDumpType will return false either if the key + // is NULL or if there is no valid DumpType value at its location). + MINIDUMP_TYPE DumpType; + if (!GetDumpType(AppSpecificKey, DumpType)) + if (!GetDumpType(DefaultLocalDumpsKey, DumpType)) + DumpType = MiniDumpNormal; + + // Look to see if a dump location is specified in the registry; first with the + // app-specific key and failing that with the global key. If none are found + // we'll just create the dump file in the default temporary file location + // (GetDumpFolder will return false either if the key is NULL or if there is + // no valid DumpFolder value at its location). + bool ExplicitDumpDirectorySet = true; + SmallString<MAX_PATH> DumpDirectory; + if (!GetDumpFolder(AppSpecificKey, DumpDirectory)) + if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory)) + ExplicitDumpDirectorySet = false; + + int FD; + SmallString<MAX_PATH> DumpPath; + + if (ExplicitDumpDirectorySet) { + if (std::error_code EC = fs::create_directories(DumpDirectory)) + return EC; + if (std::error_code EC = fs::createUniqueFile( + Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD, + DumpPath)) + return EC; + } else if (std::error_code EC = + fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath)) + return EC; + + // Our support functions return a file descriptor but Windows wants a handle. + ScopedCommonHandle FileHandle(reinterpret_cast<HANDLE>(_get_osfhandle(FD))); + + if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), + FileHandle, DumpType, ExceptionInfo, NULL, NULL)) + return mapWindowsError(::GetLastError()); + + llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n"; + return std::error_code(); +} + +void sys::CleanupOnSignal(uintptr_t Context) { + LLVMUnhandledExceptionFilter((LPEXCEPTION_POINTERS)Context); +} + +static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { + Cleanup(true); + + // We'll automatically write a Minidump file here to help diagnose + // the nasty sorts of crashes that aren't 100% reproducible from a set of + // inputs (or in the event that the user is unable or unwilling to provide a + // reproducible case). + if (!llvm::sys::Process::AreCoreFilesPrevented()) { + MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo; + ExceptionInfo.ThreadId = ::GetCurrentThreadId(); + ExceptionInfo.ExceptionPointers = ep; + ExceptionInfo.ClientPointers = FALSE; + + if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo)) + llvm::errs() << "Could not write crash dump file: " << EC.message() + << "\n"; + } + + // Stack unwinding appears to modify the context. Copy it to preserve the + // caller's context. + CONTEXT ContextCopy; + if (ep) + memcpy(&ContextCopy, ep->ContextRecord, sizeof(ContextCopy)); + + LocalPrintStackTrace(llvm::errs(), ep ? &ContextCopy : nullptr); + + return EXCEPTION_EXECUTE_HANDLER; +} + +static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { + // We are running in our very own thread, courtesy of Windows. + EnterCriticalSection(&CriticalSection); + // This function is only ever called when a CTRL-C or similar control signal + // is fired. Killing a process in this way is normal, so don't trigger the + // signal handlers. + Cleanup(false); + + // If an interrupt function has been set, go and run one it; otherwise, + // the process dies. + void (*IF)() = InterruptFunction; + InterruptFunction = 0; // Don't run it on another CTRL-C. + + if (IF) { + // Note: if the interrupt function throws an exception, there is nothing + // to catch it in this thread so it will kill the process. + IF(); // Run it now. + LeaveCriticalSection(&CriticalSection); + return TRUE; // Don't kill the process. + } + + // Allow normal processing to take place; i.e., the process dies. + LeaveCriticalSection(&CriticalSection); + return FALSE; +} + +#if __MINGW32__ + // We turned these warnings off for this file so that MinGW-g++ doesn't + // complain about the ll format specifiers used. Now we are turning the + // warnings back on. If MinGW starts to support diagnostic stacks, we can + // replace this with a pop. + #pragma GCC diagnostic warning "-Wformat" + #pragma GCC diagnostic warning "-Wformat-extra-args" +#endif void sys::unregisterHandlers() {} diff --git a/contrib/libs/llvm12/lib/Support/Windows/ThreadLocal.inc b/contrib/libs/llvm12/lib/Support/Windows/ThreadLocal.inc index 8752643680..696e5c843e 100644 --- a/contrib/libs/llvm12/lib/Support/Windows/ThreadLocal.inc +++ b/contrib/libs/llvm12/lib/Support/Windows/ThreadLocal.inc @@ -1,51 +1,51 @@ -//= llvm/Support/Win32/ThreadLocal.inc - Win32 Thread Local Data -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the Win32 specific (non-pthread) ThreadLocal class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. -//===----------------------------------------------------------------------===// - -#include "llvm/Support/Windows/WindowsSupport.h" -#include "llvm/Support/ThreadLocal.h" - -namespace llvm { - -sys::ThreadLocalImpl::ThreadLocalImpl() : data() { - static_assert(sizeof(DWORD) <= sizeof(data), "size too big"); - DWORD* tls = reinterpret_cast<DWORD*>(&data); - *tls = TlsAlloc(); - assert(*tls != TLS_OUT_OF_INDEXES); -} - -sys::ThreadLocalImpl::~ThreadLocalImpl() { - DWORD* tls = reinterpret_cast<DWORD*>(&data); - TlsFree(*tls); -} - -void *sys::ThreadLocalImpl::getInstance() { - DWORD* tls = reinterpret_cast<DWORD*>(&data); - return TlsGetValue(*tls); -} - -void sys::ThreadLocalImpl::setInstance(const void* d){ - DWORD* tls = reinterpret_cast<DWORD*>(&data); - int errorcode = TlsSetValue(*tls, const_cast<void*>(d)); - assert(errorcode != 0); - (void)errorcode; -} - -void sys::ThreadLocalImpl::removeInstance() { - setInstance(0); -} - -} +//= llvm/Support/Win32/ThreadLocal.inc - Win32 Thread Local Data -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 specific (non-pthread) ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Windows/WindowsSupport.h" +#include "llvm/Support/ThreadLocal.h" + +namespace llvm { + +sys::ThreadLocalImpl::ThreadLocalImpl() : data() { + static_assert(sizeof(DWORD) <= sizeof(data), "size too big"); + DWORD* tls = reinterpret_cast<DWORD*>(&data); + *tls = TlsAlloc(); + assert(*tls != TLS_OUT_OF_INDEXES); +} + +sys::ThreadLocalImpl::~ThreadLocalImpl() { + DWORD* tls = reinterpret_cast<DWORD*>(&data); + TlsFree(*tls); +} + +void *sys::ThreadLocalImpl::getInstance() { + DWORD* tls = reinterpret_cast<DWORD*>(&data); + return TlsGetValue(*tls); +} + +void sys::ThreadLocalImpl::setInstance(const void* d){ + DWORD* tls = reinterpret_cast<DWORD*>(&data); + int errorcode = TlsSetValue(*tls, const_cast<void*>(d)); + assert(errorcode != 0); + (void)errorcode; +} + +void sys::ThreadLocalImpl::removeInstance() { + setInstance(0); +} + +} diff --git a/contrib/libs/llvm12/lib/Support/Windows/Threading.inc b/contrib/libs/llvm12/lib/Support/Windows/Threading.inc index acee172618..6448bb478d 100644 --- a/contrib/libs/llvm12/lib/Support/Windows/Threading.inc +++ b/contrib/libs/llvm12/lib/Support/Windows/Threading.inc @@ -1,200 +1,200 @@ -//===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of Threading functions. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/Twine.h" - -#include "llvm/Support/Windows/WindowsSupport.h" -#include <process.h> - -#include <bitset> - -// Windows will at times define MemoryFence. -#ifdef MemoryFence -#undef MemoryFence -#endif - -static unsigned __stdcall threadFuncSync(void *Arg) { - SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg); - TI->UserFn(TI->UserData); - return 0; -} - -static unsigned __stdcall threadFuncAsync(void *Arg) { - std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg)); - (*Info)(); - return 0; -} - -static void -llvm_execute_on_thread_impl(unsigned (__stdcall *ThreadFunc)(void *), void *Arg, - llvm::Optional<unsigned> StackSizeInBytes, - JoiningPolicy JP) { - HANDLE hThread = (HANDLE)::_beginthreadex( - NULL, StackSizeInBytes.getValueOr(0), ThreadFunc, Arg, 0, NULL); - - if (!hThread) { - ReportLastErrorFatal("_beginthreadex failed"); - } - - if (JP == JoiningPolicy::Join) { - if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) { - ReportLastErrorFatal("WaitForSingleObject failed"); - } - } - if (::CloseHandle(hThread) == FALSE) { - ReportLastErrorFatal("CloseHandle failed"); - } -} - -uint64_t llvm::get_threadid() { - return uint64_t(::GetCurrentThreadId()); -} - -uint32_t llvm::get_max_thread_name_length() { return 0; } - -#if defined(_MSC_VER) -static void SetThreadName(DWORD Id, LPCSTR Name) { - constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; - -#pragma pack(push, 8) - struct THREADNAME_INFO { - DWORD dwType; // Must be 0x1000. - LPCSTR szName; // Pointer to thread name - DWORD dwThreadId; // Thread ID (-1 == current thread) - DWORD dwFlags; // Reserved. Do not use. - }; -#pragma pack(pop) - - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = Name; - info.dwThreadId = Id; - info.dwFlags = 0; - - __try { - ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), - (ULONG_PTR *)&info); - } - __except (EXCEPTION_EXECUTE_HANDLER) { - } -} -#endif - -void llvm::set_thread_name(const Twine &Name) { -#if defined(_MSC_VER) - // Make sure the input is null terminated. - SmallString<64> Storage; - StringRef NameStr = Name.toNullTerminatedStringRef(Storage); - SetThreadName(::GetCurrentThreadId(), NameStr.data()); -#endif -} - -void llvm::get_thread_name(SmallVectorImpl<char> &Name) { - // "Name" is not an inherent property of a thread on Windows. In fact, when - // you "set" the name, you are only firing a one-time message to a debugger - // which it interprets as a program setting its threads' name. We may be - // able to get fancy by creating a TLS entry when someone calls - // set_thread_name so that subsequent calls to get_thread_name return this - // value. - Name.clear(); -} - -SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { - // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority - // Begin background processing mode. The system lowers the resource scheduling - // priorities of the thread so that it can perform background work without - // significantly affecting activity in the foreground. - // End background processing mode. The system restores the resource scheduling - // priorities of the thread as they were before the thread entered background - // processing mode. - return SetThreadPriority(GetCurrentThread(), - Priority == ThreadPriority::Background - ? THREAD_MODE_BACKGROUND_BEGIN - : THREAD_MODE_BACKGROUND_END) - ? SetThreadPriorityResult::SUCCESS - : SetThreadPriorityResult::FAILURE; -} - -struct ProcessorGroup { - unsigned ID; - unsigned AllThreads; - unsigned UsableThreads; - unsigned ThreadsPerCore; - uint64_t Affinity; - - unsigned useableCores() const { - return std::max(1U, UsableThreads / ThreadsPerCore); - } -}; - -template <typename F> -static bool IterateProcInfo(LOGICAL_PROCESSOR_RELATIONSHIP Relationship, F Fn) { - DWORD Len = 0; - BOOL R = ::GetLogicalProcessorInformationEx(Relationship, NULL, &Len); - if (R || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - return false; - } - auto *Info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)calloc(1, Len); - R = ::GetLogicalProcessorInformationEx(Relationship, Info, &Len); - if (R) { - auto *End = - (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((uint8_t *)Info + Len); - for (auto *Curr = Info; Curr < End; - Curr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((uint8_t *)Curr + - Curr->Size)) { - if (Curr->Relationship != Relationship) - continue; - Fn(Curr); - } - } - free(Info); - return true; -} - -static ArrayRef<ProcessorGroup> getProcessorGroups() { - auto computeGroups = []() { - SmallVector<ProcessorGroup, 4> Groups; - - auto HandleGroup = [&](SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ProcInfo) { - GROUP_RELATIONSHIP &El = ProcInfo->Group; - for (unsigned J = 0; J < El.ActiveGroupCount; ++J) { - ProcessorGroup G; - G.ID = Groups.size(); - G.AllThreads = El.GroupInfo[J].MaximumProcessorCount; - G.UsableThreads = El.GroupInfo[J].ActiveProcessorCount; - assert(G.UsableThreads <= 64); - G.Affinity = El.GroupInfo[J].ActiveProcessorMask; - Groups.push_back(G); - } - }; - - if (!IterateProcInfo(RelationGroup, HandleGroup)) - return std::vector<ProcessorGroup>(); - - auto HandleProc = [&](SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ProcInfo) { - PROCESSOR_RELATIONSHIP &El = ProcInfo->Processor; - assert(El.GroupCount == 1); - unsigned NumHyperThreads = 1; - // If the flag is set, each core supports more than one hyper-thread. - if (El.Flags & LTP_PC_SMT) - NumHyperThreads = std::bitset<64>(El.GroupMask[0].Mask).count(); - unsigned I = El.GroupMask[0].Group; - Groups[I].ThreadsPerCore = NumHyperThreads; - }; - - if (!IterateProcInfo(RelationProcessorCore, HandleProc)) - return std::vector<ProcessorGroup>(); - +//===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of Threading functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" + +#include "llvm/Support/Windows/WindowsSupport.h" +#include <process.h> + +#include <bitset> + +// Windows will at times define MemoryFence. +#ifdef MemoryFence +#undef MemoryFence +#endif + +static unsigned __stdcall threadFuncSync(void *Arg) { + SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg); + TI->UserFn(TI->UserData); + return 0; +} + +static unsigned __stdcall threadFuncAsync(void *Arg) { + std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg)); + (*Info)(); + return 0; +} + +static void +llvm_execute_on_thread_impl(unsigned (__stdcall *ThreadFunc)(void *), void *Arg, + llvm::Optional<unsigned> StackSizeInBytes, + JoiningPolicy JP) { + HANDLE hThread = (HANDLE)::_beginthreadex( + NULL, StackSizeInBytes.getValueOr(0), ThreadFunc, Arg, 0, NULL); + + if (!hThread) { + ReportLastErrorFatal("_beginthreadex failed"); + } + + if (JP == JoiningPolicy::Join) { + if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) { + ReportLastErrorFatal("WaitForSingleObject failed"); + } + } + if (::CloseHandle(hThread) == FALSE) { + ReportLastErrorFatal("CloseHandle failed"); + } +} + +uint64_t llvm::get_threadid() { + return uint64_t(::GetCurrentThreadId()); +} + +uint32_t llvm::get_max_thread_name_length() { return 0; } + +#if defined(_MSC_VER) +static void SetThreadName(DWORD Id, LPCSTR Name) { + constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; + +#pragma pack(push, 8) + struct THREADNAME_INFO { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to thread name + DWORD dwThreadId; // Thread ID (-1 == current thread) + DWORD dwFlags; // Reserved. Do not use. + }; +#pragma pack(pop) + + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = Name; + info.dwThreadId = Id; + info.dwFlags = 0; + + __try { + ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), + (ULONG_PTR *)&info); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + } +} +#endif + +void llvm::set_thread_name(const Twine &Name) { +#if defined(_MSC_VER) + // Make sure the input is null terminated. + SmallString<64> Storage; + StringRef NameStr = Name.toNullTerminatedStringRef(Storage); + SetThreadName(::GetCurrentThreadId(), NameStr.data()); +#endif +} + +void llvm::get_thread_name(SmallVectorImpl<char> &Name) { + // "Name" is not an inherent property of a thread on Windows. In fact, when + // you "set" the name, you are only firing a one-time message to a debugger + // which it interprets as a program setting its threads' name. We may be + // able to get fancy by creating a TLS entry when someone calls + // set_thread_name so that subsequent calls to get_thread_name return this + // value. + Name.clear(); +} + +SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { + // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority + // Begin background processing mode. The system lowers the resource scheduling + // priorities of the thread so that it can perform background work without + // significantly affecting activity in the foreground. + // End background processing mode. The system restores the resource scheduling + // priorities of the thread as they were before the thread entered background + // processing mode. + return SetThreadPriority(GetCurrentThread(), + Priority == ThreadPriority::Background + ? THREAD_MODE_BACKGROUND_BEGIN + : THREAD_MODE_BACKGROUND_END) + ? SetThreadPriorityResult::SUCCESS + : SetThreadPriorityResult::FAILURE; +} + +struct ProcessorGroup { + unsigned ID; + unsigned AllThreads; + unsigned UsableThreads; + unsigned ThreadsPerCore; + uint64_t Affinity; + + unsigned useableCores() const { + return std::max(1U, UsableThreads / ThreadsPerCore); + } +}; + +template <typename F> +static bool IterateProcInfo(LOGICAL_PROCESSOR_RELATIONSHIP Relationship, F Fn) { + DWORD Len = 0; + BOOL R = ::GetLogicalProcessorInformationEx(Relationship, NULL, &Len); + if (R || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + return false; + } + auto *Info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)calloc(1, Len); + R = ::GetLogicalProcessorInformationEx(Relationship, Info, &Len); + if (R) { + auto *End = + (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((uint8_t *)Info + Len); + for (auto *Curr = Info; Curr < End; + Curr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((uint8_t *)Curr + + Curr->Size)) { + if (Curr->Relationship != Relationship) + continue; + Fn(Curr); + } + } + free(Info); + return true; +} + +static ArrayRef<ProcessorGroup> getProcessorGroups() { + auto computeGroups = []() { + SmallVector<ProcessorGroup, 4> Groups; + + auto HandleGroup = [&](SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ProcInfo) { + GROUP_RELATIONSHIP &El = ProcInfo->Group; + for (unsigned J = 0; J < El.ActiveGroupCount; ++J) { + ProcessorGroup G; + G.ID = Groups.size(); + G.AllThreads = El.GroupInfo[J].MaximumProcessorCount; + G.UsableThreads = El.GroupInfo[J].ActiveProcessorCount; + assert(G.UsableThreads <= 64); + G.Affinity = El.GroupInfo[J].ActiveProcessorMask; + Groups.push_back(G); + } + }; + + if (!IterateProcInfo(RelationGroup, HandleGroup)) + return std::vector<ProcessorGroup>(); + + auto HandleProc = [&](SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ProcInfo) { + PROCESSOR_RELATIONSHIP &El = ProcInfo->Processor; + assert(El.GroupCount == 1); + unsigned NumHyperThreads = 1; + // If the flag is set, each core supports more than one hyper-thread. + if (El.Flags & LTP_PC_SMT) + NumHyperThreads = std::bitset<64>(El.GroupMask[0].Mask).count(); + unsigned I = El.GroupMask[0].Group; + Groups[I].ThreadsPerCore = NumHyperThreads; + }; + + if (!IterateProcInfo(RelationProcessorCore, HandleProc)) + return std::vector<ProcessorGroup>(); + // If there's an affinity mask set, assume the user wants to constrain the // current process to only a single CPU group. On Windows, it is not // possible for affinity masks to cross CPU group boundaries. @@ -214,98 +214,98 @@ static ArrayRef<ProcessorGroup> getProcessorGroups() { ProcessorGroup NewG{Groups[CurrentGroupID]}; NewG.Affinity = ProcessAffinityMask; NewG.UsableThreads = countPopulation(ProcessAffinityMask); - Groups.clear(); - Groups.push_back(NewG); - } - } - - return std::vector<ProcessorGroup>(Groups.begin(), Groups.end()); - }; - static auto Groups = computeGroups(); - return ArrayRef<ProcessorGroup>(Groups); -} - -template <typename R, typename UnaryPredicate> -static unsigned aggregate(R &&Range, UnaryPredicate P) { - unsigned I{}; - for (const auto &It : Range) - I += P(It); - return I; -} - -// for sys::getHostNumPhysicalCores -int computeHostNumPhysicalCores() { - static unsigned Cores = - aggregate(getProcessorGroups(), [](const ProcessorGroup &G) { - return G.UsableThreads / G.ThreadsPerCore; - }); - return Cores; -} - -int computeHostNumHardwareThreads() { - static unsigned Threads = - aggregate(getProcessorGroups(), - [](const ProcessorGroup &G) { return G.UsableThreads; }); - return Threads; -} - -// Finds the proper CPU socket where a thread number should go. Returns 'None' -// if the thread shall remain on the actual CPU socket. -Optional<unsigned> -llvm::ThreadPoolStrategy::compute_cpu_socket(unsigned ThreadPoolNum) const { - ArrayRef<ProcessorGroup> Groups = getProcessorGroups(); - // Only one CPU socket in the system or process affinity was set, no need to - // move the thread(s) to another CPU socket. - if (Groups.size() <= 1) - return None; - - // We ask for less threads than there are hardware threads per CPU socket, no - // need to dispatch threads to other CPU sockets. - unsigned MaxThreadsPerSocket = - UseHyperThreads ? Groups[0].UsableThreads : Groups[0].useableCores(); - if (compute_thread_count() <= MaxThreadsPerSocket) - return None; - - assert(ThreadPoolNum < compute_thread_count() && - "The thread index is not within thread strategy's range!"); - - // Assumes the same number of hardware threads per CPU socket. - return (ThreadPoolNum * Groups.size()) / compute_thread_count(); -} - -// Assign the current thread to a more appropriate CPU socket or CPU group -void llvm::ThreadPoolStrategy::apply_thread_strategy( - unsigned ThreadPoolNum) const { - Optional<unsigned> Socket = compute_cpu_socket(ThreadPoolNum); - if (!Socket) - return; - ArrayRef<ProcessorGroup> Groups = getProcessorGroups(); - GROUP_AFFINITY Affinity{}; - Affinity.Group = Groups[*Socket].ID; - Affinity.Mask = Groups[*Socket].Affinity; - SetThreadGroupAffinity(GetCurrentThread(), &Affinity, nullptr); -} - -llvm::BitVector llvm::get_thread_affinity_mask() { - GROUP_AFFINITY Affinity{}; - GetThreadGroupAffinity(GetCurrentThread(), &Affinity); - - static unsigned All = - aggregate(getProcessorGroups(), - [](const ProcessorGroup &G) { return G.AllThreads; }); - - unsigned StartOffset = - aggregate(getProcessorGroups(), [&](const ProcessorGroup &G) { - return G.ID < Affinity.Group ? G.AllThreads : 0; - }); - - llvm::BitVector V; - V.resize(All); - for (unsigned I = 0; I < sizeof(KAFFINITY) * 8; ++I) { - if ((Affinity.Mask >> I) & 1) - V.set(StartOffset + I); - } - return V; -} - -unsigned llvm::get_cpus() { return getProcessorGroups().size(); } + Groups.clear(); + Groups.push_back(NewG); + } + } + + return std::vector<ProcessorGroup>(Groups.begin(), Groups.end()); + }; + static auto Groups = computeGroups(); + return ArrayRef<ProcessorGroup>(Groups); +} + +template <typename R, typename UnaryPredicate> +static unsigned aggregate(R &&Range, UnaryPredicate P) { + unsigned I{}; + for (const auto &It : Range) + I += P(It); + return I; +} + +// for sys::getHostNumPhysicalCores +int computeHostNumPhysicalCores() { + static unsigned Cores = + aggregate(getProcessorGroups(), [](const ProcessorGroup &G) { + return G.UsableThreads / G.ThreadsPerCore; + }); + return Cores; +} + +int computeHostNumHardwareThreads() { + static unsigned Threads = + aggregate(getProcessorGroups(), + [](const ProcessorGroup &G) { return G.UsableThreads; }); + return Threads; +} + +// Finds the proper CPU socket where a thread number should go. Returns 'None' +// if the thread shall remain on the actual CPU socket. +Optional<unsigned> +llvm::ThreadPoolStrategy::compute_cpu_socket(unsigned ThreadPoolNum) const { + ArrayRef<ProcessorGroup> Groups = getProcessorGroups(); + // Only one CPU socket in the system or process affinity was set, no need to + // move the thread(s) to another CPU socket. + if (Groups.size() <= 1) + return None; + + // We ask for less threads than there are hardware threads per CPU socket, no + // need to dispatch threads to other CPU sockets. + unsigned MaxThreadsPerSocket = + UseHyperThreads ? Groups[0].UsableThreads : Groups[0].useableCores(); + if (compute_thread_count() <= MaxThreadsPerSocket) + return None; + + assert(ThreadPoolNum < compute_thread_count() && + "The thread index is not within thread strategy's range!"); + + // Assumes the same number of hardware threads per CPU socket. + return (ThreadPoolNum * Groups.size()) / compute_thread_count(); +} + +// Assign the current thread to a more appropriate CPU socket or CPU group +void llvm::ThreadPoolStrategy::apply_thread_strategy( + unsigned ThreadPoolNum) const { + Optional<unsigned> Socket = compute_cpu_socket(ThreadPoolNum); + if (!Socket) + return; + ArrayRef<ProcessorGroup> Groups = getProcessorGroups(); + GROUP_AFFINITY Affinity{}; + Affinity.Group = Groups[*Socket].ID; + Affinity.Mask = Groups[*Socket].Affinity; + SetThreadGroupAffinity(GetCurrentThread(), &Affinity, nullptr); +} + +llvm::BitVector llvm::get_thread_affinity_mask() { + GROUP_AFFINITY Affinity{}; + GetThreadGroupAffinity(GetCurrentThread(), &Affinity); + + static unsigned All = + aggregate(getProcessorGroups(), + [](const ProcessorGroup &G) { return G.AllThreads; }); + + unsigned StartOffset = + aggregate(getProcessorGroups(), [&](const ProcessorGroup &G) { + return G.ID < Affinity.Group ? G.AllThreads : 0; + }); + + llvm::BitVector V; + V.resize(All); + for (unsigned I = 0; I < sizeof(KAFFINITY) * 8; ++I) { + if ((Affinity.Mask >> I) & 1) + V.set(StartOffset + I); + } + return V; +} + +unsigned llvm::get_cpus() { return getProcessorGroups().size(); } diff --git a/contrib/libs/llvm12/lib/Support/Windows/Watchdog.inc b/contrib/libs/llvm12/lib/Support/Windows/Watchdog.inc index dceb9759a0..a362c999de 100644 --- a/contrib/libs/llvm12/lib/Support/Windows/Watchdog.inc +++ b/contrib/libs/llvm12/lib/Support/Windows/Watchdog.inc @@ -1,23 +1,23 @@ -//===--- Windows/Watchdog.inc - Windows Watchdog Implementation -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file provides the generic Windows implementation of the Watchdog class. -// -//===----------------------------------------------------------------------===// - -// TODO: implement. -// Currently this is only used by PrettyStackTrace which is also unimplemented -// on Windows. Roughly, a Windows implementation would use CreateWaitableTimer -// and a second thread to run the TimerAPCProc. - -namespace llvm { - namespace sys { - Watchdog::Watchdog(unsigned int seconds) {} - Watchdog::~Watchdog() {} - } -} +//===--- Windows/Watchdog.inc - Windows Watchdog Implementation -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides the generic Windows implementation of the Watchdog class. +// +//===----------------------------------------------------------------------===// + +// TODO: implement. +// Currently this is only used by PrettyStackTrace which is also unimplemented +// on Windows. Roughly, a Windows implementation would use CreateWaitableTimer +// and a second thread to run the TimerAPCProc. + +namespace llvm { + namespace sys { + Watchdog::Watchdog(unsigned int seconds) {} + Watchdog::~Watchdog() {} + } +} diff --git a/contrib/libs/llvm12/lib/Support/Windows/explicit_symbols.inc b/contrib/libs/llvm12/lib/Support/Windows/explicit_symbols.inc index 0aa3f78172..0a4fda1d4e 100644 --- a/contrib/libs/llvm12/lib/Support/Windows/explicit_symbols.inc +++ b/contrib/libs/llvm12/lib/Support/Windows/explicit_symbols.inc @@ -1,96 +1,96 @@ -/* in libgcc.a */ - -#ifdef HAVE__ALLOCA - EXPLICIT_SYMBOL(_alloca) - EXPLICIT_SYMBOL2(alloca, _alloca) -#endif -#ifdef HAVE___ALLOCA - EXPLICIT_SYMBOL(__alloca) -#endif -#ifdef HAVE___CHKSTK - EXPLICIT_SYMBOL(__chkstk) -#endif -#ifdef HAVE___CHKSTK_MS - EXPLICIT_SYMBOL(__chkstk_ms) -#endif -#ifdef HAVE____CHKSTK - EXPLICIT_SYMBOL(___chkstk) -#endif -#ifdef HAVE____CHKSTK_MS - EXPLICIT_SYMBOL(___chkstk_ms) -#endif -#ifdef HAVE___MAIN - EXPLICIT_SYMBOL(__main) // FIXME: Don't call it. -#endif - -#ifdef HAVE___ASHLDI3 - EXPLICIT_SYMBOL(__ashldi3) -#endif -#ifdef HAVE___ASHRDI3 - EXPLICIT_SYMBOL(__ashrdi3) -#endif -#ifdef HAVE___CMPDI2 // FIXME: unused - EXPLICIT_SYMBOL(__cmpdi2) -#endif -#ifdef HAVE___DIVDI3 - EXPLICIT_SYMBOL(__divdi3) -#endif -#ifdef HAVE___FIXDFDI - EXPLICIT_SYMBOL(__fixdfdi) -#endif -#ifdef HAVE___FIXSFDI - EXPLICIT_SYMBOL(__fixsfdi) -#endif -#ifdef HAVE___FIXUNSDFDI - EXPLICIT_SYMBOL(__fixunsdfdi) -#endif -#ifdef HAVE___FIXUNSSFDI - EXPLICIT_SYMBOL(__fixunssfdi) -#endif -#ifdef HAVE___FLOATDIDF - EXPLICIT_SYMBOL(__floatdidf) -#endif -#ifdef HAVE___FLOATDISF - EXPLICIT_SYMBOL(__floatdisf) -#endif -#ifdef HAVE___LSHRDI3 - EXPLICIT_SYMBOL(__lshrdi3) -#endif -#ifdef HAVE___MODDI3 - EXPLICIT_SYMBOL(__moddi3) -#endif -#ifdef HAVE___UDIVDI3 - EXPLICIT_SYMBOL(__udivdi3) -#endif -#ifdef HAVE___UMODDI3 - EXPLICIT_SYMBOL(__umoddi3) -#endif - -/* msvcrt */ -#if defined(_MSC_VER) - EXPLICIT_SYMBOL2(alloca, _alloca_probe) - -#ifdef _M_IX86 -#define INLINE_DEF_FLOAT_SYMBOL(SYM, ARGC) INLINE_DEF_SYMBOL##ARGC(float, SYM) - INLINE_DEF_FLOAT_SYMBOL(acosf, 1) - INLINE_DEF_FLOAT_SYMBOL(asinf, 1) - INLINE_DEF_FLOAT_SYMBOL(atanf, 1) - INLINE_DEF_FLOAT_SYMBOL(atan2f, 2) - INLINE_DEF_FLOAT_SYMBOL(ceilf, 1) - INLINE_DEF_FLOAT_SYMBOL(cosf, 1) - INLINE_DEF_FLOAT_SYMBOL(coshf, 1) - INLINE_DEF_FLOAT_SYMBOL(expf, 1) - INLINE_DEF_FLOAT_SYMBOL(floorf, 1) - INLINE_DEF_FLOAT_SYMBOL(fmodf, 2) - INLINE_DEF_FLOAT_SYMBOL(logf, 1) - INLINE_DEF_FLOAT_SYMBOL(powf, 2) - INLINE_DEF_FLOAT_SYMBOL(sinf, 1) - INLINE_DEF_FLOAT_SYMBOL(sinhf, 1) - INLINE_DEF_FLOAT_SYMBOL(sqrtf, 1) - INLINE_DEF_FLOAT_SYMBOL(tanf, 1) - INLINE_DEF_FLOAT_SYMBOL(tanhf, 1) - -#undef INLINE_DEF_FLOAT_SYMBOL -#endif - -#endif +/* in libgcc.a */ + +#ifdef HAVE__ALLOCA + EXPLICIT_SYMBOL(_alloca) + EXPLICIT_SYMBOL2(alloca, _alloca) +#endif +#ifdef HAVE___ALLOCA + EXPLICIT_SYMBOL(__alloca) +#endif +#ifdef HAVE___CHKSTK + EXPLICIT_SYMBOL(__chkstk) +#endif +#ifdef HAVE___CHKSTK_MS + EXPLICIT_SYMBOL(__chkstk_ms) +#endif +#ifdef HAVE____CHKSTK + EXPLICIT_SYMBOL(___chkstk) +#endif +#ifdef HAVE____CHKSTK_MS + EXPLICIT_SYMBOL(___chkstk_ms) +#endif +#ifdef HAVE___MAIN + EXPLICIT_SYMBOL(__main) // FIXME: Don't call it. +#endif + +#ifdef HAVE___ASHLDI3 + EXPLICIT_SYMBOL(__ashldi3) +#endif +#ifdef HAVE___ASHRDI3 + EXPLICIT_SYMBOL(__ashrdi3) +#endif +#ifdef HAVE___CMPDI2 // FIXME: unused + EXPLICIT_SYMBOL(__cmpdi2) +#endif +#ifdef HAVE___DIVDI3 + EXPLICIT_SYMBOL(__divdi3) +#endif +#ifdef HAVE___FIXDFDI + EXPLICIT_SYMBOL(__fixdfdi) +#endif +#ifdef HAVE___FIXSFDI + EXPLICIT_SYMBOL(__fixsfdi) +#endif +#ifdef HAVE___FIXUNSDFDI + EXPLICIT_SYMBOL(__fixunsdfdi) +#endif +#ifdef HAVE___FIXUNSSFDI + EXPLICIT_SYMBOL(__fixunssfdi) +#endif +#ifdef HAVE___FLOATDIDF + EXPLICIT_SYMBOL(__floatdidf) +#endif +#ifdef HAVE___FLOATDISF + EXPLICIT_SYMBOL(__floatdisf) +#endif +#ifdef HAVE___LSHRDI3 + EXPLICIT_SYMBOL(__lshrdi3) +#endif +#ifdef HAVE___MODDI3 + EXPLICIT_SYMBOL(__moddi3) +#endif +#ifdef HAVE___UDIVDI3 + EXPLICIT_SYMBOL(__udivdi3) +#endif +#ifdef HAVE___UMODDI3 + EXPLICIT_SYMBOL(__umoddi3) +#endif + +/* msvcrt */ +#if defined(_MSC_VER) + EXPLICIT_SYMBOL2(alloca, _alloca_probe) + +#ifdef _M_IX86 +#define INLINE_DEF_FLOAT_SYMBOL(SYM, ARGC) INLINE_DEF_SYMBOL##ARGC(float, SYM) + INLINE_DEF_FLOAT_SYMBOL(acosf, 1) + INLINE_DEF_FLOAT_SYMBOL(asinf, 1) + INLINE_DEF_FLOAT_SYMBOL(atanf, 1) + INLINE_DEF_FLOAT_SYMBOL(atan2f, 2) + INLINE_DEF_FLOAT_SYMBOL(ceilf, 1) + INLINE_DEF_FLOAT_SYMBOL(cosf, 1) + INLINE_DEF_FLOAT_SYMBOL(coshf, 1) + INLINE_DEF_FLOAT_SYMBOL(expf, 1) + INLINE_DEF_FLOAT_SYMBOL(floorf, 1) + INLINE_DEF_FLOAT_SYMBOL(fmodf, 2) + INLINE_DEF_FLOAT_SYMBOL(logf, 1) + INLINE_DEF_FLOAT_SYMBOL(powf, 2) + INLINE_DEF_FLOAT_SYMBOL(sinf, 1) + INLINE_DEF_FLOAT_SYMBOL(sinhf, 1) + INLINE_DEF_FLOAT_SYMBOL(sqrtf, 1) + INLINE_DEF_FLOAT_SYMBOL(tanf, 1) + INLINE_DEF_FLOAT_SYMBOL(tanhf, 1) + +#undef INLINE_DEF_FLOAT_SYMBOL +#endif + +#endif |