Flutter Engine
The Flutter Engine
platform_win.cc
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/globals.h"
6#if defined(DART_HOST_OS_WINDOWS)
7
8#include "bin/platform.h"
9
10#include <crtdbg.h>
11
12#include "bin/console.h"
13#include "bin/file.h"
14#include "bin/lockers.h"
15#include "platform/syslog.h"
16#if !defined(PLATFORM_DISABLE_SOCKET)
17#include "bin/socket.h"
18#endif
19#include "bin/thread.h"
20#include "bin/utils.h"
21#include "bin/utils_win.h"
22
23namespace dart {
24namespace bin {
25
26const char* Platform::executable_name_ = nullptr;
27int Platform::script_index_ = 1;
28char** Platform::argv_ = nullptr;
29
30class PlatformWin {
31 public:
32 static void InitOnce() {
33 // Set up a no-op handler so that CRT functions return an error instead of
34 // hitting an assertion failure.
35 // See: https://msdn.microsoft.com/en-us/library/a9yf33zb.aspx
36 _set_invalid_parameter_handler(InvalidParameterHandler);
37 // Ensure no dialog boxes for assertions, errors and warnings in the CRT
38 // in Debug builds.
39 // See: https://msdn.microsoft.com/en-us/library/1y71x448.aspx
40 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
41 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
42 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
43 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
44 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
45 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
46
47 // Set location where the C runtime writes an error message for an error
48 // that might end the program.
49 _set_error_mode(_OUT_TO_STDERR);
50
51 // Disable dialog boxes for "critical" errors or when OpenFile cannot find
52 // the requested file. However only disable error boxes for general
53 // protection faults if an environment variable is set. Passing
54 // SEM_NOGPFAULTERRORBOX completely disables WindowsErrorReporting (WER)
55 // for the process, which means users loose ability to enable local dump
56 // archiving to collect minidumps for Dart VM crashes.
57 // Our test runner would set DART_SUPPRESS_WER to suppress WER UI during
58 // test suite execution.
59 // See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx
60 UINT new_mode = SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX;
61 if (getenv("DART_SUPPRESS_WER") != nullptr) {
62 new_mode |= SEM_NOGPFAULTERRORBOX;
63 }
64 UINT existing_mode = SetErrorMode(new_mode);
65 SetErrorMode(new_mode | existing_mode);
66 // Set up global exception handler to be able to dump stack trace on crash.
67 SetExceptionHandler();
68 }
69
70 // Windows top-level unhandled exception handler function.
71 // See MSDN documentation for UnhandledExceptionFilter.
72 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681401(v=vs.85).aspx
73 static LONG WINAPI
74 DartExceptionHandler(struct _EXCEPTION_POINTERS* ExceptionInfo) {
75 if ((ExceptionInfo->ExceptionRecord->ExceptionCode ==
76 EXCEPTION_ACCESS_VIOLATION) ||
77 (ExceptionInfo->ExceptionRecord->ExceptionCode ==
78 EXCEPTION_ILLEGAL_INSTRUCTION)) {
80 "\n===== CRASH =====\n"
81 "ExceptionCode=%d, ExceptionFlags=%d, ExceptionAddress=%p\n",
82 ExceptionInfo->ExceptionRecord->ExceptionCode,
83 ExceptionInfo->ExceptionRecord->ExceptionFlags,
84 ExceptionInfo->ExceptionRecord->ExceptionAddress);
85 Dart_DumpNativeStackTrace(ExceptionInfo->ContextRecord);
87 // Note: we want to abort(...) here instead of exiting because exiting
88 // would not cause WER to generate a minidump.
90 abort();
91 }
92 return EXCEPTION_CONTINUE_SEARCH;
93 }
94
95 static void SetExceptionHandler() {
96 SetUnhandledExceptionFilter(DartExceptionHandler);
97 }
98
99 private:
100 static void InvalidParameterHandler(const wchar_t* expression,
101 const wchar_t* function,
102 const wchar_t* file,
103 unsigned int line,
104 uintptr_t reserved) {
105 // Doing nothing here means that the CRT call that invoked it will
106 // return an error code and/or set errno.
107 }
108
111};
112
115 return true;
116}
117
119 SYSTEM_INFO info;
120 GetSystemInfo(&info);
121 return info.dwNumberOfProcessors;
122}
123
124// We pull the version number, and other version information out of the
125// registry because GetVersionEx() and friends lie about the OS version after
126// Windows 8.1. See:
127// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx
128static constexpr const wchar_t* kCurrentVersion =
129 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
130
131static bool GetCurrentVersionDWord(const wchar_t* field, DWORD* value) {
132 DWORD value_size = sizeof(*value);
133 LONG err = RegGetValue(HKEY_LOCAL_MACHINE, kCurrentVersion, field,
134 RRF_RT_REG_DWORD, nullptr, value, &value_size);
135 return err == ERROR_SUCCESS;
136}
137
138static bool GetCurrentVersionString(const wchar_t* field, const char** value) {
139 wchar_t wversion[256];
140 DWORD wversion_size = sizeof(wversion);
141 LONG err = RegGetValue(HKEY_LOCAL_MACHINE, kCurrentVersion, field,
142 RRF_RT_REG_SZ, nullptr, wversion, &wversion_size);
143 if (err != ERROR_SUCCESS) {
144 return false;
145 }
147 return true;
148}
149
150static const char* VersionNumber() {
151 // Try to get CurrentMajorVersionNumber. If that fails, fall back on
152 // CurrentVersion. If it succeeds also get CurrentMinorVersionNumber.
153 DWORD major;
154 if (!GetCurrentVersionDWord(L"CurrentMajorVersionNumber", &major)) {
155 const char* version;
156 if (!GetCurrentVersionString(L"CurrentVersion", &version)) {
157 return nullptr;
158 }
159 return version;
160 }
161
162 DWORD minor;
163 if (!GetCurrentVersionDWord(L"CurrentMinorVersionNumber", &minor)) {
164 return nullptr;
165 }
166 return DartUtils::ScopedCStringFormatted("%d.%d", major, minor);
167}
168
170 // Get the product name, e.g. "Windows 10 Home".
171 const char* name;
172 if (!GetCurrentVersionString(L"ProductName", &name)) {
173 return nullptr;
174 }
175
176 // Get the version number, e.g. "10.0".
177 const char* version_number = VersionNumber();
178 if (version_number == nullptr) {
179 return nullptr;
180 }
181
182 // Get the build number.
183 const char* build;
184 if (!GetCurrentVersionString(L"CurrentBuild", &build)) {
185 return nullptr;
186 }
187
188 // Put it all together.
189 const char* kFormat = "\"%s\" %s (Build %s)";
190 int len = snprintf(nullptr, 0, kFormat, name, version_number, build);
192 len = snprintf(result, len + 1, kFormat, name, version_number, build);
193 return result;
194}
195
196const char* Platform::LibraryPrefix() {
197 return "";
198}
199
200const char* Platform::LibraryExtension() {
201 return "dll";
202}
203
204const char* Platform::LocaleName() {
205 wchar_t locale_name[LOCALE_NAME_MAX_LENGTH];
206 int result = GetUserDefaultLocaleName(locale_name, LOCALE_NAME_MAX_LENGTH);
207 if (result == 0) {
208 return nullptr;
209 }
210 return StringUtilsWin::WideToUtf8(locale_name);
211}
212
213bool Platform::LocalHostname(char* buffer, intptr_t buffer_length) {
214#if defined(PLATFORM_DISABLE_SOCKET)
215 return false;
216#else
217 if (!SocketBase::Initialize()) {
218 return false;
219 }
220 // 256 is max length per https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-gethostnamew#remarks
221 const int HOSTNAME_MAXLENGTH = 256;
222 wchar_t hostname_w[HOSTNAME_MAXLENGTH];
223 if (GetHostNameW(hostname_w, HOSTNAME_MAXLENGTH) != 0) {
224 return false;
225 }
226 return WideCharToMultiByte(CP_UTF8, 0, hostname_w, -1, buffer, buffer_length,
227 nullptr, nullptr) != 0;
228#endif
229}
230
231char** Platform::Environment(intptr_t* count) {
232 wchar_t* strings = GetEnvironmentStringsW();
233 if (strings == nullptr) {
234 return nullptr;
235 }
236 wchar_t* tmp = strings;
237 intptr_t i = 0;
238 while (*tmp != '\0') {
239 // Skip environment strings starting with "=".
240 // These are synthetic variables corresponding to dynamic environment
241 // variables like %=C:% and %=ExitCode%, and the Dart environment does
242 // not include these.
243 if (*tmp != '=') {
244 i++;
245 }
246 tmp += (wcslen(tmp) + 1);
247 }
248 *count = i;
249 char** result;
250 result = reinterpret_cast<char**>(Dart_ScopeAllocate(i * sizeof(*result)));
251 tmp = strings;
252 for (intptr_t current = 0; current < i;) {
253 // Skip the strings that were not counted above.
254 if (*tmp != '=') {
255 result[current++] = StringUtilsWin::WideToUtf8(tmp);
256 }
257 tmp += (wcslen(tmp) + 1);
258 }
259 FreeEnvironmentStringsW(strings);
260 return result;
261}
262
263const char* Platform::GetExecutableName() {
264 return executable_name_;
265}
266
268 // GetModuleFileNameW cannot directly provide information on the
269 // required buffer size, so start out with a buffer large enough to
270 // hold any Windows path.
271 const int kTmpBufferSize = 32768;
272 wchar_t* tmp_buffer =
273 reinterpret_cast<wchar_t*>(Dart_ScopeAllocate(kTmpBufferSize));
274 // Ensure no last error before calling GetModuleFileNameW.
276 // Get the required length of the buffer.
277 GetModuleFileNameW(nullptr, tmp_buffer, kTmpBufferSize);
278 if (GetLastError() != ERROR_SUCCESS) {
279 return nullptr;
280 }
281 char* path = StringUtilsWin::WideToUtf8(tmp_buffer);
282 // Return the canonical path as the returned path might contain symlinks.
283 const char* canon_path = File::GetCanonicalPath(nullptr, path);
284 return canon_path;
285}
286
287intptr_t Platform::ResolveExecutablePathInto(char* result, size_t result_size) {
288 // Ensure no last error before calling GetModuleFileNameW.
290 const int kTmpBufferSize = 32768;
291 wchar_t tmp_buffer[kTmpBufferSize];
292 // Get the required length of the buffer.
293 GetModuleFileNameW(nullptr, tmp_buffer, kTmpBufferSize);
294 if (GetLastError() != ERROR_SUCCESS) {
295 return -1;
296 }
297 WideToUtf8Scope wide_to_utf8_scope(tmp_buffer);
298 if (wide_to_utf8_scope.length() <= result_size) {
299 strncpy(result, wide_to_utf8_scope.utf8(), result_size);
300 return wide_to_utf8_scope.length();
301 }
302 return -1;
303}
304
305void Platform::SetProcessName(const char* name) {}
306
307void Platform::Exit(int exit_code) {
308 // Restore the console's output code page
310 // On Windows we use ExitProcess so that threads can't clobber the exit_code.
311 // See: https://code.google.com/p/nativeclient/issues/detail?id=2870
313 ::ExitProcess(exit_code);
314}
315
316void Platform::_Exit(int exit_code) {
317 // Restore the console's output code page
319 // On Windows we use ExitProcess so that threads can't clobber the exit_code.
320 // See: https://code.google.com/p/nativeclient/issues/detail?id=2870
322 ::ExitProcess(exit_code);
323}
324
326 // Not supported.
327}
328
329} // namespace bin
330} // namespace dart
331
332#endif // defined(DART_HOST_OS_WINDOWS)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
int count
Definition: FontMgrTest.cpp:50
static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static void RestoreConfig()
static char * ScopedCStringFormatted(const char *format,...) PRINTF_ATTRIBUTE(1
Definition: dartutils.cc:813
static char * ScopedCString(intptr_t length)
Definition: dartutils.h:224
static const char * GetCanonicalPath(Namespace *namespc, const char *path, char *dest=nullptr, int dest_size=0)
static bool LocalHostname(char *buffer, intptr_t buffer_length)
static const char * GetExecutableName()
static const char * LibraryPrefix()
static DART_NORETURN void _Exit(int exit_code)
static void SetProcessName(const char *name)
static const char * LocaleName()
static DART_NORETURN void Exit(int exit_code)
static bool Initialize()
static char ** Environment(intptr_t *count)
static const char * OperatingSystemVersion()
static intptr_t ResolveExecutablePathInto(char *result, size_t result_size)
static int NumberOfProcessors()
static const char * LibraryExtension()
static const char * ResolveExecutablePath()
static void SetCoreDumpResourceLimit(int value)
static bool Initialize()
static char * WideToUtf8(wchar_t *wide, intptr_t len=-1, intptr_t *result_len=nullptr)
uint8_t value
GAsyncResult * result
Dart_NativeFunction function
Definition: fuchsia.cc:51
static constexpr int kCurrentVersion
Definition: build.py:1
bool InitOnce(char **error)
Definition: dart_vm.cc:33
DART_EXPORT void Dart_PrepareToAbort()
const char *const name
DART_EXPORT uint8_t * Dart_ScopeAllocate(intptr_t size)
DART_EXPORT void Dart_DumpNativeStackTrace(void *context)
def build()
Definition: dom.py:52
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName)
Definition: globals.h:593
#define DISALLOW_ALLOCATION()
Definition: globals.h:604
#define HKEY_LOCAL_MACHINE
long LONG
Definition: windows_types.h:23
unsigned int UINT
Definition: windows_types.h:32
WINBASEAPI VOID WINAPI SetLastError(_In_ DWORD dwErrCode)
#define WINAPI
WINBASEAPI _Check_return_ _Post_equals_last_error_ DWORD WINAPI GetLastError(VOID)
unsigned long DWORD
Definition: windows_types.h:22
#define ERROR_SUCCESS