diff options
Diffstat (limited to 'lib/Support/Windows')
-rw-r--r-- | lib/Support/Windows/DynamicLibrary.inc | 72 | ||||
-rw-r--r-- | lib/Support/Windows/Host.inc | 2 | ||||
-rw-r--r-- | lib/Support/Windows/Path.inc | 231 | ||||
-rw-r--r-- | lib/Support/Windows/Process.inc | 101 | ||||
-rw-r--r-- | lib/Support/Windows/Program.inc | 184 | ||||
-rw-r--r-- | lib/Support/Windows/RWMutex.inc | 8 | ||||
-rw-r--r-- | lib/Support/Windows/ThreadLocal.inc | 2 | ||||
-rw-r--r-- | lib/Support/Windows/WindowsSupport.h | 3 | ||||
-rw-r--r-- | lib/Support/Windows/explicit_symbols.inc | 30 |
9 files changed, 426 insertions, 207 deletions
diff --git a/lib/Support/Windows/DynamicLibrary.inc b/lib/Support/Windows/DynamicLibrary.inc index 5ed0b70..79d5f79 100644 --- a/lib/Support/Windows/DynamicLibrary.inc +++ b/lib/Support/Windows/DynamicLibrary.inc @@ -41,32 +41,11 @@ using namespace sys; static DenseSet<HMODULE> *OpenedHandles; -extern "C" { - - static BOOL CALLBACK ELM_Callback(WIN32_ELMCB_PCSTR ModuleName, - ULONG_PTR ModuleBase, - ULONG ModuleSize, - PVOID UserContext) - { - // Ignore VC++ runtimes prior to 7.1. Somehow some of them get loaded - // into the process. - if (stricmp(ModuleName, "msvci70") != 0 && - stricmp(ModuleName, "msvcirt") != 0 && - stricmp(ModuleName, "msvcp50") != 0 && - stricmp(ModuleName, "msvcp60") != 0 && - stricmp(ModuleName, "msvcp70") != 0 && - stricmp(ModuleName, "msvcr70") != 0 && -#ifndef __MINGW32__ - // Mingw32 uses msvcrt.dll by default. Don't ignore it. - // Otherwise the user should be aware what they are doing. - stricmp(ModuleName, "msvcrt") != 0 && -#endif - stricmp(ModuleName, "msvcrt20") != 0 && - stricmp(ModuleName, "msvcrt40") != 0) { - OpenedHandles->insert((HMODULE)ModuleBase); - } - return TRUE; - } +static BOOL CALLBACK +ELM_Callback(WIN32_ELMCB_PCSTR ModuleName, ULONG_PTR ModuleBase, + ULONG ModuleSize, PVOID UserContext) { + OpenedHandles->insert((HMODULE)ModuleBase); + return TRUE; } DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, @@ -115,10 +94,24 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, 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 void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { SmartScopedLock<true> Lock(*SymbolsMutex); @@ -142,22 +135,32 @@ void* DynamicLibrary::SearchForAddressOfSymbol(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; +#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" +#include "explicit_symbols.inc" } - #undef EXPLICIT_SYMBOL - #undef EXPLICIT_SYMBOL2 +#undef EXPLICIT_SYMBOL +#undef EXPLICIT_SYMBOL2 +#undef INLINE_DEF_SYMBOL1 +#undef INLINE_DEF_SYMBOL2 return 0; } - void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { if (!isValid()) return NULL; @@ -166,5 +169,4 @@ void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { return (void *)(intptr_t)GetProcAddress((HMODULE)Data, symbolName); } - } diff --git a/lib/Support/Windows/Host.inc b/lib/Support/Windows/Host.inc index 0c02bf9..fe89fe0a 100644 --- a/lib/Support/Windows/Host.inc +++ b/lib/Support/Windows/Host.inc @@ -1,4 +1,4 @@ -//===- llvm/Support/Win32/Host.inc -------------------------------*- C++ -*-===// +//===- llvm/Support/Win32/Host.inc ------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index 7a1bc04..365031c 100644 --- a/lib/Support/Windows/Path.inc +++ b/lib/Support/Windows/Path.inc @@ -49,23 +49,6 @@ static std::error_code windows_error(DWORD E) { return mapWindowsError(E); } -static std::error_code TempDir(SmallVectorImpl<char> &Result) { - SmallVector<wchar_t, 64> Res; -retry_temp_dir: - DWORD Len = ::GetTempPathW(Res.capacity(), Res.begin()); - - if (Len == 0) - return windows_error(::GetLastError()); - - if (Len > Res.capacity()) { - Res.reserve(Len); - goto retry_temp_dir; - } - - Res.set_size(Len); - return UTF16ToUTF8(Res.begin(), Res.size(), Result); -} - static bool is_separator(const wchar_t value) { switch (value) { case L'\\': @@ -76,6 +59,59 @@ static bool is_separator(const wchar_t value) { } } +// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the +// path is longer than CreateDirectory can tolerate, make it absolute and +// prefixed by '\\?\'. +static std::error_code widenPath(const Twine &Path8, + SmallVectorImpl<wchar_t> &Path16) { + const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename. + + // Several operations would convert Path8 to SmallString; more efficient to + // do it once up front. + SmallString<128> Path8Str; + Path8.toVector(Path8Str); + + // If we made this path absolute, how much longer would it get? + size_t CurPathLen; + if (llvm::sys::path::is_absolute(Twine(Path8Str))) + CurPathLen = 0; // No contribution from current_path needed. + else { + CurPathLen = ::GetCurrentDirectoryW(0, NULL); + if (CurPathLen == 0) + return windows_error(::GetLastError()); + } + + // Would the absolute path be longer than our limit? + if ((Path8Str.size() + CurPathLen) >= MaxDirLen && + !Path8Str.startswith("\\\\?\\")) { + SmallString<2*MAX_PATH> FullPath("\\\\?\\"); + if (CurPathLen) { + SmallString<80> CurPath; + if (std::error_code EC = llvm::sys::fs::current_path(CurPath)) + return EC; + FullPath.append(CurPath); + } + // Traverse the requested path, canonicalizing . and .. as we go (because + // the \\?\ prefix is documented to treat them as real components). + // The iterators don't report separators and append() always attaches + // preferred_separator so we don't need to call native() on the result. + for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str), + E = llvm::sys::path::end(Path8Str); + I != E; ++I) { + if (I->size() == 1 && *I == ".") + continue; + if (I->size() == 2 && *I == "..") + llvm::sys::path::remove_filename(FullPath); + else + llvm::sys::path::append(FullPath, *I); + } + return UTF8ToUTF16(FullPath, Path16); + } + + // Just use the caller's original path. + return UTF8ToUTF16(Path8Str, Path16); +} + namespace llvm { namespace sys { namespace fs { @@ -147,11 +183,9 @@ std::error_code current_path(SmallVectorImpl<char> &result) { } std::error_code create_directory(const Twine &path, bool IgnoreExisting) { - SmallString<128> path_storage; SmallVector<wchar_t, 128> path_utf16; - if (std::error_code ec = - UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) + if (std::error_code ec = widenPath(path, path_utf16)) return ec; if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { @@ -163,25 +197,14 @@ std::error_code create_directory(const Twine &path, bool IgnoreExisting) { return std::error_code(); } -std::error_code normalize_separators(SmallVectorImpl<char> &Path) { - (void) Path; - return std::error_code(); -} - // We can't use symbolic links for windows. std::error_code create_link(const Twine &to, const Twine &from) { - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toStringRef(from_storage); - StringRef t = to.toStringRef(to_storage); - // Convert to utf-16. SmallVector<wchar_t, 128> wide_from; SmallVector<wchar_t, 128> wide_to; - if (std::error_code ec = UTF8ToUTF16(f, wide_from)) + if (std::error_code ec = widenPath(from, wide_from)) return ec; - if (std::error_code ec = UTF8ToUTF16(t, wide_to)) + if (std::error_code ec = widenPath(to, wide_to)) return ec; if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) @@ -191,7 +214,6 @@ std::error_code create_link(const Twine &to, const Twine &from) { } std::error_code remove(const Twine &path, bool IgnoreNonExisting) { - SmallString<128> path_storage; SmallVector<wchar_t, 128> path_utf16; file_status ST; @@ -201,8 +223,7 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) { return std::error_code(); } - if (std::error_code ec = - UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) + if (std::error_code ec = widenPath(path, path_utf16)) return ec; if (ST.type() == file_type::directory_file) { @@ -222,18 +243,12 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) { } std::error_code rename(const Twine &from, const Twine &to) { - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toStringRef(from_storage); - StringRef t = to.toStringRef(to_storage); - // Convert to utf-16. SmallVector<wchar_t, 128> wide_from; SmallVector<wchar_t, 128> wide_to; - if (std::error_code ec = UTF8ToUTF16(f, wide_from)) + if (std::error_code ec = widenPath(from, wide_from)) return ec; - if (std::error_code ec = UTF8ToUTF16(t, wide_to)) + if (std::error_code ec = widenPath(to, wide_to)) return ec; std::error_code ec = std::error_code(); @@ -254,11 +269,9 @@ std::error_code rename(const Twine &from, const Twine &to) { } std::error_code resize_file(const Twine &path, uint64_t size) { - SmallString<128> path_storage; SmallVector<wchar_t, 128> path_utf16; - if (std::error_code ec = - UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) + if (std::error_code ec = widenPath(path, path_utf16)) return ec; int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE); @@ -273,49 +286,27 @@ std::error_code resize_file(const Twine &path, uint64_t size) { return std::error_code(error, std::generic_category()); } -std::error_code exists(const Twine &path, bool &result) { - SmallString<128> path_storage; - SmallVector<wchar_t, 128> path_utf16; +std::error_code access(const Twine &Path, AccessMode Mode) { + SmallVector<wchar_t, 128> PathUtf16; - if (std::error_code ec = - UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) - return ec; + if (std::error_code EC = widenPath(Path, PathUtf16)) + return EC; - DWORD attributes = ::GetFileAttributesW(path_utf16.begin()); + DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin()); - if (attributes == INVALID_FILE_ATTRIBUTES) { + 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 windows_error(LastError); - result = false; - } else - result = true; - return std::error_code(); -} - -bool can_write(const Twine &Path) { - // FIXME: take security attributes into account. - SmallString<128> PathStorage; - SmallVector<wchar_t, 128> PathUtf16; - - if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) - return false; - - DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); - return (Attr != INVALID_FILE_ATTRIBUTES) && !(Attr & FILE_ATTRIBUTE_READONLY); -} + return errc::no_such_file_or_directory; + } -bool can_execute(const Twine &Path) { - SmallString<128> PathStorage; - SmallVector<wchar_t, 128> PathUtf16; + if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY)) + return errc::permission_denied; - if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) - return false; - - DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); - return Attr != INVALID_FILE_ATTRIBUTES; + return std::error_code(); } bool equivalent(file_status A, file_status B) { @@ -424,7 +415,7 @@ std::error_code status(const Twine &path, file_status &result) { return std::error_code(); } - if (std::error_code ec = UTF8ToUTF16(path8, path_utf16)) + if (std::error_code ec = widenPath(path8, path_utf16)) return ec; DWORD attr = ::GetFileAttributesW(path_utf16.begin()); @@ -567,11 +558,10 @@ mapped_file_region::mapped_file_region(const Twine &path, , FileDescriptor() , FileHandle(INVALID_HANDLE_VALUE) , FileMappingHandle() { - SmallString<128> path_storage; SmallVector<wchar_t, 128> path_utf16; // Convert path to UTF-16. - if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))) + if ((ec = widenPath(path, path_utf16))) return; // Get file handle for creating a file mapping. @@ -677,7 +667,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it, StringRef path){ SmallVector<wchar_t, 128> path_utf16; - if (std::error_code ec = UTF8ToUTF16(path, path_utf16)) + if (std::error_code ec = widenPath(path, path_utf16)) return ec; // Convert path to the format that Windows is happy with. @@ -760,11 +750,9 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { } std::error_code openFileForRead(const Twine &Name, int &ResultFD) { - SmallString<128> PathStorage; SmallVector<wchar_t, 128> PathUTF16; - if (std::error_code EC = - UTF8ToUTF16(Name.toStringRef(PathStorage), PathUTF16)) + if (std::error_code EC = widenPath(Name, PathUTF16)) return EC; HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_READ, @@ -799,11 +787,9 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && "Cannot specify both 'excl' and 'append' file creation flags!"); - SmallString<128> PathStorage; SmallVector<wchar_t, 128> PathUTF16; - if (std::error_code EC = - UTF8ToUTF16(Name.toStringRef(PathStorage), PathUTF16)) + if (std::error_code EC = widenPath(Name, PathUTF16)) return EC; DWORD CreationDisposition; @@ -867,6 +853,51 @@ bool home_directory(SmallVectorImpl<char> &result) { return true; } +static bool getTempDirEnvVar(const char *Var, SmallVectorImpl<char> &Res) { + SmallVector<wchar_t, 128> NameUTF16; + if (windows::UTF8ToUTF16(Var, NameUTF16)) + return false; + + SmallVector<wchar_t, 1024> Buf; + size_t Size = 1024; + do { + Buf.reserve(Size); + Size = + GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); + if (Size == 0) + return false; + + // Try again with larger buffer. + } while (Size > Buf.capacity()); + Buf.set_size(Size); + + if (windows::UTF16ToUTF8(Buf.data(), Size, Res)) + return false; + return true; +} + +static bool getTempDirEnvVar(SmallVectorImpl<char> &Res) { + const char *EnvironmentVariables[] = {"TMP", "TEMP", "USERPROFILE"}; + for (const char *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 + // variable. + if (getTempDirEnvVar(Result)) + return; + + // Fall back to a system default. + const char *DefaultResult = "C:\\TEMP"; + Result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); +} } // end namespace path namespace windows { @@ -896,11 +927,13 @@ std::error_code UTF8ToUTF16(llvm::StringRef utf8, return std::error_code(); } -std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, - llvm::SmallVectorImpl<char> &utf8) { +static +std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, + size_t utf16_len, + llvm::SmallVectorImpl<char> &utf8) { if (utf16_len) { // Get length. - int len = ::WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_len, utf8.begin(), + int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.begin(), 0, NULL, NULL); if (len == 0) @@ -910,7 +943,7 @@ std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, utf8.set_size(len); // Now do the actual conversion. - len = ::WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_len, utf8.data(), + len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.data(), utf8.size(), NULL, NULL); if (len == 0) @@ -923,6 +956,16 @@ std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, 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> &utf8) { + return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8); +} } // end namespace windows } // end namespace sys } // end namespace llvm diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc index 81aee0e..3819e63 100644 --- a/lib/Support/Windows/Process.inc +++ b/lib/Support/Windows/Process.inc @@ -183,36 +183,103 @@ static std::error_code windows_error(DWORD E) { return mapWindowsError(E); } +static void AllocateAndPush(const SmallVectorImpl<char> &S, + SmallVectorImpl<const char *> &Vector, + SpecificBumpPtrAllocator<char> &Allocator) { + char *Buffer = Allocator.Allocate(S.size() + 1); + ::memcpy(Buffer, S.data(), S.size()); + Buffer[S.size()] = '\0'; + Vector.push_back(Buffer); +} + +/// Convert Arg from UTF-16 to UTF-8 and push it onto Args. +static std::error_code +ConvertAndPushArg(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, + SpecificBumpPtrAllocator<char> &Allocator) { + SmallVector<char, MAX_PATH> ArgString; + if (std::error_code ec = windows::UTF16ToUTF8(Arg, wcslen(Arg), ArgString)) + return ec; + AllocateAndPush(ArgString, Args, Allocator); + return std::error_code(); +} + +/// \brief 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(const wchar_t *Arg, SmallVectorImpl<const char *> &Args, + SpecificBumpPtrAllocator<char> &Allocator) { + if (!wcspbrk(Arg, L"*?")) { + // Arg does not contain any wildcard characters. This is the common case. + return ConvertAndPushArg(Arg, Args, Allocator); + } + + if (wcscmp(Arg, L"/?") == 0 || wcscmp(Arg, L"-?") == 0) { + // Don't wildcard expand /?. Always treat it as an option. + return ConvertAndPushArg(Arg, Args, Allocator); + } + + // Extract any directory part of the argument. + SmallVector<char, MAX_PATH> Dir; + if (std::error_code ec = windows::UTF16ToUTF8(Arg, wcslen(Arg), Dir)) + return ec; + sys::path::remove_filename(Dir); + const int DirSize = Dir.size(); + + // Search for matching files. + WIN32_FIND_DATAW FileData; + HANDLE FindHandle = FindFirstFileW(Arg, &FileData); + if (FindHandle == INVALID_HANDLE_VALUE) { + return ConvertAndPushArg(Arg, Args, Allocator); + } + + std::error_code ec; + do { + SmallVector<char, MAX_PATH> FileName; + ec = windows::UTF16ToUTF8(FileData.cFileName, wcslen(FileData.cFileName), + FileName); + if (ec) + break; + + // Push the filename onto Dir, and remove it afterwards. + llvm::sys::path::append(Dir, StringRef(FileName.data(), FileName.size())); + AllocateAndPush(Dir, Args, Allocator); + Dir.resize(DirSize); + } while (FindNextFileW(FindHandle, &FileData)); + + FindClose(FindHandle); + return ec; +} + std::error_code Process::GetArgumentVector(SmallVectorImpl<const char *> &Args, ArrayRef<const char *>, SpecificBumpPtrAllocator<char> &ArgAllocator) { - int NewArgCount; - std::error_code ec; - - wchar_t **UnicodeCommandLine = CommandLineToArgvW(GetCommandLineW(), - &NewArgCount); + int ArgCount; + wchar_t **UnicodeCommandLine = + CommandLineToArgvW(GetCommandLineW(), &ArgCount); if (!UnicodeCommandLine) return windows_error(::GetLastError()); - Args.reserve(NewArgCount); + Args.reserve(ArgCount); + std::error_code ec; - for (int i = 0; i < NewArgCount; ++i) { - SmallVector<char, MAX_PATH> NewArgString; - ec = windows::UTF16ToUTF8(UnicodeCommandLine[i], - wcslen(UnicodeCommandLine[i]), - NewArgString); + for (int i = 0; i < ArgCount; ++i) { + ec = WildcardExpand(UnicodeCommandLine[i], Args, ArgAllocator); if (ec) break; - - char *Buffer = ArgAllocator.Allocate(NewArgString.size() + 1); - ::memcpy(Buffer, NewArgString.data(), NewArgString.size() + 1); - Args.push_back(Buffer); } + LocalFree(UnicodeCommandLine); - if (ec) - return ec; + return ec; +} + +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(); } diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc index b2f71ae..72c2a58 100644 --- a/lib/Support/Windows/Program.inc +++ b/lib/Support/Windows/Program.inc @@ -12,7 +12,11 @@ //===----------------------------------------------------------------------===// #include "WindowsSupport.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/WindowsError.h" #include <cstdio> #include <fcntl.h> #include <io.h> @@ -28,43 +32,67 @@ using namespace sys; ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {} -// This function just uses the PATH environment variable to find the program. -std::string sys::FindProgramByName(const std::string &progName) { - // Check some degenerate cases - if (progName.length() == 0) // no program - return ""; - std::string temp = progName; - // Return paths with slashes verbatim. - if (progName.find('\\') != std::string::npos || - progName.find('/') != std::string::npos) - return temp; - - // At this point, the file name is valid and does not contain slashes. - // Let Windows search for it. - SmallVector<wchar_t, MAX_PATH> progNameUnicode; - if (windows::UTF8ToUTF16(progName, progNameUnicode)) - return ""; - - SmallVector<wchar_t, MAX_PATH> buffer; - DWORD len = MAX_PATH; - do { - buffer.reserve(len); - len = ::SearchPathW(NULL, progNameUnicode.data(), L".exe", - buffer.capacity(), buffer.data(), NULL); - - // See if it wasn't found. - if (len == 0) - return ""; - - // Buffer was too small; grow and retry. - } while (len > buffer.capacity()); - - buffer.set_size(len); - SmallVector<char, MAX_PATH> result; - if (windows::UTF16ToUTF8(buffer.begin(), buffer.size(), result)) - return ""; - - return std::string(result.data(), result.size()); +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%. + SplitString(std::getenv("PATHEXT"), 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); + Len = ::SearchPathW(Path, c_str(U16Name), + U16Ext.empty() ? nullptr : c_str(U16Ext), + 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()); } static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) { @@ -166,19 +194,7 @@ static unsigned int ArgLenWithQuotes(const char *Str) { } -static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, - const char **envp, const StringRef **redirects, - unsigned memoryLimit, std::string *ErrMsg) { - if (!sys::fs::can_execute(Program)) { - if (ErrMsg) - *ErrMsg = "program not executable"; - return false; - } - - // 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). - +static std::unique_ptr<char[]> flattenArgs(const char **args) { // First, determine the length of the command line. unsigned len = 0; for (unsigned i = 0; args[i]; i++) { @@ -216,6 +232,22 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, } *p = 0; + return command; +} + +static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, + const char **envp, const StringRef **redirects, + unsigned memoryLimit, std::string *ErrMsg) { + if (!sys::fs::can_execute(Program)) { + if (ErrMsg) + *ErrMsg = "program not executable"; + return false; + } + + // 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). + std::unique_ptr<char[]> command = flattenArgs(args); // The pointer to the environment block for the new process. std::vector<wchar_t> EnvBlock; @@ -422,20 +454,64 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, return WaitResult; } - std::error_code sys::ChangeStdinToBinary(){ - int result = _setmode( _fileno(stdin), _O_BINARY ); +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 ); +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::OpenFlags::F_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 std::make_error_code(std::errc::io_error); + + return EC; +} + bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) { // The documented max length of the command line passed to CreateProcess. static const size_t MaxCommandStringLength = 32768; diff --git a/lib/Support/Windows/RWMutex.inc b/lib/Support/Windows/RWMutex.inc index 00d0e93..2d1d25f 100644 --- a/lib/Support/Windows/RWMutex.inc +++ b/lib/Support/Windows/RWMutex.inc @@ -84,12 +84,10 @@ RWMutexImpl::RWMutexImpl() { } RWMutexImpl::~RWMutexImpl() { - if (sHasSRW) { - // Nothing to do in the case of slim reader/writers - } else { + if (!sHasSRW) DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); - free(data_); - } + // Nothing to do in the case of slim reader/writers except free the memory. + free(data_); } bool RWMutexImpl::reader_acquire() { diff --git a/lib/Support/Windows/ThreadLocal.inc b/lib/Support/Windows/ThreadLocal.inc index 3914cf7..14ce619 100644 --- a/lib/Support/Windows/ThreadLocal.inc +++ b/lib/Support/Windows/ThreadLocal.inc @@ -23,7 +23,7 @@ namespace llvm { using namespace sys; ThreadLocalImpl::ThreadLocalImpl() : data() { - typedef int SIZE_TOO_BIG[sizeof(DWORD) <= sizeof(data) ? 1 : -1]; + static_assert(sizeof(DWORD) <= sizeof(data), "size too big"); DWORD* tls = reinterpret_cast<DWORD*>(&data); *tls = TlsAlloc(); assert(*tls != TLS_OUT_OF_INDEXES); diff --git a/lib/Support/Windows/WindowsSupport.h b/lib/Support/Windows/WindowsSupport.h index f68835b..6d9c5fb 100644 --- a/lib/Support/Windows/WindowsSupport.h +++ b/lib/Support/Windows/WindowsSupport.h @@ -166,6 +166,9 @@ namespace windows { std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16); std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, SmallVectorImpl<char> &utf8); +/// Convert from UTF16 to the current code page used in the system +std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, + SmallVectorImpl<char> &utf8); } // end namespace windows } // end namespace sys } // end namespace llvm. diff --git a/lib/Support/Windows/explicit_symbols.inc b/lib/Support/Windows/explicit_symbols.inc index 379645d..cd56b13 100644 --- a/lib/Support/Windows/explicit_symbols.inc +++ b/lib/Support/Windows/explicit_symbols.inc @@ -63,4 +63,34 @@ /* 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) + + // These were added in VS 2013. +#if (1800 <= _MSC_VER && _MSC_VER < 1900) + INLINE_DEF_FLOAT_SYMBOL(copysignf, 2) + INLINE_DEF_FLOAT_SYMBOL(fminf, 2) + INLINE_DEF_FLOAT_SYMBOL(fmaxf, 2) +#endif +#undef INLINE_DEF_FLOAT_SYMBOL +#endif + #endif |