summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml28
-rw-r--r--cli/main.rs5
-rw-r--r--cli/windows_util.rs89
-rw-r--r--runtime/ops/io.rs107
4 files changed, 134 insertions, 95 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ae75f9b6e..3abdbfc90 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -84,7 +84,7 @@ jobs:
- name: Install Rust
uses: hecrj/setup-rust-action@v1
with:
- rust-version: 1.55.0
+ rust-version: 1.56.0
- name: Install clippy and rustfmt
if: matrix.job == 'lint'
@@ -184,15 +184,20 @@ jobs:
sudo ln --force --target /sysroot/etc \
/etc/passwd /etc/shadow /etc/group /etc/gshadow
- # Install clang-12 and lld-12 into the chroot environment.
- echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-12 main" |
- sudo dd of=/sysroot/etc/apt/sources.list.d/llvm-toolchain-bionic-12.list
+ # Install clang-13 and lld-13 into the chroot environment.
+ echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-13 main" |
+ sudo dd of=/sysroot/etc/apt/sources.list.d/llvm-toolchain-bionic-13.list
curl https://apt.llvm.org/llvm-snapshot.gpg.key |
gpg --dearmor |
sudo dd of=/sysroot/etc/apt/trusted.gpg.d/llvm-snapshot.gpg
sudo chroot /sysroot apt update -y
sudo chroot /sysroot apt install --no-install-recommends -y \
- clang-12 lld-12
+ clang-13 lld-13
+
+ # Redirect ld invocations to ld.lld-13 inside the chroot environment.
+ # Setting the 'LD' environment variable doesn't always work.
+ sudo chroot /sysroot bash -c \
+ 'ln -f "$(which ld.lld-13)" "$(which ld)"'
# Make rust available inside the chroot environment.
sudo mkdir -p /sysroot/usr/share/rust
@@ -221,8 +226,8 @@ jobs:
export CARGO_PROFILE_RELEASE_LTO=false
export RUSTFLAGS="
-C linker-plugin-lto=true
- -C linker=clang-12
- -C link-arg=-fuse-ld=lld-12
+ -C linker=clang-13
+ -C link-arg=-fuse-ld=lld-13
-C link-arg=-Wl,--thinlto-cache-dir=$(pwd)/target/release/lto-cache
-C link-arg=-Wl,--thinlto-cache-policy,cache_size_bytes=700m
-D warnings
@@ -231,8 +236,9 @@ jobs:
unset RUSTC_FORCE_INCREMENTAL
# C build configuration.
- export CC=clang-12 # Compile c source files with clang.
+ export CC=clang-13 # Compile c source files with clang.
export CFLAGS=-flto=thin # Tell clang to produce llvm bitcode.
+ export LD=ld.lld-13 # Use the lld linker.
# Miscellaneous flags.
export CARGO_TERM_COLOR=always
@@ -260,7 +266,7 @@ jobs:
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
- key: l-cargo-home-${{ matrix.os }}-${{ hashFiles('Cargo.lock') }}
+ key: 0-cargo-home-${{ matrix.os }}-${{ hashFiles('Cargo.lock') }}
# In main branch, always creates fresh cache
- name: Cache build output (main)
@@ -276,7 +282,7 @@ jobs:
!./target/*/*.zip
!./target/*/*.tar.gz
key: |
- l-cargo-target-${{ matrix.os }}-${{ matrix.profile }}-${{ github.sha }}
+ 0-cargo-target-${{ matrix.os }}-${{ matrix.profile }}-${{ github.sha }}
# Restore cache from the latest 'main' branch build.
- name: Cache build output (PR)
@@ -292,7 +298,7 @@ jobs:
!./target/*/*.tar.gz
key: never_saved
restore-keys: |
- l-cargo-target-${{ matrix.os }}-${{ matrix.profile }}-
+ 0-cargo-target-${{ matrix.os }}-${{ matrix.profile }}-
# Don't save cache after building PRs or branches other than 'main'.
- name: Skip save cache (PR)
diff --git a/cli/main.rs b/cli/main.rs
index d36145bea..f4d4046df 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -35,6 +35,7 @@ mod tools;
mod tsc;
mod unix_util;
mod version;
+mod windows_util;
use crate::file_fetcher::File;
use crate::file_watcher::ResolutionResult;
@@ -1364,9 +1365,11 @@ fn unwrap_or_exit<T>(result: Result<T, AnyError>) -> T {
pub fn main() {
setup_exit_process_panic_hook();
+
+ unix_util::raise_fd_limit();
+ windows_util::ensure_stdio_open();
#[cfg(windows)]
colors::enable_ansi(); // For Windows 10
- unix_util::raise_fd_limit();
let args: Vec<String> = env::args().collect();
let standalone_res = match standalone::extract_standalone(args.clone()) {
diff --git a/cli/windows_util.rs b/cli/windows_util.rs
new file mode 100644
index 000000000..0f30bb04c
--- /dev/null
+++ b/cli/windows_util.rs
@@ -0,0 +1,89 @@
+// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+
+/// Ensures that stdin, stdout, and stderr are open and have valid HANDLEs
+/// associated with them. There are many places where a `std::fs::File` is
+/// constructed from a stdio handle; if the handle is null this causes a panic.
+pub fn ensure_stdio_open() {
+ #[cfg(windows)]
+ unsafe {
+ use std::mem::size_of;
+ use winapi::shared::minwindef::DWORD;
+ use winapi::shared::minwindef::FALSE;
+ use winapi::shared::minwindef::TRUE;
+ use winapi::shared::ntdef::NULL;
+ use winapi::shared::winerror::ERROR_INVALID_HANDLE;
+ use winapi::um::errhandlingapi::GetLastError;
+ use winapi::um::fileapi::CreateFileA;
+ use winapi::um::fileapi::OPEN_EXISTING;
+ use winapi::um::handleapi::GetHandleInformation;
+ use winapi::um::handleapi::INVALID_HANDLE_VALUE;
+ use winapi::um::minwinbase::SECURITY_ATTRIBUTES;
+ use winapi::um::processenv::GetStdHandle;
+ use winapi::um::processenv::SetStdHandle;
+ use winapi::um::winbase::STD_ERROR_HANDLE;
+ use winapi::um::winbase::STD_INPUT_HANDLE;
+ use winapi::um::winbase::STD_OUTPUT_HANDLE;
+ use winapi::um::winnt::FILE_ATTRIBUTE_NORMAL;
+ use winapi::um::winnt::FILE_GENERIC_READ;
+ use winapi::um::winnt::FILE_GENERIC_WRITE;
+ use winapi::um::winnt::FILE_READ_ATTRIBUTES;
+ use winapi::um::winnt::FILE_SHARE_READ;
+ use winapi::um::winnt::FILE_SHARE_WRITE;
+
+ for std_handle in [STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE] {
+ // Check whether stdio handle is open.
+ let is_valid = match GetStdHandle(std_handle) {
+ NULL | INVALID_HANDLE_VALUE => false,
+ handle => {
+ // The stdio handle is open; check whether its handle is valid.
+ let mut flags: DWORD = 0;
+ match GetHandleInformation(handle, &mut flags) {
+ TRUE => true,
+ FALSE if GetLastError() == ERROR_INVALID_HANDLE => false,
+ FALSE => {
+ panic!("GetHandleInformation failed (error {})", GetLastError());
+ }
+ _ => unreachable!(),
+ }
+ }
+ };
+
+ if !is_valid {
+ // Open NUL device.
+ let desired_access = match std_handle {
+ STD_INPUT_HANDLE => FILE_GENERIC_READ,
+ _ => FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES,
+ };
+ let security_attributes = SECURITY_ATTRIBUTES {
+ nLength: size_of::<SECURITY_ATTRIBUTES>() as DWORD,
+ lpSecurityDescriptor: NULL,
+ bInheritHandle: TRUE,
+ };
+ let file_handle = CreateFileA(
+ b"\\\\?\\NUL\0" as *const _ as *mut _,
+ desired_access,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &security_attributes as *const _ as *mut _,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL,
+ );
+ match file_handle {
+ NULL => unreachable!(),
+ INVALID_HANDLE_VALUE => {
+ panic!("Could not open NUL device (error {})", GetLastError());
+ }
+ _ => {}
+ }
+
+ // Assign the opened NUL handle to the missing stdio handle.
+ let success = SetStdHandle(std_handle, file_handle);
+ match success {
+ TRUE => {}
+ FALSE => panic!("SetStdHandle failed (error {})", GetLastError()),
+ _ => unreachable!(),
+ }
+ }
+ }
+ }
+}
diff --git a/runtime/ops/io.rs b/runtime/ops/io.rs
index 7eb27bd12..5b98cd725 100644
--- a/runtime/ops/io.rs
+++ b/runtime/ops/io.rs
@@ -20,6 +20,7 @@ use deno_net::io::UnixStreamResource;
use deno_net::ops_tls::TlsStreamResource;
use std::borrow::Cow;
use std::cell::RefCell;
+use std::fs::File as StdFile;
use std::io::Read;
use std::io::Write;
use std::rc::Rc;
@@ -33,8 +34,19 @@ use tokio::process;
use std::os::unix::io::FromRawFd;
#[cfg(windows)]
-use std::os::windows::io::FromRawHandle;
+use {
+ std::os::windows::io::FromRawHandle,
+ winapi::um::{processenv::GetStdHandle, winbase},
+};
+#[cfg(unix)]
+lazy_static::lazy_static! {
+ static ref STDIN_HANDLE: StdFile = unsafe { StdFile::from_raw_fd(0) };
+ static ref STDOUT_HANDLE: StdFile = unsafe { StdFile::from_raw_fd(1) };
+ static ref STDERR_HANDLE: StdFile = unsafe { StdFile::from_raw_fd(2) };
+}
+
+#[cfg(windows)]
lazy_static::lazy_static! {
/// Due to portability issues on Windows handle to stdout is created from raw
/// file descriptor. The caveat of that approach is fact that when this
@@ -44,50 +56,14 @@ lazy_static::lazy_static! {
/// resource table is dropped storing reference to that handle, the handle
/// itself won't be closed (so Deno.core.print) will still work.
// TODO(ry) It should be possible to close stdout.
- static ref STDIN_HANDLE: Option<std::fs::File> = {
- #[cfg(not(windows))]
- let stdin = unsafe { Some(std::fs::File::from_raw_fd(0)) };
- #[cfg(windows)]
- let stdin = unsafe {
- let handle = winapi::um::processenv::GetStdHandle(
- winapi::um::winbase::STD_INPUT_HANDLE,
- );
- if handle.is_null() {
- return None;
- }
- Some(std::fs::File::from_raw_handle(handle))
- };
- stdin
+ static ref STDIN_HANDLE: StdFile = unsafe {
+ StdFile::from_raw_handle(GetStdHandle(winbase::STD_INPUT_HANDLE))
};
- static ref STDOUT_HANDLE: Option<std::fs::File> = {
- #[cfg(not(windows))]
- let stdout = unsafe { Some(std::fs::File::from_raw_fd(1)) };
- #[cfg(windows)]
- let stdout = unsafe {
- let handle = winapi::um::processenv::GetStdHandle(
- winapi::um::winbase::STD_OUTPUT_HANDLE,
- );
- if handle.is_null() {
- return None;
- }
- Some(std::fs::File::from_raw_handle(handle))
- };
- stdout
+ static ref STDOUT_HANDLE: StdFile = unsafe {
+ StdFile::from_raw_handle(GetStdHandle(winbase::STD_OUTPUT_HANDLE))
};
- static ref STDERR_HANDLE: Option<std::fs::File> = {
- #[cfg(not(windows))]
- let stderr = unsafe { Some(std::fs::File::from_raw_fd(2)) };
- #[cfg(windows)]
- let stderr = unsafe {
- let handle = winapi::um::processenv::GetStdHandle(
- winapi::um::winbase::STD_ERROR_HANDLE,
- );
- if handle.is_null() {
- return None;
- }
- Some(std::fs::File::from_raw_handle(handle))
- };
- stderr
+ static ref STDERR_HANDLE: StdFile = unsafe {
+ StdFile::from_raw_handle(GetStdHandle(winbase::STD_ERROR_HANDLE))
};
}
@@ -107,49 +83,14 @@ pub fn init_stdio() -> Extension {
Extension::builder()
.state(|state| {
let t = &mut state.resource_table;
- let (stdin, stdout, stderr) = get_stdio();
- if let Some(stream) = stdin {
- t.add(stream);
- }
- if let Some(stream) = stdout {
- t.add(stream);
- }
- if let Some(stream) = stderr {
- t.add(stream);
- }
+ t.add(StdFileResource::stdio(&STDIN_HANDLE, "stdin"));
+ t.add(StdFileResource::stdio(&STDOUT_HANDLE, "stdout"));
+ t.add(StdFileResource::stdio(&STDERR_HANDLE, "stderr"));
Ok(())
})
.build()
}
-pub fn get_stdio() -> (
- Option<StdFileResource>,
- Option<StdFileResource>,
- Option<StdFileResource>,
-) {
- let stdin = get_stdio_stream(&STDIN_HANDLE, "stdin");
- let stdout = get_stdio_stream(&STDOUT_HANDLE, "stdout");
- let stderr = get_stdio_stream(&STDERR_HANDLE, "stderr");
-
- (stdin, stdout, stderr)
-}
-
-fn get_stdio_stream(
- handle: &Option<std::fs::File>,
- name: &str,
-) -> Option<StdFileResource> {
- match handle {
- None => None,
- Some(file_handle) => match file_handle.try_clone() {
- Ok(clone) => {
- let tokio_file = tokio::fs::File::from_std(clone);
- Some(StdFileResource::stdio(tokio_file, name))
- }
- Err(_e) => None,
- },
- }
-}
-
#[cfg(unix)]
use nix::sys::termios;
@@ -277,10 +218,10 @@ pub struct StdFileResource {
}
impl StdFileResource {
- pub fn stdio(fs_file: tokio::fs::File, name: &str) -> Self {
+ pub fn stdio(std_file: &StdFile, name: &str) -> Self {
Self {
fs_file: Some(AsyncRefCell::new((
- Some(fs_file),
+ std_file.try_clone().map(tokio::fs::File::from_std).ok(),
Some(FileMetadata::default()),
))),
name: name.to_string(),