Skip to content

Commit ca1c7e8

Browse files
committed
Fix os.set_inheritable and msvcrt.setmode on windows
1 parent 1c4b478 commit ca1c7e8

File tree

3 files changed

+136
-95
lines changed

3 files changed

+136
-95
lines changed

vm/Lib/python_builtins/_io.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1520,7 +1520,7 @@ def __init__(self, file, mode='r', closefd=True, opener=None):
15201520
if self._blksize <= 1:
15211521
self._blksize = DEFAULT_BUFFER_SIZE
15221522

1523-
if _setmode:
1523+
if _setmode and False:
15241524
# don't translate newlines (\r\n <=> \n)
15251525
_setmode(fd, os.O_BINARY)
15261526

vm/src/stdlib/msvcrt.rs

Lines changed: 87 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,87 @@
1-
use super::os::errno_err;
2-
use crate::obj::objbytes::PyBytesRef;
3-
use crate::obj::objstr::PyStringRef;
4-
use crate::pyobject::{PyObjectRef, PyResult};
5-
use crate::VirtualMachine;
6-
7-
use itertools::Itertools;
8-
9-
extern "C" {
10-
fn _getch() -> i32;
11-
fn _getwch() -> u32;
12-
fn _getche() -> i32;
13-
fn _getwche() -> u32;
14-
fn _putch(c: u32) -> i32;
15-
fn _putwch(c: u16) -> u32;
16-
}
17-
18-
fn msvcrt_getch() -> Vec<u8> {
19-
let c = unsafe { _getch() };
20-
vec![c as u8]
21-
}
22-
fn msvcrt_getwch() -> String {
23-
let c = unsafe { _getwch() };
24-
std::char::from_u32(c).unwrap().to_string()
25-
}
26-
fn msvcrt_getche() -> Vec<u8> {
27-
let c = unsafe { _getche() };
28-
vec![c as u8]
29-
}
30-
fn msvcrt_getwche() -> String {
31-
let c = unsafe { _getwche() };
32-
std::char::from_u32(c).unwrap().to_string()
33-
}
34-
fn msvcrt_putch(b: PyBytesRef, vm: &VirtualMachine) -> PyResult<()> {
35-
let &c = b.get_value().iter().exactly_one().map_err(|_| {
36-
vm.new_type_error("putch() argument must be a byte string of length 1".to_owned())
37-
})?;
38-
unsafe { suppress_iph!(_putch(c.into())) };
39-
Ok(())
40-
}
41-
fn msvcrt_putwch(s: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
42-
let c = s.as_str().chars().exactly_one().map_err(|_| {
43-
vm.new_type_error("putch() argument must be a string of length 1".to_owned())
44-
})?;
45-
unsafe { suppress_iph!(_putwch(c as u16)) };
46-
Ok(())
47-
}
48-
49-
extern "C" {
50-
fn _setmode(fd: i32, flags: i32) -> i32;
51-
}
52-
53-
fn msvcrt_setmode(fd: i32, flags: i32, vm: &VirtualMachine) -> PyResult<i32> {
54-
let flags = unsafe { suppress_iph!(_setmode(fd, flags)) };
55-
if flags == -1 {
56-
Err(errno_err(vm))
57-
} else {
58-
Ok(flags)
59-
}
60-
}
61-
62-
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
63-
let ctx = &vm.ctx;
64-
py_module!(vm, "_msvcrt", {
65-
"getch" => ctx.new_function(msvcrt_getch),
66-
"getwch" => ctx.new_function(msvcrt_getwch),
67-
"getche" => ctx.new_function(msvcrt_getche),
68-
"getwche" => ctx.new_function(msvcrt_getwche),
69-
"putch" => ctx.new_function(msvcrt_putch),
70-
"putwch" => ctx.new_function(msvcrt_putwch),
71-
"setmode" => ctx.new_function(msvcrt_setmode),
72-
})
73-
}
1+
use super::os::convert_io_error;
2+
use crate::obj::objbytes::PyBytesRef;
3+
use crate::obj::objstr::PyStringRef;
4+
use crate::pyobject::{PyObjectRef, PyResult};
5+
use crate::VirtualMachine;
6+
7+
use itertools::Itertools;
8+
use std::io;
9+
10+
extern "C" {
11+
fn _get_errno(pValue: *mut i32) -> i32;
12+
}
13+
14+
fn get_errno() -> i32 {
15+
let mut v = 0;
16+
unsafe { _get_errno(&mut v) };
17+
v
18+
}
19+
20+
extern "C" {
21+
fn _getch() -> i32;
22+
fn _getwch() -> u32;
23+
fn _getche() -> i32;
24+
fn _getwche() -> u32;
25+
fn _putch(c: u32) -> i32;
26+
fn _putwch(c: u16) -> u32;
27+
}
28+
29+
fn msvcrt_getch() -> Vec<u8> {
30+
let c = unsafe { _getch() };
31+
vec![c as u8]
32+
}
33+
fn msvcrt_getwch() -> String {
34+
let c = unsafe { _getwch() };
35+
std::char::from_u32(c).unwrap().to_string()
36+
}
37+
fn msvcrt_getche() -> Vec<u8> {
38+
let c = unsafe { _getche() };
39+
vec![c as u8]
40+
}
41+
fn msvcrt_getwche() -> String {
42+
let c = unsafe { _getwche() };
43+
std::char::from_u32(c).unwrap().to_string()
44+
}
45+
fn msvcrt_putch(b: PyBytesRef, vm: &VirtualMachine) -> PyResult<()> {
46+
let &c = b.get_value().iter().exactly_one().map_err(|_| {
47+
vm.new_type_error("putch() argument must be a byte string of length 1".to_owned())
48+
})?;
49+
unsafe { suppress_iph!(_putch(c.into())) };
50+
Ok(())
51+
}
52+
fn msvcrt_putwch(s: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
53+
let c = s.as_str().chars().exactly_one().map_err(|_| {
54+
vm.new_type_error("putch() argument must be a string of length 1".to_owned())
55+
})?;
56+
unsafe { suppress_iph!(_putwch(c as u16)) };
57+
Ok(())
58+
}
59+
60+
extern "C" {
61+
fn _setmode(fd: i32, flags: i32) -> i32;
62+
}
63+
64+
fn msvcrt_setmode(fd: i32, flags: i32, vm: &VirtualMachine) -> PyResult<i32> {
65+
let flags = unsafe { suppress_iph!(_setmode(fd, flags)) };
66+
if flags == -1 {
67+
Err(convert_io_error(
68+
vm,
69+
io::Error::from_raw_os_error(get_errno()),
70+
))
71+
} else {
72+
Ok(flags)
73+
}
74+
}
75+
76+
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
77+
let ctx = &vm.ctx;
78+
py_module!(vm, "_msvcrt", {
79+
"getch" => ctx.new_function(msvcrt_getch),
80+
"getwch" => ctx.new_function(msvcrt_getwch),
81+
"getche" => ctx.new_function(msvcrt_getche),
82+
"getwche" => ctx.new_function(msvcrt_getwche),
83+
"putch" => ctx.new_function(msvcrt_putch),
84+
"putwch" => ctx.new_function(msvcrt_putwch),
85+
"setmode" => ctx.new_function(msvcrt_setmode),
86+
})
87+
}

vm/src/stdlib/os.rs

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ use nix::pty::openpty;
2222
use nix::unistd::{self, Gid, Pid, Uid};
2323
#[cfg(unix)]
2424
use std::os::unix::io::RawFd;
25+
#[cfg(windows)]
26+
use std::os::windows::io::RawHandle;
2527
#[cfg(unix)]
2628
use uname;
2729

@@ -70,7 +72,7 @@ pub fn raw_file_number(handle: File) -> i64 {
7072

7173
#[cfg(windows)]
7274
pub fn rust_file(raw_fileno: i64) -> File {
73-
use std::os::windows::io::{AsRawHandle, FromRawHandle, RawHandle};
75+
use std::os::windows::io::{AsRawHandle, FromRawHandle};
7476

7577
let raw_fileno = match raw_fileno {
7678
0 => io::stdin().as_raw_handle(),
@@ -975,22 +977,42 @@ fn os_get_inheritable(fd: RawFd, vm: &VirtualMachine) -> PyResult<bool> {
975977
}
976978
}
977979

978-
#[cfg(unix)]
979-
fn os_set_inheritable(fd: RawFd, inheritable: bool, vm: &VirtualMachine) -> PyResult<()> {
980-
let _set_flag = || {
981-
use nix::fcntl::fcntl;
982-
use nix::fcntl::FcntlArg;
983-
use nix::fcntl::FdFlag;
984-
985-
let flags = FdFlag::from_bits_truncate(fcntl(fd, FcntlArg::F_GETFD)?);
986-
let mut new_flags = flags;
987-
new_flags.set(FdFlag::from_bits_truncate(libc::FD_CLOEXEC), !inheritable);
988-
if flags != new_flags {
989-
fcntl(fd, FcntlArg::F_SETFD(new_flags))?;
980+
fn os_set_inheritable(fd: i64, inheritable: bool, vm: &VirtualMachine) -> PyResult<()> {
981+
#[cfg(unix)]
982+
{
983+
let fd = fd as RawFd;
984+
let _set_flag = || {
985+
use nix::fcntl::fcntl;
986+
use nix::fcntl::FcntlArg;
987+
use nix::fcntl::FdFlag;
988+
989+
let flags = FdFlag::from_bits_truncate(fcntl(fd, FcntlArg::F_GETFD)?);
990+
let mut new_flags = flags;
991+
new_flags.set(FdFlag::from_bits_truncate(libc::FD_CLOEXEC), !inheritable);
992+
if flags != new_flags {
993+
fcntl(fd, FcntlArg::F_SETFD(new_flags))?;
994+
}
995+
Ok(())
996+
};
997+
_set_flag().or_else(|err| Err(convert_nix_error(vm, err)))
998+
}
999+
#[cfg(windows)]
1000+
{
1001+
use winapi::um::{handleapi, winbase};
1002+
let fd = fd as RawHandle;
1003+
let flags = if inheritable {
1004+
winbase::HANDLE_FLAG_INHERIT
1005+
} else {
1006+
0
1007+
};
1008+
let ret =
1009+
unsafe { handleapi::SetHandleInformation(fd, winbase::HANDLE_FLAG_INHERIT, flags) };
1010+
if ret == 0 {
1011+
Err(errno_err(vm))
1012+
} else {
1013+
Ok(())
9901014
}
991-
Ok(())
992-
};
993-
_set_flag().or_else(|err| Err(convert_nix_error(vm, err)))
1015+
}
9941016
}
9951017

9961018
#[cfg(unix)]
@@ -1027,8 +1049,8 @@ fn os_pipe(vm: &VirtualMachine) -> PyResult<(RawFd, RawFd)> {
10271049
use nix::unistd::close;
10281050
use nix::unistd::pipe;
10291051
let (rfd, wfd) = pipe().map_err(|err| convert_nix_error(vm, err))?;
1030-
os_set_inheritable(rfd, false, vm)
1031-
.and_then(|_| os_set_inheritable(wfd, false, vm))
1052+
os_set_inheritable(rfd.into(), false, vm)
1053+
.and_then(|_| os_set_inheritable(wfd.into(), false, vm))
10321054
.or_else(|err| {
10331055
let _ = close(rfd);
10341056
let _ = close(wfd);
@@ -1439,6 +1461,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
14391461
"urandom" => ctx.new_function(os_urandom),
14401462
"isatty" => ctx.new_function(os_isatty),
14411463
"lseek" => ctx.new_function(os_lseek),
1464+
"set_inheritable" => ctx.new_function(os_set_inheritable),
14421465

14431466
"O_RDONLY" => ctx.new_int(libc::O_RDONLY),
14441467
"O_WRONLY" => ctx.new_int(libc::O_WRONLY),
@@ -1506,7 +1529,6 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: PyObjectRef) ->
15061529
"getuid" => ctx.new_function(os_getuid),
15071530
"geteuid" => ctx.new_function(os_geteuid),
15081531
"pipe" => ctx.new_function(os_pipe), //TODO: windows
1509-
"set_inheritable" => ctx.new_function(os_set_inheritable), // TODO: windows
15101532
"set_blocking" => ctx.new_function(os_set_blocking),
15111533
"setgid" => ctx.new_function(os_setgid),
15121534
"setpgid" => ctx.new_function(os_setpgid),
@@ -1578,7 +1600,12 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: PyObjectRef) ->
15781600
module
15791601
}
15801602

1581-
#[cfg(not(unix))]
1582-
fn extend_module_platform_specific(_vm: &VirtualMachine, module: PyObjectRef) -> PyObjectRef {
1603+
#[cfg(windows)]
1604+
fn extend_module_platform_specific(vm: &VirtualMachine, module: PyObjectRef) -> PyObjectRef {
1605+
let ctx = &vm.ctx;
1606+
extend_module!(vm, module, {
1607+
"O_BINARY" => ctx.new_int(libc::O_BINARY),
1608+
});
1609+
15831610
module
15841611
}

0 commit comments

Comments
 (0)