Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8c92044
On-demandify the typechecking of item bodies
cramertj Mar 15, 2017
5ca8a73
std: Don't cache stdio handles on Windows
alexcrichton Mar 14, 2017
c2b44a3
rustbuild: Update bootstrap compiler
alexcrichton Mar 14, 2017
1a87fc2
convert `custom_coerce_unsized_kind` into a `coerce_unsized_info`
nikomatsakis Mar 17, 2017
8e6b10a
move `check` to the top of the file, where I would expect to find it
nikomatsakis Mar 20, 2017
8ffe406
keep the AST node-id when lowering ExprKind::Range
arielb1 Mar 23, 2017
a29ae30
convert inherent-impl-related things to on-demand queries
nikomatsakis Mar 20, 2017
e341d60
Remove internal liblog
alexcrichton Feb 15, 2017
b470354
Update cargo submodule
alexcrichton Mar 23, 2017
8fba638
Rewrite `io::BufRead` doc examples to better demonstrate behaviors.
frewsxcv Mar 18, 2017
64e9af4
Allow declarative macros 2.0 and `use` macro imports to shadow builti…
jseyfried Mar 11, 2017
d64d381
Rename `builtin` => `global`.
jseyfried Mar 16, 2017
2c816f7
Optimize insertion sort
Mar 24, 2017
bff332e
travis: Update sccache again
alexcrichton Mar 25, 2017
16bfc19
Rollup merge of #40347 - alexcrichton:rm-liblog, r=brson
alexcrichton Mar 25, 2017
c43d5e3
Rollup merge of #40501 - jseyfried:shadow_builtin_macros, r=nrc
alexcrichton Mar 25, 2017
22380e7
Rollup merge of #40516 - alexcrichton:no-cache-handles, r=aturon
alexcrichton Mar 25, 2017
299a8f3
Rollup merge of #40524 - alexcrichton:update-bootstrap, r=brson
alexcrichton Mar 25, 2017
593b535
Rollup merge of #40540 - cramertj:check-bodies-as-query, r=nikomatsakis
alexcrichton Mar 25, 2017
e5f66fe
Rollup merge of #40642 - frewsxcv:io-bufread-doc-examples, r=Guillaum…
alexcrichton Mar 25, 2017
bbeb0c0
Rollup merge of #40683 - nikomatsakis:incr-comp-coerce-unsized-info, …
alexcrichton Mar 25, 2017
874045c
Rollup merge of #40764 - arielb1:range-nodes, r=eddyb
alexcrichton Mar 25, 2017
6b23772
Rollup merge of #40778 - alexcrichton:update-cargo, r=alexcrichton
alexcrichton Mar 25, 2017
1ae5b9a
Rollup merge of #40807 - stjepang:optimize-insertion-sort, r=alexcric…
alexcrichton Mar 25, 2017
9dc591c
Rollup merge of #40809 - alexcrichton:update-sccache-again, r=alexcri…
alexcrichton Mar 25, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
std: Don't cache stdio handles on Windows
This alters the stdio code on Windows to always call `GetStdHandle` whenever the
stdio read/write functions are called as this allows us to track changes to the
value over time (such as if a process calls `SetStdHandle` while it's running).

Closes #40490
  • Loading branch information
alexcrichton committed Mar 23, 2017
commit 5ca8a735ca36219abbf601624606c41148b95210
9 changes: 7 additions & 2 deletions src/libstd/sys/windows/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,13 @@ impl Stdio {
// INVALID_HANDLE_VALUE.
Stdio::Inherit => {
match stdio::get(stdio_id) {
Ok(io) => io.handle().duplicate(0, true,
c::DUPLICATE_SAME_ACCESS),
Ok(io) => {
let io = Handle::new(io.handle());
let ret = io.duplicate(0, true,
c::DUPLICATE_SAME_ACCESS);
io.into_raw();
return ret
}
Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)),
}
}
Expand Down
92 changes: 39 additions & 53 deletions src/libstd/sys/windows/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,42 +22,43 @@ use sys::cvt;
use sys::handle::Handle;
use sys_common::io::read_to_end_uninitialized;

pub struct NoClose(Option<Handle>);

pub enum Output {
Console(NoClose),
Pipe(NoClose),
Console(c::HANDLE),
Pipe(c::HANDLE),
}

pub struct Stdin {
handle: Output,
utf8: Mutex<io::Cursor<Vec<u8>>>,
}
pub struct Stdout(Output);
pub struct Stderr(Output);
pub struct Stdout;
pub struct Stderr;

pub fn get(handle: c::DWORD) -> io::Result<Output> {
let handle = unsafe { c::GetStdHandle(handle) };
if handle == c::INVALID_HANDLE_VALUE {
Err(io::Error::last_os_error())
} else if handle.is_null() {
Err(io::Error::new(io::ErrorKind::Other,
"no stdio handle available for this process"))
Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32))
} else {
let ret = NoClose::new(handle);
let mut out = 0;
match unsafe { c::GetConsoleMode(handle, &mut out) } {
0 => Ok(Output::Pipe(ret)),
_ => Ok(Output::Console(ret)),
0 => Ok(Output::Pipe(handle)),
_ => Ok(Output::Console(handle)),
}
}
}

fn write(out: &Output, data: &[u8]) -> io::Result<usize> {
let handle = match *out {
Output::Console(ref c) => c.get().raw(),
Output::Pipe(ref p) => return p.get().write(data),
fn write(handle: c::DWORD, data: &[u8]) -> io::Result<usize> {
let handle = match try!(get(handle)) {
Output::Console(c) => c,
Output::Pipe(p) => {
let handle = Handle::new(p);
let ret = handle.write(data);
handle.into_raw();
return ret
}
};

// As with stdin on windows, stdout often can't handle writes of large
// sizes. For an example, see #14940. For this reason, don't try to
// write the entire output buffer on windows.
Expand Down Expand Up @@ -93,18 +94,20 @@ fn write(out: &Output, data: &[u8]) -> io::Result<usize> {

impl Stdin {
pub fn new() -> io::Result<Stdin> {
get(c::STD_INPUT_HANDLE).map(|handle| {
Stdin {
handle: handle,
utf8: Mutex::new(Cursor::new(Vec::new())),
}
Ok(Stdin {
utf8: Mutex::new(Cursor::new(Vec::new())),
})
}

pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let handle = match self.handle {
Output::Console(ref c) => c.get().raw(),
Output::Pipe(ref p) => return p.get().read(buf),
let handle = match try!(get(c::STD_INPUT_HANDLE)) {
Output::Console(c) => c,
Output::Pipe(p) => {
let handle = Handle::new(p);
let ret = handle.read(buf);
handle.into_raw();
return ret
}
};
let mut utf8 = self.utf8.lock().unwrap();
// Read more if the buffer is empty
Expand All @@ -125,11 +128,9 @@ impl Stdin {
Ok(utf8) => utf8.into_bytes(),
Err(..) => return Err(invalid_encoding()),
};
if let Output::Console(_) = self.handle {
if let Some(&last_byte) = data.last() {
if last_byte == CTRL_Z {
data.pop();
}
if let Some(&last_byte) = data.last() {
if last_byte == CTRL_Z {
data.pop();
}
}
*utf8 = Cursor::new(data);
Expand Down Expand Up @@ -158,11 +159,11 @@ impl<'a> Read for &'a Stdin {

impl Stdout {
pub fn new() -> io::Result<Stdout> {
get(c::STD_OUTPUT_HANDLE).map(Stdout)
Ok(Stdout)
}

pub fn write(&self, data: &[u8]) -> io::Result<usize> {
write(&self.0, data)
write(c::STD_OUTPUT_HANDLE, data)
}

pub fn flush(&self) -> io::Result<()> {
Expand All @@ -172,11 +173,11 @@ impl Stdout {

impl Stderr {
pub fn new() -> io::Result<Stderr> {
get(c::STD_ERROR_HANDLE).map(Stderr)
Ok(Stderr)
}

pub fn write(&self, data: &[u8]) -> io::Result<usize> {
write(&self.0, data)
write(c::STD_ERROR_HANDLE, data)
}

pub fn flush(&self) -> io::Result<()> {
Expand All @@ -197,27 +198,12 @@ impl io::Write for Stderr {
}
}

impl NoClose {
fn new(handle: c::HANDLE) -> NoClose {
NoClose(Some(Handle::new(handle)))
}

fn get(&self) -> &Handle { self.0.as_ref().unwrap() }
}

impl Drop for NoClose {
fn drop(&mut self) {
self.0.take().unwrap().into_raw();
}
}

impl Output {
pub fn handle(&self) -> &Handle {
let nc = match *self {
Output::Console(ref c) => c,
Output::Pipe(ref c) => c,
};
nc.0.as_ref().unwrap()
pub fn handle(&self) -> c::HANDLE {
match *self {
Output::Console(c) => c,
Output::Pipe(c) => c,
}
}
}

Expand Down
64 changes: 64 additions & 0 deletions src/test/run-pass-fulldeps/switch-stdout.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(rustc_private)]

extern crate rustc_back;

use std::fs::File;
use std::io::{Read, Write};

use rustc_back::tempdir::TempDir;

#[cfg(unix)]
fn switch_stdout_to(file: File) {
use std::os::unix::prelude::*;

extern {
fn dup2(old: i32, new: i32) -> i32;
}

unsafe {
assert_eq!(dup2(file.as_raw_fd(), 1), 1);
}
}

#[cfg(windows)]
fn switch_stdout_to(file: File) {
use std::os::windows::prelude::*;

extern "system" {
fn SetStdHandle(nStdHandle: u32, handle: *mut u8) -> i32;
}

const STD_OUTPUT_HANDLE: u32 = (-11i32) as u32;

unsafe {
let rc = SetStdHandle(STD_OUTPUT_HANDLE,
file.into_raw_handle() as *mut _);
assert!(rc != 0);
}
}

fn main() {
let td = TempDir::new("foo").unwrap();
let path = td.path().join("bar");
let f = File::create(&path).unwrap();

println!("foo");
std::io::stdout().flush().unwrap();
switch_stdout_to(f);
println!("bar");
std::io::stdout().flush().unwrap();

let mut contents = String::new();
File::open(&path).unwrap().read_to_string(&mut contents).unwrap();
assert_eq!(contents, "bar\n");
}