/* -*- 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;
};