Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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";
/* exported 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_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_ATTRIBUTE_NORMAL: 0x00000080,
FILE_FLAG_OVERLAPPED: 0x40000000,
GENERIC_WRITE: 0x40000000,
OPEN_EXISTING: 0x00000003,
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 |= win32.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.INVALID_HANDLE_VALUE);
if (isInvalid(readHandle)) {
return [];
}
let writeHandle = libc.CreateFileW(
pipeName,
win32.GENERIC_WRITE,
0,
secAttr.address(),
win32.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;
};