summaryrefslogtreecommitdiffstats
path: root/toolkit/modules/subprocess/subprocess_shared_win.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/modules/subprocess/subprocess_shared_win.js')
-rw-r--r--toolkit/modules/subprocess/subprocess_shared_win.js538
1 files changed, 538 insertions, 0 deletions
diff --git a/toolkit/modules/subprocess/subprocess_shared_win.js b/toolkit/modules/subprocess/subprocess_shared_win.js
new file mode 100644
index 0000000000..2b9eb69c6d
--- /dev/null
+++ b/toolkit/modules/subprocess/subprocess_shared_win.js
@@ -0,0 +1,538 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+/* 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/. */
+"use strict";
+
+if (typeof Components !== "undefined") {
+ /* global OS */
+ Cc["@mozilla.org/net/osfileconstantsservice;1"]
+ .getService(Ci.nsIOSFileConstantsService)
+ .init();
+}
+
+/* exported LIBC, Win, createPipe, libc, win32 */
+
+// ctypes is either already available in the chrome worker scope, or defined
+// in scope via loadSubScript.
+/* global ctypes */
+
+// This file is loaded into the same scope as subprocess_shared.js.
+/* import-globals-from subprocess_shared.js */
+
+const LIBC = OS.Constants.libc;
+
+const Win = OS.Constants.Win;
+
+const LIBC_CHOICES = ["kernel32.dll"];
+
+var win32 = {
+ // On Windows 64, winapi_abi is an alias for default_abi.
+ WINAPI: ctypes.winapi_abi,
+
+ VOID: ctypes.void_t,
+
+ BYTE: ctypes.uint8_t,
+ WORD: ctypes.uint16_t,
+ DWORD: ctypes.uint32_t,
+ LONG: ctypes.long,
+ LARGE_INTEGER: ctypes.int64_t,
+ ULONGLONG: ctypes.uint64_t,
+
+ UINT: ctypes.unsigned_int,
+ UCHAR: ctypes.unsigned_char,
+
+ BOOL: ctypes.bool,
+
+ HANDLE: ctypes.voidptr_t,
+ PVOID: ctypes.voidptr_t,
+ LPVOID: ctypes.voidptr_t,
+
+ CHAR: ctypes.char,
+ WCHAR: ctypes.jschar,
+
+ ULONG_PTR: ctypes.uintptr_t,
+
+ SIZE_T: ctypes.size_t,
+ PSIZE_T: ctypes.size_t.ptr,
+};
+
+Object.assign(win32, {
+ DWORD_PTR: win32.ULONG_PTR,
+
+ LPSTR: win32.CHAR.ptr,
+ LPWSTR: win32.WCHAR.ptr,
+
+ LPBYTE: win32.BYTE.ptr,
+ LPDWORD: win32.DWORD.ptr,
+ LPHANDLE: win32.HANDLE.ptr,
+
+ // This is an opaque type.
+ PROC_THREAD_ATTRIBUTE_LIST: ctypes.char.array(),
+ LPPROC_THREAD_ATTRIBUTE_LIST: ctypes.char.ptr,
+});
+
+Object.assign(win32, {
+ LPCSTR: win32.LPSTR,
+ LPCWSTR: win32.LPWSTR,
+ LPCVOID: win32.LPVOID,
+});
+
+Object.assign(win32, {
+ INVALID_HANDLE_VALUE: ctypes.cast(ctypes.int64_t(-1), win32.HANDLE),
+ NULL_HANDLE_VALUE: ctypes.cast(ctypes.uintptr_t(0), win32.HANDLE),
+
+ CREATE_SUSPENDED: 0x00000004,
+ CREATE_NEW_CONSOLE: 0x00000010,
+ CREATE_UNICODE_ENVIRONMENT: 0x00000400,
+ CREATE_NO_WINDOW: 0x08000000,
+ CREATE_BREAKAWAY_FROM_JOB: 0x01000000,
+ EXTENDED_STARTUPINFO_PRESENT: 0x00080000,
+
+ STARTF_USESTDHANDLES: 0x0100,
+
+ DUPLICATE_CLOSE_SOURCE: 0x01,
+ DUPLICATE_SAME_ACCESS: 0x02,
+
+ ERROR_HANDLE_EOF: 38,
+ ERROR_BROKEN_PIPE: 109,
+ ERROR_INSUFFICIENT_BUFFER: 122,
+
+ FILE_FLAG_OVERLAPPED: 0x40000000,
+
+ PIPE_TYPE_BYTE: 0x00,
+
+ PIPE_ACCESS_INBOUND: 0x01,
+ PIPE_ACCESS_OUTBOUND: 0x02,
+ PIPE_ACCESS_DUPLEX: 0x03,
+
+ PIPE_WAIT: 0x00,
+ PIPE_NOWAIT: 0x01,
+
+ STILL_ACTIVE: 259,
+
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST: 0x00020002,
+
+ JobObjectBasicLimitInformation: 2,
+ JobObjectExtendedLimitInformation: 9,
+
+ JOB_OBJECT_LIMIT_BREAKAWAY_OK: 0x00000800,
+
+ // These constants are 32-bit unsigned integers, but Windows defines
+ // them as negative integers cast to an unsigned type.
+ STD_INPUT_HANDLE: -10 + 0x100000000,
+ STD_OUTPUT_HANDLE: -11 + 0x100000000,
+ STD_ERROR_HANDLE: -12 + 0x100000000,
+
+ WAIT_TIMEOUT: 0x00000102,
+ WAIT_FAILED: 0xffffffff,
+});
+
+Object.assign(win32, {
+ JOBOBJECT_BASIC_LIMIT_INFORMATION: new ctypes.StructType(
+ "JOBOBJECT_BASIC_LIMIT_INFORMATION",
+ [
+ { PerProcessUserTimeLimit: win32.LARGE_INTEGER },
+ { PerJobUserTimeLimit: win32.LARGE_INTEGER },
+ { LimitFlags: win32.DWORD },
+ { MinimumWorkingSetSize: win32.SIZE_T },
+ { MaximumWorkingSetSize: win32.SIZE_T },
+ { ActiveProcessLimit: win32.DWORD },
+ { Affinity: win32.ULONG_PTR },
+ { PriorityClass: win32.DWORD },
+ { SchedulingClass: win32.DWORD },
+ ]
+ ),
+
+ IO_COUNTERS: new ctypes.StructType("IO_COUNTERS", [
+ { ReadOperationCount: win32.ULONGLONG },
+ { WriteOperationCount: win32.ULONGLONG },
+ { OtherOperationCount: win32.ULONGLONG },
+ { ReadTransferCount: win32.ULONGLONG },
+ { WriteTransferCount: win32.ULONGLONG },
+ { OtherTransferCount: win32.ULONGLONG },
+ ]),
+});
+
+Object.assign(win32, {
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION: new ctypes.StructType(
+ "JOBOBJECT_EXTENDED_LIMIT_INFORMATION",
+ [
+ { BasicLimitInformation: win32.JOBOBJECT_BASIC_LIMIT_INFORMATION },
+ { IoInfo: win32.IO_COUNTERS },
+ { ProcessMemoryLimit: win32.SIZE_T },
+ { JobMemoryLimit: win32.SIZE_T },
+ { PeakProcessMemoryUsed: win32.SIZE_T },
+ { PeakJobMemoryUsed: win32.SIZE_T },
+ ]
+ ),
+
+ OVERLAPPED: new ctypes.StructType("OVERLAPPED", [
+ { Internal: win32.ULONG_PTR },
+ { InternalHigh: win32.ULONG_PTR },
+ { Offset: win32.DWORD },
+ { OffsetHigh: win32.DWORD },
+ { hEvent: win32.HANDLE },
+ ]),
+
+ PROCESS_INFORMATION: new ctypes.StructType("PROCESS_INFORMATION", [
+ { hProcess: win32.HANDLE },
+ { hThread: win32.HANDLE },
+ { dwProcessId: win32.DWORD },
+ { dwThreadId: win32.DWORD },
+ ]),
+
+ SECURITY_ATTRIBUTES: new ctypes.StructType("SECURITY_ATTRIBUTES", [
+ { nLength: win32.DWORD },
+ { lpSecurityDescriptor: win32.LPVOID },
+ { bInheritHandle: win32.BOOL },
+ ]),
+
+ STARTUPINFOW: new ctypes.StructType("STARTUPINFOW", [
+ { cb: win32.DWORD },
+ { lpReserved: win32.LPWSTR },
+ { lpDesktop: win32.LPWSTR },
+ { lpTitle: win32.LPWSTR },
+ { dwX: win32.DWORD },
+ { dwY: win32.DWORD },
+ { dwXSize: win32.DWORD },
+ { dwYSize: win32.DWORD },
+ { dwXCountChars: win32.DWORD },
+ { dwYCountChars: win32.DWORD },
+ { dwFillAttribute: win32.DWORD },
+ { dwFlags: win32.DWORD },
+ { wShowWindow: win32.WORD },
+ { cbReserved2: win32.WORD },
+ { lpReserved2: win32.LPBYTE },
+ { hStdInput: win32.HANDLE },
+ { hStdOutput: win32.HANDLE },
+ { hStdError: win32.HANDLE },
+ ]),
+});
+
+Object.assign(win32, {
+ STARTUPINFOEXW: new ctypes.StructType("STARTUPINFOEXW", [
+ { StartupInfo: win32.STARTUPINFOW },
+ { lpAttributeList: win32.LPPROC_THREAD_ATTRIBUTE_LIST },
+ ]),
+});
+
+var libc = new Library("libc", LIBC_CHOICES, {
+ AssignProcessToJobObject: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.HANDLE /* hJob */,
+ win32.HANDLE /* hProcess */,
+ ],
+
+ CloseHandle: [win32.WINAPI, win32.BOOL, win32.HANDLE /* hObject */],
+
+ CreateEventW: [
+ win32.WINAPI,
+ win32.HANDLE,
+ win32.SECURITY_ATTRIBUTES.ptr /* opt lpEventAttributes */,
+ win32.BOOL /* bManualReset */,
+ win32.BOOL /* bInitialState */,
+ win32.LPWSTR /* lpName */,
+ ],
+
+ CreateFileW: [
+ win32.WINAPI,
+ win32.HANDLE,
+ win32.LPWSTR /* lpFileName */,
+ win32.DWORD /* dwDesiredAccess */,
+ win32.DWORD /* dwShareMode */,
+ win32.SECURITY_ATTRIBUTES.ptr /* opt lpSecurityAttributes */,
+ win32.DWORD /* dwCreationDisposition */,
+ win32.DWORD /* dwFlagsAndAttributes */,
+ win32.HANDLE /* opt hTemplateFile */,
+ ],
+
+ CreateJobObjectW: [
+ win32.WINAPI,
+ win32.HANDLE,
+ win32.SECURITY_ATTRIBUTES.ptr /* opt lpJobAttributes */,
+ win32.LPWSTR /* lpName */,
+ ],
+
+ CreateNamedPipeW: [
+ win32.WINAPI,
+ win32.HANDLE,
+ win32.LPWSTR /* lpName */,
+ win32.DWORD /* dwOpenMode */,
+ win32.DWORD /* dwPipeMode */,
+ win32.DWORD /* nMaxInstances */,
+ win32.DWORD /* nOutBufferSize */,
+ win32.DWORD /* nInBufferSize */,
+ win32.DWORD /* nDefaultTimeOut */,
+ win32.SECURITY_ATTRIBUTES.ptr /* opt lpSecurityAttributes */,
+ ],
+
+ CreatePipe: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.LPHANDLE /* out hReadPipe */,
+ win32.LPHANDLE /* out hWritePipe */,
+ win32.SECURITY_ATTRIBUTES.ptr /* opt lpPipeAttributes */,
+ win32.DWORD /* nSize */,
+ ],
+
+ CreateProcessW: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.LPCWSTR /* lpApplicationName */,
+ win32.LPWSTR /* lpCommandLine */,
+ win32.SECURITY_ATTRIBUTES.ptr /* lpProcessAttributes */,
+ win32.SECURITY_ATTRIBUTES.ptr /* lpThreadAttributes */,
+ win32.BOOL /* bInheritHandle */,
+ win32.DWORD /* dwCreationFlags */,
+ win32.LPVOID /* opt lpEnvironment */,
+ win32.LPCWSTR /* opt lpCurrentDirectory */,
+ win32.STARTUPINFOW.ptr /* lpStartupInfo */,
+ win32.PROCESS_INFORMATION.ptr /* out lpProcessInformation */,
+ ],
+
+ CreateSemaphoreW: [
+ win32.WINAPI,
+ win32.HANDLE,
+ win32.SECURITY_ATTRIBUTES.ptr /* opt lpSemaphoreAttributes */,
+ win32.LONG /* lInitialCount */,
+ win32.LONG /* lMaximumCount */,
+ win32.LPCWSTR /* opt lpName */,
+ ],
+
+ DeleteProcThreadAttributeList: [
+ win32.WINAPI,
+ win32.VOID,
+ win32.LPPROC_THREAD_ATTRIBUTE_LIST /* in/out lpAttributeList */,
+ ],
+
+ DuplicateHandle: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.HANDLE /* hSourceProcessHandle */,
+ win32.HANDLE /* hSourceHandle */,
+ win32.HANDLE /* hTargetProcessHandle */,
+ win32.LPHANDLE /* out lpTargetHandle */,
+ win32.DWORD /* dwDesiredAccess */,
+ win32.BOOL /* bInheritHandle */,
+ win32.DWORD /* dwOptions */,
+ ],
+
+ FreeEnvironmentStringsW: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.LPCWSTR /* lpszEnvironmentBlock */,
+ ],
+
+ GetCurrentProcess: [win32.WINAPI, win32.HANDLE],
+
+ GetCurrentProcessId: [win32.WINAPI, win32.DWORD],
+
+ GetEnvironmentStringsW: [win32.WINAPI, win32.LPCWSTR],
+
+ GetExitCodeProcess: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.HANDLE /* hProcess */,
+ win32.LPDWORD /* lpExitCode */,
+ ],
+
+ GetOverlappedResult: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.HANDLE /* hFile */,
+ win32.OVERLAPPED.ptr /* lpOverlapped */,
+ win32.LPDWORD /* lpNumberOfBytesTransferred */,
+ win32.BOOL /* bWait */,
+ ],
+
+ GetStdHandle: [win32.WINAPI, win32.HANDLE, win32.DWORD /* nStdHandle */],
+
+ InitializeProcThreadAttributeList: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.LPPROC_THREAD_ATTRIBUTE_LIST /* out opt lpAttributeList */,
+ win32.DWORD /* dwAttributeCount */,
+ win32.DWORD /* dwFlags */,
+ win32.PSIZE_T /* in/out lpSize */,
+ ],
+
+ ReadFile: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.HANDLE /* hFile */,
+ win32.LPVOID /* out lpBuffer */,
+ win32.DWORD /* nNumberOfBytesToRead */,
+ win32.LPDWORD /* opt out lpNumberOfBytesRead */,
+ win32.OVERLAPPED.ptr /* opt in/out lpOverlapped */,
+ ],
+
+ ReleaseSemaphore: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.HANDLE /* hSemaphore */,
+ win32.LONG /* lReleaseCount */,
+ win32.LONG.ptr /* opt out lpPreviousCount */,
+ ],
+
+ ResumeThread: [win32.WINAPI, win32.DWORD, win32.HANDLE /* hThread */],
+
+ SetInformationJobObject: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.HANDLE /* hJob */,
+ ctypes.int /* JobObjectInfoClass */,
+ win32.LPVOID /* lpJobObjectInfo */,
+ win32.DWORD /* cbJobObjectInfoLengt */,
+ ],
+
+ TerminateJobObject: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.HANDLE /* hJob */,
+ win32.UINT /* uExitCode */,
+ ],
+
+ TerminateProcess: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.HANDLE /* hProcess */,
+ win32.UINT /* uExitCode */,
+ ],
+
+ UpdateProcThreadAttribute: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.LPPROC_THREAD_ATTRIBUTE_LIST /* in/out lpAttributeList */,
+ win32.DWORD /* dwFlags */,
+ win32.DWORD_PTR /* Attribute */,
+ win32.PVOID /* lpValue */,
+ win32.SIZE_T /* cbSize */,
+ win32.PVOID /* out opt lpPreviousValue */,
+ win32.PSIZE_T /* opt lpReturnSize */,
+ ],
+
+ WaitForMultipleObjects: [
+ win32.WINAPI,
+ win32.DWORD,
+ win32.DWORD /* nCount */,
+ win32.HANDLE.ptr /* hHandles */,
+ win32.BOOL /* bWaitAll */,
+ win32.DWORD /* dwMilliseconds */,
+ ],
+
+ WaitForSingleObject: [
+ win32.WINAPI,
+ win32.DWORD,
+ win32.HANDLE /* hHandle */,
+ win32.BOOL /* bWaitAll */,
+ win32.DWORD /* dwMilliseconds */,
+ ],
+
+ WriteFile: [
+ win32.WINAPI,
+ win32.BOOL,
+ win32.HANDLE /* hFile */,
+ win32.LPCVOID /* lpBuffer */,
+ win32.DWORD /* nNumberOfBytesToRead */,
+ win32.LPDWORD /* opt out lpNumberOfBytesWritten */,
+ win32.OVERLAPPED.ptr /* opt in/out lpOverlapped */,
+ ],
+});
+
+let nextNamedPipeId = 0;
+
+win32.Handle = function (handle) {
+ return ctypes.CDataFinalizer(win32.HANDLE(handle), libc.CloseHandle);
+};
+
+win32.createPipe = function (secAttr, readFlags = 0, writeFlags = 0, size = 0) {
+ readFlags |= win32.PIPE_ACCESS_INBOUND;
+ writeFlags |= Win.FILE_ATTRIBUTE_NORMAL;
+
+ if (size == 0) {
+ size = 4096;
+ }
+
+ let pid = libc.GetCurrentProcessId();
+ let pipeName = String.raw`\\.\Pipe\SubProcessPipe.${pid}.${nextNamedPipeId++}`;
+
+ let readHandle = libc.CreateNamedPipeW(
+ pipeName,
+ readFlags,
+ win32.PIPE_TYPE_BYTE | win32.PIPE_WAIT,
+ 1 /* number of connections */,
+ size /* output buffer size */,
+ size /* input buffer size */,
+ 0 /* timeout */,
+ secAttr.address()
+ );
+
+ let isInvalid = handle =>
+ String(handle) == String(win32.HANDLE(Win.INVALID_HANDLE_VALUE));
+
+ if (isInvalid(readHandle)) {
+ return [];
+ }
+
+ let writeHandle = libc.CreateFileW(
+ pipeName,
+ Win.GENERIC_WRITE,
+ 0,
+ secAttr.address(),
+ Win.OPEN_EXISTING,
+ writeFlags,
+ null
+ );
+
+ if (isInvalid(writeHandle)) {
+ libc.CloseHandle(readHandle);
+ return [];
+ }
+
+ return [win32.Handle(readHandle), win32.Handle(writeHandle)];
+};
+
+win32.createThreadAttributeList = function (handles) {
+ try {
+ void libc.InitializeProcThreadAttributeList;
+ void libc.DeleteProcThreadAttributeList;
+ void libc.UpdateProcThreadAttribute;
+ } catch (e) {
+ // This is only supported in Windows Vista and later.
+ return null;
+ }
+
+ let size = win32.SIZE_T();
+ if (
+ !libc.InitializeProcThreadAttributeList(null, 1, 0, size.address()) &&
+ ctypes.winLastError != win32.ERROR_INSUFFICIENT_BUFFER
+ ) {
+ return null;
+ }
+
+ let attrList = win32.PROC_THREAD_ATTRIBUTE_LIST(size.value);
+
+ if (!libc.InitializeProcThreadAttributeList(attrList, 1, 0, size.address())) {
+ return null;
+ }
+
+ let ok = libc.UpdateProcThreadAttribute(
+ attrList,
+ 0,
+ win32.PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+ handles,
+ handles.constructor.size,
+ null,
+ null
+ );
+
+ if (!ok) {
+ libc.DeleteProcThreadAttributeList(attrList);
+ return null;
+ }
+
+ return attrList;
+};