Skip to content

Commit bbe27f9

Browse files
authored
Merge pull request #62605 from al45tair/eng/PR-103397975
Centralise code to map between UTF-8 and UTF-16 on Windows.
2 parents a5c81b9 + a13d677 commit bbe27f9

File tree

8 files changed

+227
-124
lines changed

8 files changed

+227
-124
lines changed

include/swift/Runtime/Win32.h

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//===--- Win32.h - Win32 utility functions ----------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Utility functions that are specific to the Windows port.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_RUNTIME_WIN32_H
18+
#define SWIFT_RUNTIME_WIN32_H
19+
20+
#ifdef _WIN32
21+
22+
#include "swift/shims/Visibility.h"
23+
24+
#include <functional>
25+
#include <type_traits>
26+
27+
// For HANDLE
28+
#define WIN32_LEAN_AND_MEAN
29+
#define NOMINMAX
30+
#include <windows.h>
31+
32+
#include <wchar.h>
33+
34+
/// Convert a wide string to UTF-8.
35+
///
36+
/// @param str The string to convert.
37+
///
38+
/// @returns The string, converted to UTF-8. The caller is responsible
39+
/// for freeing this string with @c free() when done with it.
40+
///
41+
/// If @a str cannot be converted to UTF-8, @c nullptr is returned.
42+
SWIFT_RUNTIME_STDLIB_SPI
43+
char *_swift_win32_copyUTF8FromWide(const wchar_t *str);
44+
45+
/// Convert a UTF-8 string to a wide string.
46+
///
47+
/// @param str The string to convert.
48+
///
49+
/// @returns The string, converted to UTF-16. The caller is responsible
50+
/// for freeing this string with @c free() when done with it.
51+
///
52+
/// If @a str cannot be converted to UTF-16, @c nullptr is returned.
53+
SWIFT_RUNTIME_STDLIB_SPI
54+
wchar_t *_swift_win32_copyWideFromUTF8(const char *str);
55+
56+
/// Configure the environment to allow calling into the Debug Help library.
57+
///
58+
/// \param body A function to invoke. This function attempts to first initialize
59+
/// the Debug Help library. If it did so successfully, the handle used during
60+
/// initialization is passed to this function and should be used with
61+
/// subsequent calls to the Debug Help library. Do not close this handle.
62+
/// \param context A caller-supplied value to pass to \a body.
63+
///
64+
/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All
65+
/// calls into it from the Swift runtime and stdlib should route through this
66+
/// function.
67+
///
68+
/// This function sets the Debug Help library's options by calling
69+
/// \c SymSetOptions() before \a body is invoked, and then resets them back to
70+
/// their old value before returning. \a body can also call \c SymSetOptions()
71+
/// if needed.
72+
SWIFT_RUNTIME_STDLIB_SPI
73+
void _swift_win32_withDbgHelpLibrary(
74+
void (* body)(HANDLE hProcess, void *context), void *context);
75+
76+
/// Configure the environment to allow calling into the Debug Help library.
77+
///
78+
/// \param body A function to invoke. This function attempts to first initialize
79+
/// the Debug Help library. If it did so successfully, the handle used during
80+
/// initialization is passed to this function and should be used with
81+
/// subsequent calls to the Debug Help library. Do not close this handle.
82+
///
83+
/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All
84+
/// calls into it from the Swift runtime and stdlib should route through this
85+
/// function.
86+
///
87+
/// This function sets the Debug Help library's options by calling
88+
/// \c SymSetOptions() before \a body is invoked, and then resets them back to
89+
/// their old value before returning. \a body can also call \c SymSetOptions()
90+
/// if needed.
91+
static inline void _swift_win32_withDbgHelpLibrary(
92+
const std::function<void(HANDLE /*hProcess*/)> &body) {
93+
_swift_win32_withDbgHelpLibrary([](HANDLE hProcess, void *context) {
94+
auto bodyp = reinterpret_cast<std::function<void(HANDLE)> *>(context);
95+
(* bodyp)(hProcess);
96+
}, const_cast<void *>(reinterpret_cast<const void *>(&body)));
97+
}
98+
99+
/// Configure the environment to allow calling into the Debug Help library.
100+
///
101+
/// \param body A function to invoke. This function attempts to first initialize
102+
/// the Debug Help library. If it did so successfully, the handle used during
103+
/// initialization is passed to this function and should be used with
104+
/// subsequent calls to the Debug Help library. Do not close this handle.
105+
///
106+
/// \returns Whatever is returned from \a body.
107+
///
108+
/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All
109+
/// calls into it from the Swift runtime and stdlib should route through this
110+
/// function.
111+
///
112+
/// This function sets the Debug Help library's options by calling
113+
/// \c SymSetOptions() before \a body is invoked, and then resets them back to
114+
/// their old value before returning. \a body can also call \c SymSetOptions()
115+
/// if needed.
116+
template <
117+
typename F,
118+
typename R = typename std::result_of_t<F&(HANDLE /*hProcess*/)>,
119+
typename = typename std::enable_if_t<!std::is_same<void, R>::value>
120+
>
121+
static inline R _swift_win32_withDbgHelpLibrary(const F& body) {
122+
R result;
123+
124+
_swift_win32_withDbgHelpLibrary([&body, &result] (HANDLE hProcess) {
125+
result = body(hProcess);
126+
});
127+
128+
return result;
129+
}
130+
131+
#endif // defined(_WIN32)
132+
133+
#endif // SWIFT_RUNTIME_WIN32_H

stdlib/public/CommandLineSupport/CommandLine.cpp

Lines changed: 13 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <string>
2626

2727
#include "swift/Runtime/Debug.h"
28+
#include "swift/Runtime/Win32.h"
2829

2930
#include "swift/shims/GlobalObjects.h"
3031
#include "swift/shims/RuntimeStubs.h"
@@ -193,48 +194,6 @@ static void swift::enumerateUnsafeArgv(const F& body) {
193194
#elif defined(_WIN32)
194195
#include <stdlib.h>
195196

196-
namespace swift {
197-
/// Convert an argument, represented by a wide string, to UTF-8.
198-
///
199-
/// @param str The string to convert.
200-
///
201-
/// @returns The string, converted to UTF-8. The caller is responsible for
202-
/// freeing this string when done with it.
203-
///
204-
/// If @a str cannot be converted to UTF-8, a fatal error occurs.
205-
static char *copyUTF8FromWide(wchar_t *str) {
206-
char *result = nullptr;
207-
208-
int resultLength = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, str,
209-
-1, nullptr, 0, nullptr, nullptr);
210-
if (resultLength <= 0) {
211-
swift::fatalError(0,
212-
"Fatal error: Could not get length of commandline "
213-
"argument '%ls': %lu\n",
214-
str, GetLastError());
215-
}
216-
217-
result = reinterpret_cast<char *>(malloc(resultLength));
218-
if (!result) {
219-
swift::fatalError(0,
220-
"Fatal error: Could not allocate space for commandline "
221-
"argument '%ls': %d\n",
222-
str, errno);
223-
}
224-
225-
resultLength = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, str, -1,
226-
result, resultLength, nullptr, nullptr);
227-
if (resultLength <= 0) {
228-
swift::fatalError(0,
229-
"Fatal error: Conversion to UTF-8 failed for "
230-
"commandline argument '%ls': %lu\n",
231-
str, GetLastError());
232-
}
233-
234-
return result;
235-
}
236-
}
237-
238197
static char **swift::getUnsafeArgvArgc(int *outArgLen) {
239198
return nullptr;
240199
}
@@ -244,9 +203,18 @@ static void swift::enumerateUnsafeArgv(const F& body) {
244203
int argc = 0;
245204
if (LPWSTR *wargv = CommandLineToArgvW(GetCommandLineW(), &argc)) {
246205
std::for_each(wargv, wargv + argc, [=] (wchar_t *warg) {
247-
auto arg = copyUTF8FromWide(warg);
248-
body(argc, arg);
249-
free(arg);
206+
if (char *arg = _swift_win32_copyUTF8FromWide(warg)) {
207+
body(argc, arg);
208+
free(arg);
209+
} else {
210+
// Note that GetLastError() and errno may not be so useful here,
211+
// as in the error case we may have called free(), which might reset
212+
// either or both of them.
213+
swift::fatalError(0,
214+
"Fatal error: Unable to convert argument '%ls' to "
215+
"UTF-8: %lx, %d.\n",
216+
warg, ::GetLastError(), errno);
217+
}
250218
});
251219

252220
LocalFree(wargv);

stdlib/public/runtime/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ set(swift_runtime_sources
7070
SwiftTLSContext.cpp
7171
ThreadingError.cpp
7272
AccessibleFunction.cpp
73-
RuntimeAttribute.cpp)
73+
RuntimeAttribute.cpp
74+
Win32.cpp)
7475

7576
# Acknowledge that the following sources are known.
7677
set(LLVM_OPTIONAL_SOURCES

stdlib/public/runtime/Errors.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "swift/Demangling/Demangle.h"
3737
#include "swift/Runtime/Debug.h"
3838
#include "swift/Runtime/Portability.h"
39+
#include "swift/Runtime/Win32.h"
3940
#include "swift/Threading/Errors.h"
4041
#include "swift/Threading/Mutex.h"
4142
#include "llvm/ADT/StringRef.h"

stdlib/public/runtime/ImageInspection.h

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -92,83 +92,6 @@ void addImageRuntimeAttributesBlockCallbackUnsafe(const void *baseAddress,
9292
const void *start,
9393
uintptr_t size);
9494

95-
#if defined(_WIN32)
96-
/// Configure the environment to allow calling into the Debug Help library.
97-
///
98-
/// \param body A function to invoke. This function attempts to first initialize
99-
/// the Debug Help library. If it did so successfully, the handle used during
100-
/// initialization is passed to this function and should be used with
101-
/// subsequent calls to the Debug Help library. Do not close this handle.
102-
/// \param context A caller-supplied value to pass to \a body.
103-
///
104-
/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All
105-
/// calls into it from the Swift runtime and stdlib should route through this
106-
/// function.
107-
///
108-
/// This function sets the Debug Help library's options by calling
109-
/// \c SymSetOptions() before \a body is invoked, and then resets them back to
110-
/// their old value before returning. \a body can also call \c SymSetOptions()
111-
/// if needed.
112-
SWIFT_RUNTIME_STDLIB_SPI
113-
void _swift_win32_withDbgHelpLibrary(
114-
void (* body)(HANDLE hProcess, void *context), void *context);
115-
116-
/// Configure the environment to allow calling into the Debug Help library.
117-
///
118-
/// \param body A function to invoke. This function attempts to first initialize
119-
/// the Debug Help library. If it did so successfully, the handle used during
120-
/// initialization is passed to this function and should be used with
121-
/// subsequent calls to the Debug Help library. Do not close this handle.
122-
///
123-
/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All
124-
/// calls into it from the Swift runtime and stdlib should route through this
125-
/// function.
126-
///
127-
/// This function sets the Debug Help library's options by calling
128-
/// \c SymSetOptions() before \a body is invoked, and then resets them back to
129-
/// their old value before returning. \a body can also call \c SymSetOptions()
130-
/// if needed.
131-
static inline void _swift_win32_withDbgHelpLibrary(
132-
const std::function<void(HANDLE /*hProcess*/)> &body) {
133-
_swift_win32_withDbgHelpLibrary([](HANDLE hProcess, void *context) {
134-
auto bodyp = reinterpret_cast<std::function<void(HANDLE)> *>(context);
135-
(* bodyp)(hProcess);
136-
}, const_cast<void *>(reinterpret_cast<const void *>(&body)));
137-
}
138-
139-
/// Configure the environment to allow calling into the Debug Help library.
140-
///
141-
/// \param body A function to invoke. This function attempts to first initialize
142-
/// the Debug Help library. If it did so successfully, the handle used during
143-
/// initialization is passed to this function and should be used with
144-
/// subsequent calls to the Debug Help library. Do not close this handle.
145-
///
146-
/// \returns Whatever is returned from \a body.
147-
///
148-
/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All
149-
/// calls into it from the Swift runtime and stdlib should route through this
150-
/// function.
151-
///
152-
/// This function sets the Debug Help library's options by calling
153-
/// \c SymSetOptions() before \a body is invoked, and then resets them back to
154-
/// their old value before returning. \a body can also call \c SymSetOptions()
155-
/// if needed.
156-
template <
157-
typename F,
158-
typename R = typename std::result_of_t<F&(HANDLE /*hProcess*/)>,
159-
typename = typename std::enable_if_t<!std::is_same<void, R>::value>
160-
>
161-
static inline R _swift_win32_withDbgHelpLibrary(const F& body) {
162-
R result;
163-
164-
_swift_win32_withDbgHelpLibrary([&body, &result] (HANDLE hProcess) {
165-
result = body(hProcess);
166-
});
167-
168-
return result;
169-
}
170-
#endif
171-
17295
} // end namespace swift
17396

17497
#endif

stdlib/public/runtime/ImageInspectionCOFF.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <DbgHelp.h>
2424
#endif
2525

26+
#include "swift/Runtime/Win32.h"
2627
#include "swift/Threading/Mutex.h"
2728

2829
using namespace swift;
@@ -31,7 +32,7 @@ using namespace swift;
3132
static LazyMutex mutex;
3233
static HANDLE dbgHelpHandle = nullptr;
3334

34-
void swift::_swift_win32_withDbgHelpLibrary(
35+
void _swift_win32_withDbgHelpLibrary(
3536
void (* body)(HANDLE hProcess, void *context), void *context) {
3637
mutex.withLock([=] () {
3738
// If we have not previously created a handle to use with the library, do so

stdlib/public/runtime/SymbolInfo.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include <dlfcn.h>
2222
#endif
2323

24+
#include "swift/Runtime/Win32.h"
25+
2426
#include "ImageInspection.h"
2527

2628
using namespace swift;

0 commit comments

Comments
 (0)