From edb84896bf9e0b1b182489b91a929109f2b1765f Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Thu, 7 Nov 2019 22:13:05 -0600 Subject: [PATCH 1/7] Make PyObject.dict an Option> --- Lib/_threading_local.py | 2 ++ vm/src/builtins.rs | 12 +++++++++--- vm/src/frame.rs | 2 +- vm/src/obj/objmodule.rs | 2 +- vm/src/obj/objobject.rs | 26 ++++++++++++++------------ vm/src/pyobject.rs | 13 +++++++++---- vm/src/vm.rs | 2 +- 7 files changed, 37 insertions(+), 22 deletions(-) diff --git a/Lib/_threading_local.py b/Lib/_threading_local.py index 4ec4828144..76f10229d2 100644 --- a/Lib/_threading_local.py +++ b/Lib/_threading_local.py @@ -193,6 +193,7 @@ class _localimpl: @contextmanager def _patch(self): + old = object.__getattribute__(self, '__dict__') impl = object.__getattribute__(self, '_local__impl') try: dct = impl.get_dict() @@ -203,6 +204,7 @@ def _patch(self): with impl.locallock: object.__setattr__(self, '__dict__', dct) yield + object.__setattr__(self, '__dict__', old) class local: diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 5cf2db1afa..c8a8f59446 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -252,9 +252,15 @@ fn make_scope(vm: &VirtualMachine, scope: ScopeArgs) -> PyResult { let globals = match globals { Some(dict) => { if !dict.contains_key("__builtins__", vm) { - let builtins_dict = vm.builtins.dict.as_ref().unwrap().as_object(); - dict.set_item("__builtins__", builtins_dict.clone(), vm) - .unwrap(); + let builtins_dict = vm + .builtins + .dict + .as_ref() + .unwrap() + .borrow() + .as_object() + .clone(); + dict.set_item("__builtins__", builtins_dict, vm).unwrap(); } dict } diff --git a/vm/src/frame.rs b/vm/src/frame.rs index e330ab462a..02c669d339 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -699,7 +699,7 @@ impl Frame { // Grab all the names from the module and put them in the context if let Some(dict) = &module.dict { - for (k, v) in dict { + for (k, v) in &*dict.borrow() { let k = vm.to_str(&k)?; let k = k.as_str(); if !k.starts_with('_') { diff --git a/vm/src/obj/objmodule.rs b/vm/src/obj/objmodule.rs index 616c289981..c822362248 100644 --- a/vm/src/obj/objmodule.rs +++ b/vm/src/obj/objmodule.rs @@ -50,7 +50,7 @@ impl PyModuleRef { let zelf = PyModule {}.into_ref_with_type(vm, cls)?; init_module_dict( vm, - zelf.as_object().dict.as_ref().unwrap(), + &zelf.as_object().dict.as_ref().unwrap().borrow(), name.into_object(), doc.flat_option() .map_or_else(|| vm.get_none(), PyRef::into_object), diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index a3e512ce59..2a5a0afef4 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -77,7 +77,7 @@ fn object_setattr( } if let Some(ref dict) = obj.clone().dict { - dict.set_item(attr_name.as_str(), value, vm)?; + dict.borrow().set_item(attr_name.as_str(), value, vm)?; Ok(()) } else { Err(vm.new_attribute_error(format!( @@ -98,7 +98,7 @@ fn object_delattr(obj: PyObjectRef, attr_name: PyStringRef, vm: &VirtualMachine) } if let Some(ref dict) = obj.dict { - dict.del_item(attr_name.as_str(), vm)?; + dict.borrow().del_item(attr_name.as_str(), vm)?; Ok(()) } else { Err(vm.new_attribute_error(format!( @@ -130,7 +130,7 @@ pub fn object_dir(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { if let Some(object_dict) = &obj.dict { vm.invoke( &vm.get_attribute(dict.clone().into_object(), "update")?, - object_dict.clone().into_object(), + object_dict.borrow().clone().into_object(), )?; } @@ -210,20 +210,22 @@ fn object_class_setter( fn object_dict(object: PyObjectRef, vm: &VirtualMachine) -> PyResult { if let Some(ref dict) = object.dict { - Ok(dict.clone()) + Ok(dict.borrow().clone()) } else { Err(vm.new_attribute_error("no dictionary.".to_string())) } } -fn object_dict_setter( - _instance: PyObjectRef, - _value: PyObjectRef, - vm: &VirtualMachine, -) -> PyResult { - Err(vm.new_not_implemented_error( - "Setting __dict__ attribute on an object isn't yet implemented".to_string(), - )) +fn object_dict_setter(instance: PyObjectRef, value: PyDictRef, vm: &VirtualMachine) -> PyResult { + if let Some(dict) = &instance.dict { + *dict.borrow_mut() = value; + Ok(vm.get_none()) + } else { + Err(vm.new_attribute_error(format!( + "'{}' object has no attribute '__dict__'", + instance.class().name + ))) + } } fn object_getattribute(obj: PyObjectRef, name: PyStringRef, vm: &VirtualMachine) -> PyResult { diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 0d5b95f50d..9ac099ff0e 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -1,5 +1,5 @@ use std::any::Any; -use std::cell::Cell; +use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::fmt; use std::marker::PhantomData; @@ -522,7 +522,7 @@ impl PyContext { pub fn new_instance(&self, class: PyClassRef, dict: Option) -> PyObjectRef { PyObject { typ: class, - dict, + dict: dict.map(RefCell::new), payload: objobject::PyInstance, } .into_ref() @@ -566,7 +566,7 @@ where T: ?Sized + PyObjectPayload, { pub typ: PyClassRef, - pub dict: Option, // __dict__ member + pub dict: Option>, // __dict__ member pub payload: T, } @@ -1038,7 +1038,12 @@ where { #[allow(clippy::new_ret_no_self)] pub fn new(payload: T, typ: PyClassRef, dict: Option) -> PyObjectRef { - PyObject { typ, dict, payload }.into_ref() + PyObject { + typ, + dict: dict.map(RefCell::new), + payload, + } + .into_ref() } // Move this object into a reference object, transferring ownership. diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 403d975921..f9cac2244b 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -952,7 +952,7 @@ impl VirtualMachine { } let attr = if let Some(ref dict) = obj.dict { - dict.get_item_option(name_str.as_str(), self)? + dict.borrow().get_item_option(name_str.as_str(), self)? } else { None }; From e612c0d7ababac2021c1388813524454b30cbd2c Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Sat, 16 Nov 2019 22:56:32 -0600 Subject: [PATCH 2/7] Add the errno::errors module --- vm/src/stdlib/errno.rs | 522 ++++++++++++++++------------------------- 1 file changed, 197 insertions(+), 325 deletions(-) diff --git a/vm/src/stdlib/errno.rs b/vm/src/stdlib/errno.rs index dfd502900b..7aa55fcd88 100644 --- a/vm/src/stdlib/errno.rs +++ b/vm/src/stdlib/errno.rs @@ -15,334 +15,206 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { module } -#[cfg(target_os = "linux")] -const ERROR_CODES: &[(&str, i32)] = &[ - ("ENODEV", libc::ENODEV), - ("ENOCSI", libc::ENOCSI), - ("EHOSTUNREACH", libc::EHOSTUNREACH), - ("ENOMSG", libc::ENOMSG), - ("EUCLEAN", libc::EUCLEAN), - ("EL2NSYNC", libc::EL2NSYNC), - ("EL2HLT", libc::EL2HLT), - ("ENODATA", libc::ENODATA), - ("ENOTBLK", libc::ENOTBLK), - ("ENOSYS", libc::ENOSYS), - ("EPIPE", libc::EPIPE), - ("EINVAL", libc::EINVAL), - ("EOVERFLOW", libc::EOVERFLOW), - ("EADV", libc::EADV), - ("EINTR", libc::EINTR), - ("EUSERS", libc::EUSERS), - ("ENOTEMPTY", libc::ENOTEMPTY), - ("ENOBUFS", libc::ENOBUFS), - ("EPROTO", libc::EPROTO), - ("EREMOTE", libc::EREMOTE), - ("ENAVAIL", libc::ENAVAIL), - ("ECHILD", libc::ECHILD), - ("ELOOP", libc::ELOOP), - ("EXDEV", libc::EXDEV), - ("E2BIG", libc::E2BIG), - ("ESRCH", libc::ESRCH), - ("EMSGSIZE", libc::EMSGSIZE), - ("EAFNOSUPPORT", libc::EAFNOSUPPORT), - ("EBADR", libc::EBADR), - ("EHOSTDOWN", libc::EHOSTDOWN), - ("EPFNOSUPPORT", libc::EPFNOSUPPORT), - ("ENOPROTOOPT", libc::ENOPROTOOPT), - ("EBUSY", libc::EBUSY), - ("EAGAIN", libc::EAGAIN), - ("EBADFD", libc::EBADFD), - ("EDOTDOT", libc::EDOTDOT), - ("EISCONN", libc::EISCONN), - ("ENOANO", libc::ENOANO), - ("ESHUTDOWN", libc::ESHUTDOWN), - ("ECHRNG", libc::ECHRNG), - ("ELIBBAD", libc::ELIBBAD), - ("ENONET", libc::ENONET), - ("EBADE", libc::EBADE), - ("EBADF", libc::EBADF), - ("EMULTIHOP", libc::EMULTIHOP), - ("EIO", libc::EIO), - ("EUNATCH", libc::EUNATCH), - ("EPROTOTYPE", libc::EPROTOTYPE), - ("ENOSPC", libc::ENOSPC), - ("ENOEXEC", libc::ENOEXEC), - ("EALREADY", libc::EALREADY), - ("ENETDOWN", libc::ENETDOWN), - ("ENOTNAM", libc::ENOTNAM), - ("EACCES", libc::EACCES), - ("ELNRNG", libc::ELNRNG), - ("EILSEQ", libc::EILSEQ), - ("ENOTDIR", libc::ENOTDIR), - ("ENOTUNIQ", libc::ENOTUNIQ), - ("EPERM", libc::EPERM), - ("EDOM", libc::EDOM), - ("EXFULL", libc::EXFULL), - ("ECONNREFUSED", libc::ECONNREFUSED), - ("EISDIR", libc::EISDIR), - ("EPROTONOSUPPORT", libc::EPROTONOSUPPORT), - ("EROFS", libc::EROFS), - ("EADDRNOTAVAIL", libc::EADDRNOTAVAIL), - ("EIDRM", libc::EIDRM), - ("ECOMM", libc::ECOMM), - ("ESRMNT", libc::ESRMNT), - ("EREMOTEIO", libc::EREMOTEIO), - ("EL3RST", libc::EL3RST), - ("EBADMSG", libc::EBADMSG), - ("ENFILE", libc::ENFILE), - ("ELIBMAX", libc::ELIBMAX), - ("ESPIPE", libc::ESPIPE), - ("ENOLINK", libc::ENOLINK), - ("ENETRESET", libc::ENETRESET), - ("ETIMEDOUT", libc::ETIMEDOUT), - ("ENOENT", libc::ENOENT), - ("EEXIST", libc::EEXIST), - ("EDQUOT", libc::EDQUOT), - ("ENOSTR", libc::ENOSTR), - ("EBADSLT", libc::EBADSLT), - ("EBADRQC", libc::EBADRQC), - ("ELIBACC", libc::ELIBACC), - ("EFAULT", libc::EFAULT), - ("EFBIG", libc::EFBIG), - ("EDEADLOCK", libc::EDEADLOCK), - ("ENOTCONN", libc::ENOTCONN), - ("EDESTADDRREQ", libc::EDESTADDRREQ), - ("ELIBSCN", libc::ELIBSCN), - ("ENOLCK", libc::ENOLCK), - ("EISNAM", libc::EISNAM), - ("ECONNABORTED", libc::ECONNABORTED), - ("ENETUNREACH", libc::ENETUNREACH), - ("ESTALE", libc::ESTALE), - ("ENOSR", libc::ENOSR), - ("ENOMEM", libc::ENOMEM), - ("ENOTSOCK", libc::ENOTSOCK), - ("ESTRPIPE", libc::ESTRPIPE), - ("EMLINK", libc::EMLINK), - ("ERANGE", libc::ERANGE), - ("ELIBEXEC", libc::ELIBEXEC), - ("EL3HLT", libc::EL3HLT), - ("ECONNRESET", libc::ECONNRESET), - ("EADDRINUSE", libc::EADDRINUSE), - ("ENOTSUP", libc::ENOTSUP), - ("EREMCHG", libc::EREMCHG), - ("ENAMETOOLONG", libc::ENAMETOOLONG), - ("ENOTTY", libc::ENOTTY), - ("ERESTART", libc::ERESTART), - ("ESOCKTNOSUPPORT", libc::ESOCKTNOSUPPORT), - ("ETIME", libc::ETIME), - ("EBFONT", libc::EBFONT), - ("ETOOMANYREFS", libc::ETOOMANYREFS), - ("EMFILE", libc::EMFILE), - ("ETXTBSY", libc::ETXTBSY), - ("EINPROGRESS", libc::EINPROGRESS), - ("ENXIO", libc::ENXIO), - ("ENOPKG", libc::ENOPKG), - ("ENOMEDIUM", libc::ENOMEDIUM), - ("EMEDIUMTYPE", libc::EMEDIUMTYPE), - ("ECANCELED", libc::ECANCELED), - ("ENOKEY", libc::ENOKEY), - ("EKEYEXPIRED", libc::EKEYEXPIRED), - ("EKEYREVOKED", libc::EKEYREVOKED), - ("EKEYREJECTED", libc::EKEYREJECTED), - ("EOWNERDEAD", libc::EOWNERDEAD), - ("ENOTRECOVERABLE", libc::ENOTRECOVERABLE), - ("ERFKILL", libc::ERFKILL), -]; +#[rustfmt::skip] +#[allow(unused)] +pub mod errors { + pub use libc::*; + #[cfg(windows)] + pub use winapi::shared::winerror::*; + #[cfg(windows)] pub const EACCES: i32 = WSAEACCES as _; + #[cfg(windows)] pub const EADDRINUSE: i32 = WSAEADDRINUSE as _; + #[cfg(windows)] pub const EADDRNOTAVAIL: i32 = WSAEADDRNOTAVAIL as _; + #[cfg(windows)] pub const EAFNOSUPPORT: i32 = WSAEAFNOSUPPORT as _; + #[cfg(windows)] pub const EALREADY: i32 = WSAEALREADY as _; + #[cfg(windows)] pub const EBADF: i32 = WSAEBADF as _; + #[cfg(windows)] pub const ECANCELED: i32 = WSAECANCELLED as _; + #[cfg(windows)] pub const ECONNABORTED: i32 = WSAECONNABORTED as _; + #[cfg(windows)] pub const ECONNREFUSED: i32 = WSAECONNREFUSED as _; + #[cfg(windows)] pub const ECONNRESET: i32 = WSAECONNRESET as _; + #[cfg(windows)] pub const EDESTADDRREQ: i32 = WSAEDESTADDRREQ as _; + #[cfg(windows)] pub const EDISCON: i32 = WSAEDISCON as _; + #[cfg(windows)] pub const EDQUOT: i32 = WSAEDQUOT as _; + #[cfg(windows)] pub const EFAULT: i32 = WSAEFAULT as _; + #[cfg(windows)] pub const EHOSTDOWN: i32 = WSAEHOSTDOWN as _; + #[cfg(windows)] pub const EHOSTUNREACH: i32 = WSAEHOSTUNREACH as _; + #[cfg(windows)] pub const EINPROGRESS: i32 = WSAEINPROGRESS as _; + #[cfg(windows)] pub const EINTR: i32 = WSAEINTR as _; + #[cfg(windows)] pub const EINVAL: i32 = WSAEINVAL as _; + #[cfg(windows)] pub const EINVALIDPROCTABLE: i32 = WSAEINVALIDPROCTABLE as _; + #[cfg(windows)] pub const EINVALIDPROVIDER: i32 = WSAEINVALIDPROVIDER as _; + #[cfg(windows)] pub const EISCONN: i32 = WSAEISCONN as _; + #[cfg(windows)] pub const ELOOP: i32 = WSAELOOP as _; + #[cfg(windows)] pub const EMFILE: i32 = WSAEMFILE as _; + #[cfg(windows)] pub const EMSGSIZE: i32 = WSAEMSGSIZE as _; + #[cfg(windows)] pub const ENAMETOOLONG: i32 = WSAENAMETOOLONG as _; + #[cfg(windows)] pub const ENETDOWN: i32 = WSAENETDOWN as _; + #[cfg(windows)] pub const ENETRESET: i32 = WSAENETRESET as _; + #[cfg(windows)] pub const ENETUNREACH: i32 = WSAENETUNREACH as _; + #[cfg(windows)] pub const ENOBUFS: i32 = WSAENOBUFS as _; + #[cfg(windows)] pub const ENOMORE: i32 = WSAENOMORE as _; + #[cfg(windows)] pub const ENOPROTOOPT: i32 = WSAENOPROTOOPT as _; + #[cfg(windows)] pub const ENOTCONN: i32 = WSAENOTCONN as _; + #[cfg(windows)] pub const ENOTEMPTY: i32 = WSAENOTEMPTY as _; + #[cfg(windows)] pub const ENOTSOCK: i32 = WSAENOTSOCK as _; + #[cfg(windows)] pub const EOPNOTSUPP: i32 = WSAEOPNOTSUPP as _; + #[cfg(windows)] pub const EPFNOSUPPORT: i32 = WSAEPFNOSUPPORT as _; + #[cfg(windows)] pub const EPROCLIM: i32 = WSAEPROCLIM as _; + #[cfg(windows)] pub const EPROTONOSUPPORT: i32 = WSAEPROTONOSUPPORT as _; + #[cfg(windows)] pub const EPROTOTYPE: i32 = WSAEPROTOTYPE as _; + #[cfg(windows)] pub const EPROVIDERFAILEDINIT: i32 = WSAEPROVIDERFAILEDINIT as _; + #[cfg(windows)] pub const EREFUSED: i32 = WSAEREFUSED as _; + #[cfg(windows)] pub const EREMOTE: i32 = WSAEREMOTE as _; + #[cfg(windows)] pub const ESHUTDOWN: i32 = WSAESHUTDOWN as _; + #[cfg(windows)] pub const ESOCKTNOSUPPORT: i32 = WSAESOCKTNOSUPPORT as _; + #[cfg(windows)] pub const ESTALE: i32 = WSAESTALE as _; + #[cfg(windows)] pub const ETIMEDOUT: i32 = WSAETIMEDOUT as _; + #[cfg(windows)] pub const ETOOMANYREFS: i32 = WSAETOOMANYREFS as _; + #[cfg(windows)] pub const EUSERS: i32 = WSAEUSERS as _; + #[cfg(windows)] pub const EWOULDBLOCK: i32 = WSAEWOULDBLOCK as _; +} -#[cfg(all(unix, not(target_os = "linux")))] -const ERROR_CODES: &[(&str, i32)] = &[ - ("ENODEV", libc::ENODEV), - ("EHOSTUNREACH", libc::EHOSTUNREACH), - ("ENOMSG", libc::ENOMSG), - ("ENODATA", libc::ENODATA), - ("ENOTBLK", libc::ENOTBLK), - ("ENOSYS", libc::ENOSYS), - ("EPIPE", libc::EPIPE), - ("EINVAL", libc::EINVAL), - ("EOVERFLOW", libc::EOVERFLOW), - ("EINTR", libc::EINTR), - ("EUSERS", libc::EUSERS), - ("ENOTEMPTY", libc::ENOTEMPTY), - ("ENOBUFS", libc::ENOBUFS), - ("EPROTO", libc::EPROTO), - ("EREMOTE", libc::EREMOTE), - ("ECHILD", libc::ECHILD), - ("ELOOP", libc::ELOOP), - ("EXDEV", libc::EXDEV), - ("E2BIG", libc::E2BIG), - ("ESRCH", libc::ESRCH), - ("EMSGSIZE", libc::EMSGSIZE), - ("EAFNOSUPPORT", libc::EAFNOSUPPORT), - ("EHOSTDOWN", libc::EHOSTDOWN), - ("EPFNOSUPPORT", libc::EPFNOSUPPORT), - ("ENOPROTOOPT", libc::ENOPROTOOPT), - ("EBUSY", libc::EBUSY), - ("EAGAIN", libc::EAGAIN), - ("EISCONN", libc::EISCONN), - ("ESHUTDOWN", libc::ESHUTDOWN), - ("EBADF", libc::EBADF), - ("EMULTIHOP", libc::EMULTIHOP), - ("EIO", libc::EIO), - ("EPROTOTYPE", libc::EPROTOTYPE), - ("ENOSPC", libc::ENOSPC), - ("ENOEXEC", libc::ENOEXEC), - ("EALREADY", libc::EALREADY), - ("ENETDOWN", libc::ENETDOWN), - ("EACCES", libc::EACCES), - ("EILSEQ", libc::EILSEQ), - ("ENOTDIR", libc::ENOTDIR), - ("EPERM", libc::EPERM), - ("EDOM", libc::EDOM), - ("ECONNREFUSED", libc::ECONNREFUSED), - ("EISDIR", libc::EISDIR), - ("EPROTONOSUPPORT", libc::EPROTONOSUPPORT), - ("EROFS", libc::EROFS), - ("EADDRNOTAVAIL", libc::EADDRNOTAVAIL), - ("EIDRM", libc::EIDRM), - ("EBADMSG", libc::EBADMSG), - ("ENFILE", libc::ENFILE), - ("ESPIPE", libc::ESPIPE), - ("ENOLINK", libc::ENOLINK), - ("ENETRESET", libc::ENETRESET), - ("ETIMEDOUT", libc::ETIMEDOUT), - ("ENOENT", libc::ENOENT), - ("EEXIST", libc::EEXIST), - ("EDQUOT", libc::EDQUOT), - ("ENOSTR", libc::ENOSTR), - ("EFAULT", libc::EFAULT), - ("EFBIG", libc::EFBIG), - ("ENOTCONN", libc::ENOTCONN), - ("EDESTADDRREQ", libc::EDESTADDRREQ), - ("ENOLCK", libc::ENOLCK), - ("ECONNABORTED", libc::ECONNABORTED), - ("ENETUNREACH", libc::ENETUNREACH), - ("ESTALE", libc::ESTALE), - ("ENOSR", libc::ENOSR), - ("ENOMEM", libc::ENOMEM), - ("ENOTSOCK", libc::ENOTSOCK), - ("EMLINK", libc::EMLINK), - ("ERANGE", libc::ERANGE), - ("ECONNRESET", libc::ECONNRESET), - ("EADDRINUSE", libc::EADDRINUSE), - #[cfg(not(target_os = "redox"))] - ("ENOTSUP", libc::ENOTSUP), - ("ENAMETOOLONG", libc::ENAMETOOLONG), - ("ENOTTY", libc::ENOTTY), - ("ESOCKTNOSUPPORT", libc::ESOCKTNOSUPPORT), - ("ETIME", libc::ETIME), - ("ETOOMANYREFS", libc::ETOOMANYREFS), - ("EMFILE", libc::EMFILE), - ("ETXTBSY", libc::ETXTBSY), - ("EINPROGRESS", libc::EINPROGRESS), - ("ENXIO", libc::ENXIO), - ("ECANCELED", libc::ECANCELED), - ("EOWNERDEAD", libc::EOWNERDEAD), - ("ENOTRECOVERABLE", libc::ENOTRECOVERABLE), -]; +macro_rules! e { + ($name:ident) => { + (stringify!($name), errors::$name as _) + }; + (cfg($($cfg:tt)*), $name:ident) => { + #[cfg($($cfg)*)] + (stringify!($name), errors::$name as _) + }; +} -#[cfg(windows)] +#[cfg(any(unix, windows))] const ERROR_CODES: &[(&str, i32)] = &[ - ("ENODEV", 19), - ("WSAEHOSTUNREACH", 10065), - ("ENOMSG", 122), - ("ENODATA", 120), - ("ENOSYS", 40), - ("EPIPE", 32), - ("EINVAL", 22), - ("EOVERFLOW", 132), - ("EINTR", 4), - ("WSAEUSERS", 10068), - ("ENOTEMPTY", 41), - ("WSAENOBUFS", 10055), - ("EPROTO", 134), - ("WSAEREMOTE", 10071), - ("ECHILD", 10), - ("WSAELOOP", 10062), - ("EXDEV", 18), - ("E2BIG", 7), - ("ESRCH", 3), - ("WSAEMSGSIZE", 10040), - ("WSAEAFNOSUPPORT", 10047), - ("WSAEHOSTDOWN", 10064), - ("WSAEPFNOSUPPORT", 10046), - ("WSAENOPROTOOPT", 10042), - ("EBUSY", 16), - ("WSAEWOULDBLOCK", 10035), - ("WSAEISCONN", 10056), - ("WSAESHUTDOWN", 10058), - ("EBADF", 9), - ("EIO", 5), - ("WSAEPROTOTYPE", 10041), - ("ENOSPC", 28), - ("ENOEXEC", 8), - ("WSAEALREADY", 10037), - ("WSAENETDOWN", 10050), - ("EACCES", 13), - ("EILSEQ", 42), - ("ENOTDIR", 20), - ("EPERM", 1), - ("EDOM", 33), - ("WSAECONNREFUSED", 10061), - ("EISDIR", 21), - ("WSAEPROTONOSUPPORT", 10043), - ("EROFS", 30), - ("WSAEADDRNOTAVAIL", 10049), - ("EIDRM", 111), - ("EBADMSG", 104), - ("ENFILE", 23), - ("ESPIPE", 29), - ("ENOLINK", 121), - ("WSAENETRESET", 10052), - ("WSAETIMEDOUT", 10060), - ("ENOENT", 2), - ("EEXIST", 17), - ("WSAEDQUOT", 10069), - ("ENOSTR", 125), - ("EFAULT", 14), - ("EFBIG", 27), - ("EDEADLOCK", 36), - ("WSAENOTCONN", 10057), - ("WSAEDESTADDRREQ", 10039), - ("ENOLCK", 39), - ("WSAECONNABORTED", 10053), - ("WSAENETUNREACH", 10051), - ("WSAESTALE", 10070), - ("ENOSR", 124), - ("ENOMEM", 12), - ("WSAENOTSOCK", 10038), - ("EMLINK", 31), - ("ERANGE", 34), - ("WSAECONNRESET", 10054), - ("WSAEADDRINUSE", 10048), - ("WSAEOPNOTSUPP", 10045), - ("EAGAIN", 11), - ("ENAMETOOLONG", 38), - ("ENOTTY", 25), - ("WSAESOCKTNOSUPPORT", 10044), - ("ETIME", 137), - ("WSAETOOMANYREFS", 10059), - ("EMFILE", 24), - ("ETXTBSY", 139), - ("WSAEINPROGRESS", 10036), - ("ENXIO", 6), - ("WSAEMFILE", 10024), - ("WSAVERNOTSUPPORTED", 10092), - ("WSAEPROCLIM", 10067), - ("WSAEFAULT", 10014), - ("WSANOTINITIALISED", 10093), - ("WSAENAMETOOLONG", 10063), - ("WSAENOTEMPTY", 10066), - ("WSAEACCES", 10013), - ("WSABASEERR", 10000), - ("WSAEBADF", 10009), - ("WSAEDISCON", 10101), - ("WSAEINTR", 10004), - ("WSASYSNOTREADY", 10091), - ("WSAEINVAL", 10022), - ("ECANCELED", 105), - ("EOWNERDEAD", 133), - ("ENOTRECOVERABLE", 127), - ("ENOTSUP", 129), + e!(ENODEV), + e!(EHOSTUNREACH), + e!(cfg(not(windows)), ENOMSG), + e!(cfg(not(windows)), ENODATA), + e!(cfg(not(windows)), ENOTBLK), + e!(ENOSYS), + e!(EPIPE), + e!(EINVAL), + e!(cfg(not(windows)), EOVERFLOW), + e!(EINTR), + e!(EUSERS), + e!(ENOTEMPTY), + e!(ENOBUFS), + e!(cfg(not(windows)), EPROTO), + e!(EREMOTE), + e!(ECHILD), + e!(ELOOP), + e!(EXDEV), + e!(E2BIG), + e!(ESRCH), + e!(EMSGSIZE), + e!(EAFNOSUPPORT), + e!(EHOSTDOWN), + e!(EPFNOSUPPORT), + e!(ENOPROTOOPT), + e!(EBUSY), + e!(EAGAIN), + e!(EISCONN), + e!(ESHUTDOWN), + e!(EBADF), + e!(cfg(not(windows)), EMULTIHOP), + e!(EIO), + e!(EPROTOTYPE), + e!(ENOSPC), + e!(ENOEXEC), + e!(EALREADY), + e!(ENETDOWN), + e!(EACCES), + e!(EILSEQ), + e!(ENOTDIR), + e!(EPERM), + e!(EDOM), + e!(ECONNREFUSED), + e!(EISDIR), + e!(EPROTONOSUPPORT), + e!(EROFS), + e!(EADDRNOTAVAIL), + e!(cfg(not(windows)), EIDRM), + e!(cfg(not(windows)), EBADMSG), + e!(ENFILE), + e!(ESPIPE), + e!(cfg(not(windows)), ENOLINK), + e!(ENETRESET), + e!(ETIMEDOUT), + e!(ENOENT), + e!(EEXIST), + e!(EDQUOT), + e!(cfg(not(windows)), ENOSTR), + e!(EFAULT), + e!(EFBIG), + e!(ENOTCONN), + e!(EDESTADDRREQ), + e!(ENOLCK), + e!(ECONNABORTED), + e!(ENETUNREACH), + e!(ESTALE), + e!(cfg(not(windows)), ENOSR), + e!(ENOMEM), + e!(ENOTSOCK), + e!(EMLINK), + e!(ERANGE), + e!(ECONNRESET), + e!(EADDRINUSE), + e!(cfg(not(any(target_os = "redox", windows))), ENOTSUP), + e!(ENAMETOOLONG), + e!(ENOTTY), + e!(ESOCKTNOSUPPORT), + e!(cfg(not(windows)), ETIME), + e!(ETOOMANYREFS), + e!(EMFILE), + e!(cfg(not(windows)), ETXTBSY), + e!(EINPROGRESS), + e!(ENXIO), + e!(ECANCELED), + e!(cfg(not(windows)), EOWNERDEAD), + e!(cfg(not(windows)), ENOTRECOVERABLE), + e!(cfg(windows), WSAEAFNOSUPPORT), + e!(cfg(windows), WSAEHOSTDOWN), + e!(cfg(windows), WSAEPFNOSUPPORT), + e!(cfg(windows), WSAENOPROTOOPT), + e!(cfg(windows), WSAEISCONN), + e!(cfg(windows), WSAESHUTDOWN), + e!(cfg(windows), WSAEINVAL), + e!(cfg(windows), WSAEBADF), + e!(cfg(windows), WSAENAMETOOLONG), + e!(cfg(windows), WSAEPROCLIM), + e!(cfg(windows), WSAEMFILE), + e!(cfg(windows), WSAEINPROGRESS), + e!(cfg(windows), WSAETOOMANYREFS), + e!(cfg(windows), WSAESOCKTNOSUPPORT), + e!(cfg(windows), WSAECONNRESET), + e!(cfg(windows), WSAENOTSOCK), + e!(cfg(windows), WSAECONNABORTED), + e!(cfg(windows), WSAENOTCONN), + e!(cfg(windows), WSAEDQUOT), + e!(cfg(windows), WSAENETRESET), + e!(cfg(windows), WSAEADDRNOTAVAIL), + e!(cfg(windows), WSAEPROTONOSUPPORT), + e!(cfg(windows), WSAECONNREFUSED), + e!(cfg(windows), WSAEALREADY), + e!(cfg(windows), WSAEPROTOTYPE), + e!(cfg(windows), WSAEWOULDBLOCK), + e!(cfg(windows), WSAEMSGSIZE), + e!(cfg(windows), WSAELOOP), + e!(cfg(windows), WSAEREMOTE), + e!(cfg(windows), WSAENOBUFS), + e!(cfg(windows), WSAEUSERS), + e!(cfg(windows), WSAEHOSTUNREACH), + e!(cfg(windows), WSAENETDOWN), + e!(cfg(windows), WSAETIMEDOUT), + e!(cfg(windows), WSAEDESTADDRREQ), + e!(cfg(windows), WSAENETUNREACH), + e!(cfg(windows), WSAESTALE), + e!(cfg(windows), WSAEADDRINUSE), + e!(cfg(windows), WSAEOPNOTSUPP), + e!(cfg(windows), WSAEFAULT), + e!(cfg(windows), WSAENOTEMPTY), + e!(cfg(windows), WSAEACCES), + e!(cfg(windows), WSAEDISCON), + e!(cfg(windows), WSAEINTR), ]; #[cfg(not(any(unix, windows)))] From 5ca0e9a92799eadf7e346507e9b4458b4a0114a3 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Thu, 7 Nov 2019 21:54:42 -0600 Subject: [PATCH 3/7] Add more IO exceptions --- vm/src/builtins.rs | 16 ++++++++++---- vm/src/exceptions.rs | 52 ++++++++++++++++++++++++++++++++++---------- vm/src/stdlib/os.rs | 29 ++++++++++++------------ 3 files changed, 67 insertions(+), 30 deletions(-) diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index c8a8f59446..7acac57e18 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -876,23 +876,31 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef) { "IndexError" => ctx.exceptions.index_error.clone(), "ImportError" => ctx.exceptions.import_error.clone(), "LookupError" => ctx.exceptions.lookup_error.clone(), - "FileNotFoundError" => ctx.exceptions.file_not_found_error.clone(), - "FileExistsError" => ctx.exceptions.file_exists_error.clone(), "StopIteration" => ctx.exceptions.stop_iteration.clone(), "StopAsyncIteration" => ctx.exceptions.stop_async_iteration.clone(), "SystemError" => ctx.exceptions.system_error.clone(), - "PermissionError" => ctx.exceptions.permission_error.clone(), "UnicodeError" => ctx.exceptions.unicode_error.clone(), "UnicodeDecodeError" => ctx.exceptions.unicode_decode_error.clone(), "UnicodeEncodeError" => ctx.exceptions.unicode_encode_error.clone(), "UnicodeTranslateError" => ctx.exceptions.unicode_translate_error.clone(), "ZeroDivisionError" => ctx.exceptions.zero_division_error.clone(), "KeyError" => ctx.exceptions.key_error.clone(), - "OSError" => ctx.exceptions.os_error.clone(), "ModuleNotFoundError" => ctx.exceptions.module_not_found_error.clone(), "EOFError" => ctx.exceptions.eof_error.clone(), "MemoryError" => ctx.exceptions.memory_error.clone(), + "OSError" => ctx.exceptions.os_error.clone(), + "FileNotFoundError" => ctx.exceptions.file_not_found_error.clone(), + "PermissionError" => ctx.exceptions.permission_error.clone(), + "FileExistsError" => ctx.exceptions.file_exists_error.clone(), + "BlockingIOError" => ctx.exceptions.blocking_io_error.clone(), + "InterruptedError" => ctx.exceptions.interrupted_error.clone(), + "ConnectionError" => ctx.exceptions.connection_error.clone(), + "ConnectionResetError" => ctx.exceptions.connection_reset_error.clone(), + "ConnectionRefusedError" => ctx.exceptions.connection_refused_error.clone(), + "ConnectionAbortedError" => ctx.exceptions.connection_aborted_error.clone(), + "BrokenPipeError" => ctx.exceptions.broken_pipe_error.clone(), + // Warnings "Warning" => ctx.exceptions.warning.clone(), "BytesWarning" => ctx.exceptions.bytes_warning.clone(), diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index cc2f5cad3f..9acd8f5602 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -228,8 +228,6 @@ pub struct ExceptionZoo { pub attribute_error: PyClassRef, pub base_exception_type: PyClassRef, pub exception_type: PyClassRef, - pub file_not_found_error: PyClassRef, - pub file_exists_error: PyClassRef, pub import_error: PyClassRef, pub index_error: PyClassRef, pub key_error: PyClassRef, @@ -238,9 +236,7 @@ pub struct ExceptionZoo { pub name_error: PyClassRef, pub not_implemented_error: PyClassRef, pub recursion_error: PyClassRef, - pub os_error: PyClassRef, pub overflow_error: PyClassRef, - pub permission_error: PyClassRef, pub reference_error: PyClassRef, pub runtime_error: PyClassRef, pub stop_iteration: PyClassRef, @@ -259,6 +255,18 @@ pub struct ExceptionZoo { pub eof_error: PyClassRef, pub memory_error: PyClassRef, + pub os_error: PyClassRef, + pub file_not_found_error: PyClassRef, + pub permission_error: PyClassRef, + pub file_exists_error: PyClassRef, + pub blocking_io_error: PyClassRef, + pub interrupted_error: PyClassRef, + pub connection_error: PyClassRef, + pub connection_reset_error: PyClassRef, + pub connection_refused_error: PyClassRef, + pub connection_aborted_error: PyClassRef, + pub broken_pipe_error: PyClassRef, + pub warning: PyClassRef, pub bytes_warning: PyClassRef, pub unicode_warning: PyClassRef, @@ -289,7 +297,6 @@ impl ExceptionZoo { let key_error = create_type("KeyError", &type_type, &exception_type); let lookup_error = create_type("LookupError", &type_type, &exception_type); let name_error = create_type("NameError", &type_type, &exception_type); - let os_error = create_type("OSError", &type_type, &exception_type); let runtime_error = create_type("RuntimeError", &type_type, &exception_type); let reference_error = create_type("ReferenceError", &type_type, &exception_type); let stop_iteration = create_type("StopIteration", &type_type, &exception_type); @@ -303,9 +310,6 @@ impl ExceptionZoo { let module_not_found_error = create_type("ModuleNotFoundError", &type_type, &import_error); let not_implemented_error = create_type("NotImplementedError", &type_type, &runtime_error); let recursion_error = create_type("RecursionError", &type_type, &runtime_error); - let file_not_found_error = create_type("FileNotFoundError", &type_type, &os_error); - let permission_error = create_type("PermissionError", &type_type, &os_error); - let file_exists_error = create_type("FileExistsError", &type_type, &os_error); let eof_error = create_type("EOFError", &type_type, &exception_type); let indentation_error = create_type("IndentationError", &type_type, &syntax_error); let tab_error = create_type("TabError", &type_type, &indentation_error); @@ -316,6 +320,23 @@ impl ExceptionZoo { create_type("UnicodeTranslateError", &type_type, &unicode_error); let memory_error = create_type("MemoryError", &type_type, &exception_type); + // os errors + let os_error = create_type("OSError", &type_type, &exception_type); + + let file_not_found_error = create_type("FileNotFoundError", &type_type, &os_error); + let permission_error = create_type("PermissionError", &type_type, &os_error); + let file_exists_error = create_type("FileExistsError", &type_type, &os_error); + let blocking_io_error = create_type("BlockingIOError", &type_type, &os_error); + let interrupted_error = create_type("InterruptedError", &type_type, &os_error); + let connection_error = create_type("ConnectionError", &type_type, &os_error); + let connection_reset_error = + create_type("ConnectionResetError", &type_type, &connection_error); + let connection_refused_error = + create_type("ConnectionRefusedError", &type_type, &connection_error); + let connection_aborted_error = + create_type("ConnectionAbortedError", &type_type, &connection_error); + let broken_pipe_error = create_type("BrokenPipeError", &type_type, &connection_error); + let warning = create_type("Warning", &type_type, &exception_type); let bytes_warning = create_type("BytesWarning", &type_type, &warning); let unicode_warning = create_type("UnicodeWarning", &type_type, &warning); @@ -339,8 +360,6 @@ impl ExceptionZoo { attribute_error, base_exception_type, exception_type, - file_not_found_error, - file_exists_error, import_error, index_error, key_error, @@ -349,9 +368,7 @@ impl ExceptionZoo { name_error, not_implemented_error, recursion_error, - os_error, overflow_error, - permission_error, runtime_error, stop_iteration, stop_async_iteration, @@ -368,6 +385,17 @@ impl ExceptionZoo { zero_division_error, eof_error, memory_error, + os_error, + file_not_found_error, + permission_error, + file_exists_error, + blocking_io_error, + interrupted_error, + connection_error, + connection_reset_error, + connection_refused_error, + connection_aborted_error, + broken_pipe_error, warning, bytes_warning, unicode_warning, diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 76249e117d..ec01180a41 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -21,6 +21,7 @@ use nix::pty::openpty; #[cfg(unix)] use nix::unistd::{self, Gid, Pid, Uid, Whence}; +use super::errno::errors; use crate::function::{IntoPyNativeFunc, OptionalArg, PyFuncArgs}; use crate::obj::objbytes::PyBytesRef; use crate::obj::objdict::PyDictRef; @@ -152,21 +153,21 @@ pub fn os_open(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn convert_io_error(vm: &VirtualMachine, err: io::Error) -> PyObjectRef { - let os_error = match err.kind() { - ErrorKind::NotFound => { - let exc_type = vm.ctx.exceptions.file_not_found_error.clone(); - vm.new_exception(exc_type, err.to_string()) - } - ErrorKind::PermissionDenied => { - let exc_type = vm.ctx.exceptions.permission_error.clone(); - vm.new_exception(exc_type, err.to_string()) - } - ErrorKind::AlreadyExists => { - let exc_type = vm.ctx.exceptions.file_exists_error.clone(); - vm.new_exception(exc_type, err.to_string()) - } - _ => vm.new_os_error(err.to_string()), + #[allow(unreachable_patterns)] // some errors are just aliases of each other + let exc_type = match err.kind() { + ErrorKind::NotFound => vm.ctx.exceptions.file_not_found_error.clone(), + ErrorKind::PermissionDenied => vm.ctx.exceptions.permission_error.clone(), + ErrorKind::AlreadyExists => vm.ctx.exceptions.file_exists_error.clone(), + ErrorKind::WouldBlock => vm.ctx.exceptions.blocking_io_error.clone(), + _ => match err.raw_os_error() { + Some(errors::EAGAIN) + | Some(errors::EALREADY) + | Some(errors::EWOULDBLOCK) + | Some(errors::EINPROGRESS) => vm.ctx.exceptions.blocking_io_error.clone(), + _ => vm.ctx.exceptions.os_error.clone(), + }, }; + let os_error = vm.new_exception(exc_type, err.to_string()); if let Some(errno) = err.raw_os_error() { vm.set_attr(&os_error, "errno", vm.ctx.new_int(errno)) .unwrap(); From bed54e035cabd9b25373db153304d46fd8de3be7 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Thu, 7 Nov 2019 18:28:18 -0600 Subject: [PATCH 4/7] Add some constants to native modules --- Cargo.lock | 1 + bytecode/src/bytecode.rs | 7 +++++ vm/Cargo.toml | 1 + vm/src/obj/objcode.rs | 5 ++++ vm/src/stdlib/dis.rs | 19 ++++++++++++-- vm/src/stdlib/os.rs | 12 +++++++++ vm/src/stdlib/select.rs | 5 ++++ vm/src/stdlib/socket.rs | 57 +++++++++++++++++++++++++--------------- 8 files changed, 84 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63615acd26..e7b3094651 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1295,6 +1295,7 @@ dependencies = [ "flamer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", "gethostname 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "hexf-parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/bytecode/src/bytecode.rs b/bytecode/src/bytecode.rs index bd166ff8d4..7f84163b75 100644 --- a/bytecode/src/bytecode.rs +++ b/bytecode/src/bytecode.rs @@ -65,6 +65,13 @@ impl Default for CodeFlags { } } +impl CodeFlags { + pub const NAME_MAPPING: &'static [(&'static str, CodeFlags)] = &[ + ("GENERATOR", CodeFlags::IS_GENERATOR), + ("COROUTINE", CodeFlags::IS_COROUTINE), + ]; +} + #[derive(Serialize, Debug, Deserialize, Clone, Copy, PartialEq, Eq, Hash)] pub struct Label(usize); diff --git a/vm/Cargo.toml b/vm/Cargo.toml index f5df633fa1..89a7b8ce9e 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -32,6 +32,7 @@ num-rational = "0.2.2" num-iter = "0.1.39" rand = "0.7" rand_distr = "0.2" +getrandom = "0.1" log = "0.4" rustpython-derive = {path = "../derive", version = "0.1.1"} rustpython-parser = {path = "../parser", optional = true, version = "0.1.1"} diff --git a/vm/src/obj/objcode.rs b/vm/src/obj/objcode.rs index c15fe47f95..23a99fbfdc 100644 --- a/vm/src/obj/objcode.rs +++ b/vm/src/obj/objcode.rs @@ -86,6 +86,10 @@ impl PyCodeRef { fn co_name(self, _vm: &VirtualMachine) -> String { self.code.obj_name.clone() } + + fn co_flags(self, _vm: &VirtualMachine) -> u8 { + self.code.flags.bits() + } } pub fn init(context: &PyContext) { @@ -99,5 +103,6 @@ pub fn init(context: &PyContext) { "co_firstlineno" => context.new_property(PyCodeRef::co_firstlineno), "co_kwonlyargcount" => context.new_property(PyCodeRef::co_kwonlyargcount), "co_name" => context.new_property(PyCodeRef::co_name), + "co_flags" => context.new_property(PyCodeRef::co_flags), }); } diff --git a/vm/src/stdlib/dis.rs b/vm/src/stdlib/dis.rs index 4c35f45e99..8302ef919b 100644 --- a/vm/src/stdlib/dis.rs +++ b/vm/src/stdlib/dis.rs @@ -1,5 +1,6 @@ +use crate::bytecode::CodeFlags; use crate::obj::objcode::PyCodeRef; -use crate::pyobject::{PyObjectRef, PyResult, TryFromObject}; +use crate::pyobject::{ItemProtocol, PyObjectRef, PyResult, TryFromObject}; use crate::vm::VirtualMachine; fn dis_dis(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { @@ -17,11 +18,25 @@ fn dis_disassemble(co: PyObjectRef, vm: &VirtualMachine) -> PyResult { Ok(vm.get_none()) } +fn dis_compiler_flag_names(vm: &VirtualMachine) -> PyObjectRef { + let dict = vm.ctx.new_dict(); + for (name, flag) in CodeFlags::NAME_MAPPING { + dict.set_item( + &vm.ctx.new_int(flag.bits()), + vm.ctx.new_str(name.to_string()), + vm, + ) + .unwrap(); + } + dict.into_object() +} + pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { let ctx = &vm.ctx; py_module!(vm, "dis", { "dis" => ctx.new_rustfunc(dis_dis), - "disassemble" => ctx.new_rustfunc(dis_disassemble) + "disassemble" => ctx.new_rustfunc(dis_disassemble), + "COMPILER_FLAG_NAMES" => dis_compiler_flag_names(vm), }) } diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index ec01180a41..9307b98e56 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -1090,6 +1090,17 @@ pub fn os_ttyname(fd: i32, vm: &VirtualMachine) -> PyResult { } } +fn os_urandom(size: usize, vm: &VirtualMachine) -> PyResult> { + let mut buf = vec![0u8; size]; + match getrandom::getrandom(&mut buf) { + Ok(()) => Ok(buf), + Err(e) => match e.raw_os_error() { + Some(errno) => Err(convert_io_error(vm, io::Error::from_raw_os_error(errno))), + None => Err(vm.new_os_error("Getting random failed".to_string())), + }, + } +} + pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { let ctx = &vm.ctx; @@ -1214,6 +1225,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { "getpid" => ctx.new_rustfunc(os_getpid), "cpu_count" => ctx.new_rustfunc(os_cpu_count), "_exit" => ctx.new_rustfunc(os_exit), + "urandom" => ctx.new_rustfunc(os_urandom), "O_RDONLY" => ctx.new_int(libc::O_RDONLY), "O_WRONLY" => ctx.new_int(libc::O_WRONLY), diff --git a/vm/src/stdlib/select.rs b/vm/src/stdlib/select.rs index c8e81442f9..9da61b4418 100644 --- a/vm/src/stdlib/select.rs +++ b/vm/src/stdlib/select.rs @@ -135,6 +135,11 @@ fn select_select( let (wlist, mut w) = seq2set(&wlist)?; let (xlist, mut x) = seq2set(&xlist)?; + if rlist.is_empty() && wlist.is_empty() && xlist.is_empty() { + let empty = vm.ctx.new_list(vec![]); + return Ok((empty.clone(), empty.clone(), empty)); + } + let nfds = [&mut r, &mut w, &mut x] .iter_mut() .filter_map(|set| set.highest()) diff --git a/vm/src/stdlib/socket.rs b/vm/src/stdlib/socket.rs index 970a05afea..84d88c977e 100644 --- a/vm/src/stdlib/socket.rs +++ b/vm/src/stdlib/socket.rs @@ -7,7 +7,7 @@ use byteorder::{BigEndian, ByteOrder}; use gethostname::gethostname; #[cfg(all(unix, not(target_os = "redox")))] use nix::unistd::sethostname; -use socket2::{Domain, Socket, Type as SocketType}; +use socket2::{Domain, Protocol, Socket, Type as SocketType}; use super::os::convert_io_error; #[cfg(unix)] @@ -27,7 +27,31 @@ type RawSocket = std::os::unix::io::RawFd; type RawSocket = std::os::windows::raw::SOCKET; #[cfg(unix)] -use libc as c; +mod c { + pub use libc::*; + // TODO: open a PR to add these constants to libc; then just use libc + #[cfg(target_os = "android")] + pub const AI_PASSIVE: c_int = 0x00000001; + #[cfg(target_os = "android")] + pub const AI_CANONNAME: c_int = 0x00000002; + #[cfg(target_os = "android")] + pub const AI_NUMERICHOST: c_int = 0x00000004; + #[cfg(target_os = "android")] + pub const AI_NUMERICSERV: c_int = 0x00000008; + #[cfg(target_os = "android")] + pub const AI_MASK: c_int = + AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV | AI_ADDRCONFIG; + #[cfg(target_os = "android")] + pub const AI_ALL: c_int = 0x00000100; + #[cfg(target_os = "android")] + pub const AI_V4MAPPED_CFG: c_int = 0x00000200; + #[cfg(target_os = "android")] + pub const AI_ADDRCONFIG: c_int = 0x00000400; + #[cfg(target_os = "android")] + pub const AI_V4MAPPED: c_int = 0x00000800; + #[cfg(target_os = "android")] + pub const AI_DEFAULT: c_int = AI_V4MAPPED_CFG | AI_ADDRCONFIG; +} #[cfg(windows)] mod c { pub use winapi::shared::ws2def::*; @@ -92,28 +116,17 @@ impl PySocket { unsafe { Socket::from_raw_socket(fileno) } } } else { - let domain = match family { - c::AF_INET => Domain::ipv4(), - c::AF_INET6 => Domain::ipv6(), - #[cfg(unix)] - c::AF_UNIX => Domain::unix(), - _ => { - return Err(vm.new_os_error(format!("Unknown address family value: {}", family))) - } - }; + let sock = Socket::new( + Domain::from(family), + SocketType::from(socket_kind), + Some(Protocol::from(proto)), + ) + .map_err(|err| convert_sock_error(vm, err))?; + self.family.set(family); - let socket_type = match socket_kind { - c::SOCK_STREAM => SocketType::stream(), - c::SOCK_DGRAM => SocketType::dgram(), - _ => { - return Err( - vm.new_os_error(format!("Unknown socket kind value: {}", socket_kind)) - ) - } - }; self.kind.set(socket_kind); self.proto.set(proto); - Socket::new(domain, socket_type, None).map_err(|err| convert_sock_error(vm, err))? + sock }; self.sock.replace(sock); Ok(()) @@ -435,6 +448,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { "error" => ctx.exceptions.os_error.clone(), "timeout" => socket_timeout, "gaierror" => socket_gaierror, + "AF_UNSPEC" => ctx.new_int(0), "AF_INET" => ctx.new_int(c::AF_INET), "AF_INET6" => ctx.new_int(c::AF_INET6), "SOCK_STREAM" => ctx.new_int(c::SOCK_STREAM), @@ -446,6 +460,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { "MSG_PEEK" => ctx.new_int(c::MSG_PEEK), "MSG_WAITALL" => ctx.new_int(c::MSG_WAITALL), "AI_ALL" => ctx.new_int(c::AI_ALL), + "AI_PASSIVE" => ctx.new_int(c::AI_PASSIVE), "socket" => PySocket::make_class(ctx), "inet_aton" => ctx.new_rustfunc(socket_inet_aton), "inet_ntoa" => ctx.new_rustfunc(socket_inet_ntoa), From ae0a343906a94094b3a85271edc08c00641e95d5 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Sat, 16 Nov 2019 23:27:46 -0600 Subject: [PATCH 5/7] Add stub _winapi module --- vm/Cargo.toml | 2 +- vm/src/stdlib/mod.rs | 8 ++++++++ vm/src/stdlib/winapi.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 vm/src/stdlib/winapi.rs diff --git a/vm/Cargo.toml b/vm/Cargo.toml index 89a7b8ce9e..180684567a 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -89,7 +89,7 @@ socket2 = { version = "0.3", features = ["unix"] } [target."cfg(windows)".dependencies.winapi] version = "0.3" -features = ["winsock2", "handleapi", "ws2def", "std"] +features = ["winsock2", "handleapi", "ws2def", "std", "winbase"] [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2" diff --git a/vm/src/stdlib/mod.rs b/vm/src/stdlib/mod.rs index cde43c1b1a..c22c8d157b 100644 --- a/vm/src/stdlib/mod.rs +++ b/vm/src/stdlib/mod.rs @@ -48,6 +48,8 @@ mod select; pub mod signal; #[cfg(not(target_arch = "wasm32"))] mod subprocess; +#[cfg(windows)] +mod winapi; #[cfg(not(target_arch = "wasm32"))] mod zlib; @@ -119,5 +121,11 @@ pub fn get_module_inits() -> HashMap { modules.insert("pwd".to_string(), Box::new(pwd::make_module)); } + // Windows-only + #[cfg(windows)] + { + modules.insert("_winapi".to_string(), Box::new(winapi::make_module)); + } + modules } diff --git a/vm/src/stdlib/winapi.rs b/vm/src/stdlib/winapi.rs new file mode 100644 index 0000000000..10063df3fe --- /dev/null +++ b/vm/src/stdlib/winapi.rs @@ -0,0 +1,29 @@ +use std::io; +use winapi::shared::winerror; +use winapi::um::winnt::HANDLE; +use winapi::um::{handleapi, winbase}; + +use super::os::convert_io_error; +use crate::pyobject::{PyObjectRef, PyResult}; +use crate::VirtualMachine; + +fn winapi_CloseHandle(handle: usize, vm: &VirtualMachine) -> PyResult<()> { + let res = unsafe { handleapi::CloseHandle(handle as HANDLE) }; + if res == 0 { + Err(convert_io_error(vm, io::Error::last_os_error())) + } else { + Ok(()) + } +} + +pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { + let ctx = &vm.ctx; + py_module!(vm, "_winapi", { + "CloseHandle" => ctx.new_rustfunc(winapi_CloseHandle), + "WAIT_OBJECT_0" => ctx.new_int(winbase::WAIT_OBJECT_0), + "WAIT_ABANDONED" => ctx.new_int(winbase::WAIT_ABANDONED), + "WAIT_ABANDONED_0" => ctx.new_int(winbase::WAIT_ABANDONED_0), + "WAIT_TIMEOUT" => ctx.new_int(winerror::WAIT_TIMEOUT), + "INFINITE" => ctx.new_int(winbase::INFINITE), + }) +} From f7831491c50767e0d227f75d58636f357a29d780 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Sat, 16 Nov 2019 23:31:58 -0600 Subject: [PATCH 6/7] Add stub implementation of atexit --- Lib/atexit.py | 9 +++++++++ vm/src/macros.rs | 14 +++++++------- vm/src/obj/objfunction.rs | 15 ++++++++++++++- vm/src/vm.rs | 30 +++++++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 Lib/atexit.py diff --git a/Lib/atexit.py b/Lib/atexit.py new file mode 100644 index 0000000000..c990e82ba2 --- /dev/null +++ b/Lib/atexit.py @@ -0,0 +1,9 @@ +# Dummy implementation of atexit + + +def register(func, *args, **kwargs): + return func + + +def unregister(func): + pass diff --git a/vm/src/macros.rs b/vm/src/macros.rs index 39150b3073..7dca09f4d3 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -116,22 +116,22 @@ macro_rules! no_kwargs { #[macro_export] macro_rules! py_module { - ( $vm:expr, $module_name:expr, { $($name:expr => $value:expr),* $(,)* }) => {{ + ( $vm:expr, $module_name:expr, { $($name:expr => $value:expr),* $(,)? }) => {{ let module = $vm.new_module($module_name, $vm.ctx.new_dict()); - $( - $vm.set_attr(&module, $name, $value).unwrap(); - )* + $crate::extend_module!($vm, module, { $($name => $value),* }); module }}; } #[macro_export] macro_rules! extend_module { - ( $vm:expr, $module:expr, { $($name:expr => $value:expr),* $(,)* }) => { + ( $vm:expr, $module:expr, { $($name:expr => $value:expr),* $(,)? }) => {{ + #[allow(unused_variables)] + let module: &$crate::pyobject::PyObjectRef = &$module; $( - $vm.set_attr(&$module, $name, $value).unwrap(); + $vm.__module_set_attr(&module, $name, $value).unwrap(); )* - } + }}; } #[macro_export] diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index 5742a95536..e780fc3168 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -64,11 +64,24 @@ pub struct PyMethod { // TODO: these shouldn't be public pub object: PyObjectRef, pub function: PyObjectRef, + pub actually_bind: bool, } impl PyMethod { pub fn new(object: PyObjectRef, function: PyObjectRef) -> Self { - PyMethod { object, function } + PyMethod { + object, + function, + actually_bind: true, + } + } + + pub fn new_nobind(object: PyObjectRef, function: PyObjectRef) -> Self { + PyMethod { + object, + function, + actually_bind: false, + } } fn getattribute(&self, name: PyStringRef, vm: &VirtualMachine) -> PyResult { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index f9cac2244b..85f50e8209 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -580,9 +580,15 @@ impl VirtualMachine { } else if let Some(PyMethod { ref function, ref object, + actually_bind, }) = func_ref.payload() { - self.invoke(&function, args.insert(object.clone())) + let args = if *actually_bind { + args.insert(object.clone()) + } else { + args + }; + self.invoke(&function, args) } else if let Some(PyBuiltinFunction { ref value }) = func_ref.payload() { value(self, args) } else if self.is_callable(&func_ref) { @@ -1303,6 +1309,28 @@ impl VirtualMachine { }; Ok(value) } + + #[doc(hidden)] + pub fn __module_set_attr( + &self, + module: &PyObjectRef, + attr_name: impl TryIntoRef, + attr_value: impl Into, + ) -> PyResult<()> { + let val = attr_value.into(); + let val = if val + .class() + .is(&self.ctx.types.builtin_function_or_method_type) + { + PyMethod::new_nobind(module.clone(), val) + .into_ref(self) + .into_object() + } else { + val + }; + self.set_attr(module, attr_name, val)?; + Ok(()) + } } impl Default for VirtualMachine { From 7c3340b6b1be659a05c7aed91797df1866cb141e Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Sun, 17 Nov 2019 00:58:00 -0600 Subject: [PATCH 7/7] Add object.__dict__ = ... test --- tests/snippets/object.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/snippets/object.py b/tests/snippets/object.py index 663a2cd76b..db6a9f6bdc 100644 --- a/tests/snippets/object.py +++ b/tests/snippets/object.py @@ -17,3 +17,8 @@ assert MyObject().__lt__(MyObject()) == NotImplemented assert MyObject().__le__(MyObject()) == NotImplemented assert MyObject().__gt__(MyObject()) == NotImplemented assert MyObject().__ge__(MyObject()) == NotImplemented + +obj = MyObject() +assert not hasattr(obj, 'a') +obj.__dict__ = {'a': 1} +assert obj.a == 1