diff --git a/include/swift/Runtime/Win32.h b/include/swift/Runtime/Win32.h new file mode 100644 index 0000000000000..ee9729b05ca35 --- /dev/null +++ b/include/swift/Runtime/Win32.h @@ -0,0 +1,133 @@ +//===--- Win32.h - Win32 utility functions ----------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Utility functions that are specific to the Windows port. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_RUNTIME_WIN32_H +#define SWIFT_RUNTIME_WIN32_H + +#ifdef _WIN32 + +#include "swift/shims/Visibility.h" + +#include +#include + +// For HANDLE +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include + +#include + +/// Convert a wide string to UTF-8. +/// +/// @param str The string to convert. +/// +/// @returns The string, converted to UTF-8. The caller is responsible +/// for freeing this string with @c free() when done with it. +/// +/// If @a str cannot be converted to UTF-8, @c nullptr is returned. +SWIFT_RUNTIME_STDLIB_SPI +char *_swift_win32_copyUTF8FromWide(const wchar_t *str); + +/// Convert a UTF-8 string to a wide string. +/// +/// @param str The string to convert. +/// +/// @returns The string, converted to UTF-16. The caller is responsible +/// for freeing this string with @c free() when done with it. +/// +/// If @a str cannot be converted to UTF-16, @c nullptr is returned. +SWIFT_RUNTIME_STDLIB_SPI +wchar_t *_swift_win32_copyWideFromUTF8(const char *str); + +/// Configure the environment to allow calling into the Debug Help library. +/// +/// \param body A function to invoke. This function attempts to first initialize +/// the Debug Help library. If it did so successfully, the handle used during +/// initialization is passed to this function and should be used with +/// subsequent calls to the Debug Help library. Do not close this handle. +/// \param context A caller-supplied value to pass to \a body. +/// +/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All +/// calls into it from the Swift runtime and stdlib should route through this +/// function. +/// +/// This function sets the Debug Help library's options by calling +/// \c SymSetOptions() before \a body is invoked, and then resets them back to +/// their old value before returning. \a body can also call \c SymSetOptions() +/// if needed. +SWIFT_RUNTIME_STDLIB_SPI +void _swift_win32_withDbgHelpLibrary( + void (* body)(HANDLE hProcess, void *context), void *context); + +/// Configure the environment to allow calling into the Debug Help library. +/// +/// \param body A function to invoke. This function attempts to first initialize +/// the Debug Help library. If it did so successfully, the handle used during +/// initialization is passed to this function and should be used with +/// subsequent calls to the Debug Help library. Do not close this handle. +/// +/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All +/// calls into it from the Swift runtime and stdlib should route through this +/// function. +/// +/// This function sets the Debug Help library's options by calling +/// \c SymSetOptions() before \a body is invoked, and then resets them back to +/// their old value before returning. \a body can also call \c SymSetOptions() +/// if needed. +static inline void _swift_win32_withDbgHelpLibrary( + const std::function &body) { + _swift_win32_withDbgHelpLibrary([](HANDLE hProcess, void *context) { + auto bodyp = reinterpret_cast *>(context); + (* bodyp)(hProcess); + }, const_cast(reinterpret_cast(&body))); +} + +/// Configure the environment to allow calling into the Debug Help library. +/// +/// \param body A function to invoke. This function attempts to first initialize +/// the Debug Help library. If it did so successfully, the handle used during +/// initialization is passed to this function and should be used with +/// subsequent calls to the Debug Help library. Do not close this handle. +/// +/// \returns Whatever is returned from \a body. +/// +/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All +/// calls into it from the Swift runtime and stdlib should route through this +/// function. +/// +/// This function sets the Debug Help library's options by calling +/// \c SymSetOptions() before \a body is invoked, and then resets them back to +/// their old value before returning. \a body can also call \c SymSetOptions() +/// if needed. +template < + typename F, + typename R = typename std::result_of_t, + typename = typename std::enable_if_t::value> +> +static inline R _swift_win32_withDbgHelpLibrary(const F& body) { + R result; + + _swift_win32_withDbgHelpLibrary([&body, &result] (HANDLE hProcess) { + result = body(hProcess); + }); + + return result; +} + +#endif // defined(_WIN32) + +#endif // SWIFT_RUNTIME_WIN32_H diff --git a/stdlib/public/CommandLineSupport/CommandLine.cpp b/stdlib/public/CommandLineSupport/CommandLine.cpp index d06b21971f404..18efd62f76415 100644 --- a/stdlib/public/CommandLineSupport/CommandLine.cpp +++ b/stdlib/public/CommandLineSupport/CommandLine.cpp @@ -25,6 +25,7 @@ #include #include "swift/Runtime/Debug.h" +#include "swift/Runtime/Win32.h" #include "swift/shims/GlobalObjects.h" #include "swift/shims/RuntimeStubs.h" @@ -193,48 +194,6 @@ static void swift::enumerateUnsafeArgv(const F& body) { #elif defined(_WIN32) #include -namespace swift { - /// Convert an argument, represented by a wide string, to UTF-8. - /// - /// @param str The string to convert. - /// - /// @returns The string, converted to UTF-8. The caller is responsible for - /// freeing this string when done with it. - /// - /// If @a str cannot be converted to UTF-8, a fatal error occurs. - static char *copyUTF8FromWide(wchar_t *str) { - char *result = nullptr; - - int resultLength = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, str, - -1, nullptr, 0, nullptr, nullptr); - if (resultLength <= 0) { - swift::fatalError(0, - "Fatal error: Could not get length of commandline " - "argument '%ls': %lu\n", - str, GetLastError()); - } - - result = reinterpret_cast(malloc(resultLength)); - if (!result) { - swift::fatalError(0, - "Fatal error: Could not allocate space for commandline " - "argument '%ls': %d\n", - str, errno); - } - - resultLength = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, str, -1, - result, resultLength, nullptr, nullptr); - if (resultLength <= 0) { - swift::fatalError(0, - "Fatal error: Conversion to UTF-8 failed for " - "commandline argument '%ls': %lu\n", - str, GetLastError()); - } - - return result; - } -} - static char **swift::getUnsafeArgvArgc(int *outArgLen) { return nullptr; } @@ -244,9 +203,18 @@ static void swift::enumerateUnsafeArgv(const F& body) { int argc = 0; if (LPWSTR *wargv = CommandLineToArgvW(GetCommandLineW(), &argc)) { std::for_each(wargv, wargv + argc, [=] (wchar_t *warg) { - auto arg = copyUTF8FromWide(warg); - body(argc, arg); - free(arg); + if (char *arg = _swift_win32_copyUTF8FromWide(warg)) { + body(argc, arg); + free(arg); + } else { + // Note that GetLastError() and errno may not be so useful here, + // as in the error case we may have called free(), which might reset + // either or both of them. + swift::fatalError(0, + "Fatal error: Unable to convert argument '%ls' to " + "UTF-8: %lx, %d.\n", + warg, ::GetLastError(), errno); + } }); LocalFree(wargv); diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index c6a32d004a8ea..3aacf32cb352d 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -70,7 +70,8 @@ set(swift_runtime_sources SwiftTLSContext.cpp ThreadingError.cpp AccessibleFunction.cpp - RuntimeAttribute.cpp) + RuntimeAttribute.cpp + Win32.cpp) # Acknowledge that the following sources are known. set(LLVM_OPTIONAL_SOURCES diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp index 221e2b0712a6d..b126245d14bbe 100644 --- a/stdlib/public/runtime/Errors.cpp +++ b/stdlib/public/runtime/Errors.cpp @@ -36,6 +36,7 @@ #include "swift/Demangling/Demangle.h" #include "swift/Runtime/Debug.h" #include "swift/Runtime/Portability.h" +#include "swift/Runtime/Win32.h" #include "swift/Threading/Errors.h" #include "swift/Threading/Mutex.h" #include "llvm/ADT/StringRef.h" diff --git a/stdlib/public/runtime/ImageInspection.h b/stdlib/public/runtime/ImageInspection.h index f7d730d34ca46..f06694c7ab17d 100644 --- a/stdlib/public/runtime/ImageInspection.h +++ b/stdlib/public/runtime/ImageInspection.h @@ -92,83 +92,6 @@ void addImageRuntimeAttributesBlockCallbackUnsafe(const void *baseAddress, const void *start, uintptr_t size); -#if defined(_WIN32) -/// Configure the environment to allow calling into the Debug Help library. -/// -/// \param body A function to invoke. This function attempts to first initialize -/// the Debug Help library. If it did so successfully, the handle used during -/// initialization is passed to this function and should be used with -/// subsequent calls to the Debug Help library. Do not close this handle. -/// \param context A caller-supplied value to pass to \a body. -/// -/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All -/// calls into it from the Swift runtime and stdlib should route through this -/// function. -/// -/// This function sets the Debug Help library's options by calling -/// \c SymSetOptions() before \a body is invoked, and then resets them back to -/// their old value before returning. \a body can also call \c SymSetOptions() -/// if needed. -SWIFT_RUNTIME_STDLIB_SPI -void _swift_win32_withDbgHelpLibrary( - void (* body)(HANDLE hProcess, void *context), void *context); - -/// Configure the environment to allow calling into the Debug Help library. -/// -/// \param body A function to invoke. This function attempts to first initialize -/// the Debug Help library. If it did so successfully, the handle used during -/// initialization is passed to this function and should be used with -/// subsequent calls to the Debug Help library. Do not close this handle. -/// -/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All -/// calls into it from the Swift runtime and stdlib should route through this -/// function. -/// -/// This function sets the Debug Help library's options by calling -/// \c SymSetOptions() before \a body is invoked, and then resets them back to -/// their old value before returning. \a body can also call \c SymSetOptions() -/// if needed. -static inline void _swift_win32_withDbgHelpLibrary( - const std::function &body) { - _swift_win32_withDbgHelpLibrary([](HANDLE hProcess, void *context) { - auto bodyp = reinterpret_cast *>(context); - (* bodyp)(hProcess); - }, const_cast(reinterpret_cast(&body))); -} - -/// Configure the environment to allow calling into the Debug Help library. -/// -/// \param body A function to invoke. This function attempts to first initialize -/// the Debug Help library. If it did so successfully, the handle used during -/// initialization is passed to this function and should be used with -/// subsequent calls to the Debug Help library. Do not close this handle. -/// -/// \returns Whatever is returned from \a body. -/// -/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All -/// calls into it from the Swift runtime and stdlib should route through this -/// function. -/// -/// This function sets the Debug Help library's options by calling -/// \c SymSetOptions() before \a body is invoked, and then resets them back to -/// their old value before returning. \a body can also call \c SymSetOptions() -/// if needed. -template < - typename F, - typename R = typename std::result_of_t, - typename = typename std::enable_if_t::value> -> -static inline R _swift_win32_withDbgHelpLibrary(const F& body) { - R result; - - _swift_win32_withDbgHelpLibrary([&body, &result] (HANDLE hProcess) { - result = body(hProcess); - }); - - return result; -} -#endif - } // end namespace swift #endif diff --git a/stdlib/public/runtime/ImageInspectionCOFF.cpp b/stdlib/public/runtime/ImageInspectionCOFF.cpp index 7277c863557b2..f9803345ff747 100644 --- a/stdlib/public/runtime/ImageInspectionCOFF.cpp +++ b/stdlib/public/runtime/ImageInspectionCOFF.cpp @@ -23,6 +23,7 @@ #include #endif +#include "swift/Runtime/Win32.h" #include "swift/Threading/Mutex.h" using namespace swift; @@ -31,7 +32,7 @@ using namespace swift; static LazyMutex mutex; static HANDLE dbgHelpHandle = nullptr; -void swift::_swift_win32_withDbgHelpLibrary( +void _swift_win32_withDbgHelpLibrary( void (* body)(HANDLE hProcess, void *context), void *context) { mutex.withLock([=] () { // If we have not previously created a handle to use with the library, do so diff --git a/stdlib/public/runtime/SymbolInfo.cpp b/stdlib/public/runtime/SymbolInfo.cpp index ebcccf71e79b2..f51e46b02aa95 100644 --- a/stdlib/public/runtime/SymbolInfo.cpp +++ b/stdlib/public/runtime/SymbolInfo.cpp @@ -21,6 +21,8 @@ #include #endif +#include "swift/Runtime/Win32.h" + #include "ImageInspection.h" using namespace swift; diff --git a/stdlib/public/runtime/Win32.cpp b/stdlib/public/runtime/Win32.cpp new file mode 100644 index 0000000000000..14eb627d052a1 --- /dev/null +++ b/stdlib/public/runtime/Win32.cpp @@ -0,0 +1,74 @@ +//===--- Win32.cpp - Win32 utility functions --------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Utility functions that are specific to the Windows port. +// +//===----------------------------------------------------------------------===// + +#include "swift/Runtime/Debug.h" +#include "swift/Runtime/Win32.h" + +#ifdef _WIN32 + +#include + +char * +_swift_win32_copyUTF8FromWide(const wchar_t *str) { + char *result = nullptr; + int len = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, + str, -1, + nullptr, 0, + nullptr, nullptr); + if (len <= 0) + return nullptr; + + result = reinterpret_cast(std::malloc(len)); + if (!result) + return nullptr; + + len = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, + str, -1, + result, len, + nullptr, nullptr); + + if (len) + return result; + + free(result); + return nullptr; +} + +wchar_t * +_swift_win32_copyWideFromUTF8(const char *str) { + wchar_t *result = nullptr; + int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + str, -1, + nullptr, 0); + if (len <= 0) + return nullptr; + + result = reinterpret_cast(std::malloc(len * sizeof(wchar_t))); + if (!result) + return nullptr; + + len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + str, -1, + result, len); + + if (len) + return result; + + free(result); + return nullptr; +} + +#endif // defined(_WIN32)