forked from mirrors/gecko-dev
Correctness improvements: * UTF errors are handled safely per spec instead of dangerously truncating strings. * There are fewer converter implementations. Performance improvements: * The old code did exact buffer length math, which meant doing UTF math twice on each input string (once for length calculation and another time for conversion). Exact length math is more complicated when handling errors properly, which the old code didn't do. The new code does UTF math on the string content only once (when converting) but risks allocating more than once. There are heuristics in place to lower the probability of reallocation in cases where the double math avoidance isn't enough of a saving to absorb an allocation and memcpy. * Previously, in UTF-16 <-> UTF-8 conversions, an ASCII prefix was optimized but a single non-ASCII code point pessimized the rest of the string. The new code tries to get back on the fast ASCII path. * UTF-16 to Latin1 conversion guarantees less about handling of out-of-range input to eliminate an operation from the inner loop on x86/x86_64. * When assigning to a pre-existing string, the new code tries to reuse the old buffer instead of first releasing the old buffer and then allocating a new one. * When reallocating from the new code, the memcpy covers only the data that is part of the logical length of the old string instead of memcpying the whole capacity. (For old callers old excess memcpy behavior is preserved due to bogus callers. See bug 1472113.) * UTF-8 strings in XPConnect that are in the Latin1 range are passed to SpiderMonkey as Latin1. New features: * Conversion between UTF-8 and Latin1 is added in order to enable faster future interop between Rust code (or otherwise UTF-8-using code) and text node and SpiderMonkey code that uses Latin1. MozReview-Commit-ID: JaJuExfILM9
178 lines
4.9 KiB
C++
178 lines
4.9 KiB
C++
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
// This file is not build directly. Instead, it is included in multiple
|
|
// shared objects.
|
|
|
|
#ifdef nsWindowsRestart_cpp
|
|
#error "nsWindowsRestart.cpp is not a header file, and must only be included once."
|
|
#else
|
|
#define nsWindowsRestart_cpp
|
|
#endif
|
|
|
|
#include "mozilla/CmdLineAndEnvUtils.h"
|
|
#include "nsUTF8Utils.h"
|
|
|
|
#include <shellapi.h>
|
|
|
|
// Needed for CreateEnvironmentBlock
|
|
#include <userenv.h>
|
|
#pragma comment(lib, "userenv.lib")
|
|
|
|
/**
|
|
* Convert UTF8 to UTF16 without using the normal XPCOM goop, which we
|
|
* can't link to updater.exe.
|
|
*/
|
|
static char16_t*
|
|
AllocConvertUTF8toUTF16(const char *arg)
|
|
{
|
|
// UTF16 can't be longer in units than UTF8
|
|
size_t len = strlen(arg);
|
|
char16_t *s = new char16_t[(len + 1) * sizeof(char16_t)];
|
|
if (!s)
|
|
return nullptr;
|
|
|
|
size_t dstLen = ::MultiByteToWideChar(
|
|
CP_UTF8, 0, arg, len, reinterpret_cast<wchar_t*>(s), len);
|
|
s[dstLen] = 0;
|
|
|
|
return s;
|
|
}
|
|
|
|
static void
|
|
FreeAllocStrings(int argc, wchar_t **argv)
|
|
{
|
|
while (argc) {
|
|
--argc;
|
|
delete [] argv[argc];
|
|
}
|
|
|
|
delete [] argv;
|
|
}
|
|
|
|
static wchar_t**
|
|
AllocConvertUTF8toUTF16Strings(int argc, char **argv)
|
|
{
|
|
wchar_t **argvConverted = new wchar_t*[argc];
|
|
if (!argvConverted)
|
|
return nullptr;
|
|
|
|
for (int i = 0; i < argc; ++i) {
|
|
argvConverted[i] = reinterpret_cast<wchar_t*>(AllocConvertUTF8toUTF16(argv[i]));
|
|
if (!argvConverted[i]) {
|
|
FreeAllocStrings(i, argvConverted);
|
|
return nullptr;
|
|
}
|
|
}
|
|
return argvConverted;
|
|
}
|
|
|
|
|
|
/**
|
|
* Launch a child process with the specified arguments.
|
|
* @note argv[0] is ignored
|
|
* @note The form of this function that takes char **argv expects UTF-8
|
|
*/
|
|
|
|
BOOL
|
|
WinLaunchChild(const wchar_t *exePath,
|
|
int argc, wchar_t **argv,
|
|
HANDLE userToken = nullptr,
|
|
HANDLE *hProcess = nullptr);
|
|
|
|
BOOL
|
|
WinLaunchChild(const wchar_t *exePath,
|
|
int argc, char **argv,
|
|
HANDLE userToken,
|
|
HANDLE *hProcess)
|
|
{
|
|
wchar_t **argvConverted = AllocConvertUTF8toUTF16Strings(argc, argv);
|
|
if (!argvConverted)
|
|
return FALSE;
|
|
|
|
BOOL ok = WinLaunchChild(exePath, argc, argvConverted, userToken, hProcess);
|
|
FreeAllocStrings(argc, argvConverted);
|
|
return ok;
|
|
}
|
|
|
|
BOOL
|
|
WinLaunchChild(const wchar_t *exePath,
|
|
int argc,
|
|
wchar_t **argv,
|
|
HANDLE userToken,
|
|
HANDLE *hProcess)
|
|
{
|
|
BOOL ok;
|
|
|
|
mozilla::UniquePtr<wchar_t[]> cl(mozilla::MakeCommandLine(argc, argv));
|
|
if (!cl) {
|
|
return FALSE;
|
|
}
|
|
|
|
STARTUPINFOW si = {0};
|
|
si.cb = sizeof(STARTUPINFOW);
|
|
si.lpDesktop = L"winsta0\\Default";
|
|
PROCESS_INFORMATION pi = {0};
|
|
|
|
if (userToken == nullptr) {
|
|
ok = CreateProcessW(exePath,
|
|
cl.get(),
|
|
nullptr, // no special security attributes
|
|
nullptr, // no special thread attributes
|
|
FALSE, // don't inherit filehandles
|
|
0, // creation flags
|
|
nullptr, // inherit my environment
|
|
nullptr, // use my current directory
|
|
&si,
|
|
&pi);
|
|
} else {
|
|
// Create an environment block for the process we're about to start using
|
|
// the user's token.
|
|
LPVOID environmentBlock = nullptr;
|
|
if (!CreateEnvironmentBlock(&environmentBlock, userToken, TRUE)) {
|
|
environmentBlock = nullptr;
|
|
}
|
|
|
|
ok = CreateProcessAsUserW(userToken,
|
|
exePath,
|
|
cl.get(),
|
|
nullptr, // no special security attributes
|
|
nullptr, // no special thread attributes
|
|
FALSE, // don't inherit filehandles
|
|
0, // creation flags
|
|
environmentBlock,
|
|
nullptr, // use my current directory
|
|
&si,
|
|
&pi);
|
|
|
|
if (environmentBlock) {
|
|
DestroyEnvironmentBlock(environmentBlock);
|
|
}
|
|
}
|
|
|
|
if (ok) {
|
|
if (hProcess) {
|
|
*hProcess = pi.hProcess; // the caller now owns the HANDLE
|
|
} else {
|
|
CloseHandle(pi.hProcess);
|
|
}
|
|
CloseHandle(pi.hThread);
|
|
} else {
|
|
LPVOID lpMsgBuf = nullptr;
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
nullptr,
|
|
GetLastError(),
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR) &lpMsgBuf,
|
|
0,
|
|
nullptr);
|
|
wprintf(L"Error restarting: %s\n", lpMsgBuf ? static_cast<const wchar_t*>(lpMsgBuf) : L"(null)");
|
|
if (lpMsgBuf)
|
|
LocalFree(lpMsgBuf);
|
|
}
|
|
|
|
return ok;
|
|
}
|