Skip to content

Miscellaneous io-related fixes #1870

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 6 additions & 3 deletions Lib/_codecs.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ def charmap_encode(obj, errors='strict', mapping='latin-1'):
res = bytes(res)
return res, len(res)

def charmap_build(s):
return {ord(c): i for i, c in enumerate(s)}

if sys.maxunicode == 65535:
unicode_bytes = 2
else:
Expand Down Expand Up @@ -1525,11 +1528,11 @@ def charmapencode_output(c, mapping):
rep = mapping[c]
if isinstance(rep, int) or isinstance(rep, int):
if rep < 256:
return chr(rep)
return rep
else:
raise TypeError("character mapping must be in range(256)")
elif isinstance(rep, str):
return rep
return ord(rep)
elif rep == None:
raise KeyError("character maps to <undefined>")
else:
Expand Down Expand Up @@ -1579,7 +1582,7 @@ def PyUnicode_DecodeCharmap(s, size, mapping, errors):
#/* Get mapping (char ordinal -> integer, Unicode char or None) */
ch = s[inpos]
try:
x = mapping[ord(ch)]
x = mapping[ch]
if isinstance(x, int):
if x < 65536:
p += chr(x)
Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_unicode.py
Original file line number Diff line number Diff line change
Expand Up @@ -2219,8 +2219,6 @@ def test_codecs(self):
for encoding in ('utf-8',):
self.assertEqual(str(u.encode(encoding),encoding), u)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_codecs_charmap(self):
# 0-127
s = bytes(range(128))
Expand Down
2 changes: 1 addition & 1 deletion vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ schannel = "0.1"

[target."cfg(windows)".dependencies.winapi]
version = "0.3"
features = ["winsock2", "handleapi", "ws2def", "std", "winbase", "wincrypt"]
features = ["winsock2", "handleapi", "ws2def", "std", "winbase", "wincrypt", "fileapi"]

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2"
31 changes: 24 additions & 7 deletions vm/src/stdlib/faulthandler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,33 @@ fn dump_traceback(_file: OptionalArg<i64>, _all_threads: OptionalArg<bool>, vm:
}
}

fn enable(_file: OptionalArg<i64>, _all_threads: OptionalArg<bool>) {
#[derive(FromArgs)]
#[allow(unused)]
struct EnableArgs {
#[pyarg(positional_or_keyword, default = "None")]
file: Option<i64>,
#[pyarg(positional_or_keyword, default = "true")]
all_threads: bool,
}

fn enable(_args: EnableArgs) {
// TODO
}

fn register(
_signum: i64,
_file: OptionalArg<i64>,
_all_threads: OptionalArg<bool>,
_chain: OptionalArg<bool>,
) {
#[derive(FromArgs)]
#[allow(unused)]
struct RegisterArgs {
#[pyarg(positional_only)]
signum: i64,
#[pyarg(positional_or_keyword, default = "None")]
file: Option<i64>,
#[pyarg(positional_or_keyword, default = "true")]
all_threads: bool,
#[pyarg(positional_or_keyword, default = "false")]
chain: bool,
}

fn register(_args: RegisterArgs) {
// TODO
}

Expand Down
15 changes: 15 additions & 0 deletions vm/src/stdlib/msvcrt.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::os::errno_err;
use crate::obj::objbytes::PyBytesRef;
use crate::obj::objstr::PyStringRef;
use crate::pyobject::{PyObjectRef, PyResult};
Expand Down Expand Up @@ -45,6 +46,19 @@ fn msvcrt_putwch(s: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
Ok(())
}

extern "C" {
fn _setmode(fd: i32, flags: i32) -> i32;
}

fn msvcrt_setmode(fd: i32, flags: i32, vm: &VirtualMachine) -> PyResult<i32> {
let flags = unsafe { suppress_iph!(_setmode(fd, flags)) };
if flags == -1 {
Err(errno_err(vm))
} else {
Ok(flags)
}
}

pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
let ctx = &vm.ctx;
py_module!(vm, "_msvcrt", {
Expand All @@ -54,5 +68,6 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
"getwche" => ctx.new_function(msvcrt_getwche),
"putch" => ctx.new_function(msvcrt_putch),
"putwch" => ctx.new_function(msvcrt_putwch),
"setmode" => ctx.new_function(msvcrt_setmode),
})
}
90 changes: 66 additions & 24 deletions vm/src/stdlib/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use nix::pty::openpty;
use nix::unistd::{self, Gid, Pid, Uid};
#[cfg(unix)]
use std::os::unix::io::RawFd;
#[cfg(windows)]
use std::os::windows::io::RawHandle;
#[cfg(unix)]
use uname;

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

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

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

#[cfg(unix)]
fn os_set_inheritable(fd: RawFd, inheritable: bool, vm: &VirtualMachine) -> PyResult<()> {
let _set_flag = || {
use nix::fcntl::fcntl;
use nix::fcntl::FcntlArg;
use nix::fcntl::FdFlag;

let flags = FdFlag::from_bits_truncate(fcntl(fd, FcntlArg::F_GETFD)?);
let mut new_flags = flags;
new_flags.set(FdFlag::from_bits_truncate(libc::FD_CLOEXEC), !inheritable);
if flags != new_flags {
fcntl(fd, FcntlArg::F_SETFD(new_flags))?;
fn os_set_inheritable(fd: i64, inheritable: bool, vm: &VirtualMachine) -> PyResult<()> {
#[cfg(unix)]
{
let fd = fd as RawFd;
let _set_flag = || {
use nix::fcntl::fcntl;
use nix::fcntl::FcntlArg;
use nix::fcntl::FdFlag;

let flags = FdFlag::from_bits_truncate(fcntl(fd, FcntlArg::F_GETFD)?);
let mut new_flags = flags;
new_flags.set(FdFlag::from_bits_truncate(libc::FD_CLOEXEC), !inheritable);
if flags != new_flags {
fcntl(fd, FcntlArg::F_SETFD(new_flags))?;
}
Ok(())
};
_set_flag().or_else(|err| Err(convert_nix_error(vm, err)))
}
#[cfg(windows)]
{
use winapi::um::{handleapi, winbase};
let fd = fd as RawHandle;
let flags = if inheritable {
winbase::HANDLE_FLAG_INHERIT
} else {
0
};
let ret =
unsafe { handleapi::SetHandleInformation(fd, winbase::HANDLE_FLAG_INHERIT, flags) };
if ret == 0 {
Err(errno_err(vm))
} else {
Ok(())
}
Ok(())
};
_set_flag().or_else(|err| Err(convert_nix_error(vm, err)))
}
}

#[cfg(unix)]
Expand Down Expand Up @@ -1027,8 +1049,8 @@ fn os_pipe(vm: &VirtualMachine) -> PyResult<(RawFd, RawFd)> {
use nix::unistd::close;
use nix::unistd::pipe;
let (rfd, wfd) = pipe().map_err(|err| convert_nix_error(vm, err))?;
os_set_inheritable(rfd, false, vm)
.and_then(|_| os_set_inheritable(wfd, false, vm))
os_set_inheritable(rfd.into(), false, vm)
.and_then(|_| os_set_inheritable(wfd.into(), false, vm))
.or_else(|err| {
let _ = close(rfd);
let _ = close(wfd);
Expand Down Expand Up @@ -1322,10 +1344,25 @@ fn os_isatty(fd: i32) -> bool {

fn os_lseek(fd: i32, position: Offset, how: i32, vm: &VirtualMachine) -> PyResult<Offset> {
#[cfg(not(windows))]
use libc::lseek;
let res = unsafe { suppress_iph!(libc::lseek(fd, position, how)) };
#[cfg(windows)]
use libc::lseek64 as lseek;
let res = unsafe { suppress_iph!(lseek(fd, position, how)) };
let res = unsafe {
use winapi::um::{fileapi, winnt};
let mut li = winnt::LARGE_INTEGER::default();
*li.QuadPart_mut() = position;
let ret = fileapi::SetFilePointer(
fd as RawHandle,
li.u().LowPart as _,
&mut li.u_mut().HighPart,
how as _,
);
if ret == fileapi::INVALID_SET_FILE_POINTER {
-1
} else {
li.u_mut().LowPart = ret;
*li.QuadPart()
}
};
if res < 0 {
Err(errno_err(vm))
} else {
Expand Down Expand Up @@ -1439,6 +1476,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
"urandom" => ctx.new_function(os_urandom),
"isatty" => ctx.new_function(os_isatty),
"lseek" => ctx.new_function(os_lseek),
"set_inheritable" => ctx.new_function(os_set_inheritable),

"O_RDONLY" => ctx.new_int(libc::O_RDONLY),
"O_WRONLY" => ctx.new_int(libc::O_WRONLY),
Expand Down Expand Up @@ -1506,7 +1544,6 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: PyObjectRef) ->
"getuid" => ctx.new_function(os_getuid),
"geteuid" => ctx.new_function(os_geteuid),
"pipe" => ctx.new_function(os_pipe), //TODO: windows
"set_inheritable" => ctx.new_function(os_set_inheritable), // TODO: windows
"set_blocking" => ctx.new_function(os_set_blocking),
"setgid" => ctx.new_function(os_setgid),
"setpgid" => ctx.new_function(os_setpgid),
Expand Down Expand Up @@ -1578,7 +1615,12 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: PyObjectRef) ->
module
}

#[cfg(not(unix))]
fn extend_module_platform_specific(_vm: &VirtualMachine, module: PyObjectRef) -> PyObjectRef {
#[cfg(windows)]
fn extend_module_platform_specific(vm: &VirtualMachine, module: PyObjectRef) -> PyObjectRef {
let ctx = &vm.ctx;
extend_module!(vm, module, {
"O_BINARY" => ctx.new_int(libc::O_BINARY),
});

module
}
32 changes: 24 additions & 8 deletions vm/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,14 +537,30 @@ impl VirtualMachine {

// TODO: #[track_caller] when stabilized
fn _py_panic_failed(&self, exc: &PyBaseExceptionRef, msg: &str) -> ! {
let show_backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |v| &v != "0");
let after = if show_backtrace {
exceptions::print_exception(self, exc);
"exception backtrace above"
} else {
"run with RUST_BACKTRACE=1 to see Python backtrace"
};
panic!("{}; {}", msg, after)
#[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"))))]
{
let show_backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |v| &v != "0");
let after = if show_backtrace {
exceptions::print_exception(self, exc);
"exception backtrace above"
} else {
"run with RUST_BACKTRACE=1 to see Python backtrace"
};
panic!("{}; {}", msg, after)
}
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
{
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn error(s: &str);
}
let mut s = Vec::<u8>::new();
exceptions::write_exception(&mut s, self, exc).unwrap();
error(std::str::from_utf8(&s).unwrap());
panic!("{}; exception backtrace above", msg)
}
}
pub fn unwrap_pyresult<T>(&self, result: PyResult<T>) -> T {
result.unwrap_or_else(|exc| {
Expand Down