Skip to content

Commit 9598e8c

Browse files
Unify nul errors
Part of #8245 to reduce the amount of work needed to review. I simplified the embedded nul errors by forwarding to the implementations in `vm::exceptions`.
1 parent cc30cd5 commit 9598e8c

15 files changed

Lines changed: 91 additions & 41 deletions

File tree

crates/stdlib/src/grp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ mod grp {
6363
fn getgrnam(name: PyUtf8StrRef, vm: &VirtualMachine) -> PyResult<GroupData> {
6464
let gr_name = name.as_str();
6565
if gr_name.contains('\0') {
66-
return Err(exceptions::cstring_error(vm));
66+
return Err(exceptions::nul_char_error(vm));
6767
}
6868
let group = host_grp::getgrnam(gr_name).map_err(|err| err.into_pyexception(vm))?;
6969
let group = group.ok_or_else(|| {

crates/stdlib/src/multiprocessing.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ mod _multiprocessing {
359359
use rustpython_host_env::multiprocessing::{
360360
self as host_multiprocessing, SemError, TryAcquireStatus, WaitStatus,
361361
};
362+
use rustpython_vm::exceptions;
362363

363364
/// Error type for sem_timedwait operations
364365
#[cfg(target_vendor = "apple")]
@@ -811,7 +812,7 @@ mod _multiprocessing {
811812
let (handle, name) =
812813
SemHandle::create(&args.name, value, args.unlink).map_err(|err| {
813814
if err == SemError::InvalidInput && args.name.contains('\0') {
814-
vm.new_value_error("embedded null character")
815+
exceptions::nul_char_error(vm)
815816
} else {
816817
os_error(vm, err)
817818
}
@@ -835,7 +836,7 @@ mod _multiprocessing {
835836
fn sem_unlink(name: String, vm: &VirtualMachine) -> PyResult<()> {
836837
host_multiprocessing::sem_unlink(&name).map_err(|err| {
837838
if err == SemError::InvalidInput && name.contains('\0') {
838-
vm.new_value_error("embedded null character")
839+
exceptions::nul_char_error(vm)
839840
} else {
840841
os_error(vm, err)
841842
}

crates/stdlib/src/openssl.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,7 +1041,7 @@ mod _ssl {
10411041
fn set_ciphers(&self, cipherlist: PyStrRef, vm: &VirtualMachine) -> PyResult<()> {
10421042
let ciphers: &str = cipherlist.as_ref();
10431043
if ciphers.contains('\0') {
1044-
return Err(exceptions::cstring_error(vm));
1044+
return Err(exceptions::nul_char_error(vm));
10451045
}
10461046
self.builder()
10471047
.set_cipher_list(ciphers)
@@ -1097,12 +1097,12 @@ mod _ssl {
10971097
Either::A(s) => {
10981098
let s: &str = s.as_ref();
10991099
if s.contains('\0') {
1100-
return Err(exceptions::cstring_error(vm));
1100+
return Err(exceptions::nul_char_error(vm));
11011101
}
11021102
s.to_cstring(vm)?
11031103
}
11041104
Either::B(b) => std::ffi::CString::new(b.borrow_buf().to_vec())
1105-
.map_err(|_| exceptions::cstring_error(vm))?,
1105+
.map_err(|_| exceptions::nul_char_error(vm))?,
11061106
};
11071107

11081108
// Find the NID for the curve name using OBJ_sn2nid
@@ -2038,7 +2038,7 @@ mod _ssl {
20382038
));
20392039
}
20402040
if hostname_str.contains('\0') {
2041-
return Err(vm.new_type_error("embedded null character"));
2041+
return Err(exceptions::nul_char_type_error(vm));
20422042
}
20432043
let ip = hostname_str.parse::<core::net::IpAddr>();
20442044
if ip.is_err() {

crates/stdlib/src/ssl.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ mod _ssl {
7070
sync::atomic::{AtomicUsize, Ordering},
7171
time::Duration,
7272
};
73+
use rustpython_vm::exceptions;
7374
use std::{
7475
collections::{HashMap, hash_map::DefaultHasher},
7576
io::BufRead,
@@ -392,7 +393,7 @@ mod _ssl {
392393
// SNI will not be sent for IP addresses
393394

394395
if hostname.contains('\0') {
395-
return Err(vm.new_type_error("embedded null character"));
396+
return Err(exceptions::nul_char_type_error(vm));
396397
}
397398

398399
if hostname.len() > 253 {
@@ -1869,7 +1870,7 @@ mod _ssl {
18691870

18701871
// Check for NULL bytes
18711872
if hostname.contains('\0') {
1872-
return Err(vm.new_type_error("embedded null character"));
1873+
return Err(exceptions::nul_char_error(vm));
18731874
}
18741875

18751876
Some(hostname.to_string())

crates/vm/src/buffer.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::{
33
builtins::{PyBaseExceptionRef, PyBytesRef, PyTuple, PyTupleRef, PyTypeRef},
44
common::{static_cell, str::wchar_t},
55
convert::ToPyObject,
6+
exceptions,
67
function::{ArgBytesLike, ArgIntoBool, ArgIntoFloat},
78
};
89

@@ -282,7 +283,7 @@ impl FormatCode {
282283

283284
// Check for embedded null character
284285
if c == 0 {
285-
return Err("embedded null character".to_owned());
286+
return Err(exceptions::NulError.to_string());
286287
}
287288

288289
// PEP3118: Handle extended format specifiers

crates/vm/src/exceptions.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::{
1515
suggestion::offer_suggestions,
1616
types::{Callable, Constructor, Initializer, Representable},
1717
};
18+
use core::fmt::{self, Display, Formatter};
1819
use crossbeam_utils::atomic::AtomicCell;
1920
use itertools::Itertools;
2021
#[cfg(feature = "host_env")]
@@ -1188,20 +1189,62 @@ impl serde::Serialize for SerializeException<'_, '_> {
11881189
}
11891190
}
11901191

1191-
pub fn cstring_error(vm: &VirtualMachine) -> PyBaseExceptionRef {
1192+
#[derive(Debug)]
1193+
pub struct NulError;
1194+
1195+
impl Display for NulError {
1196+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1197+
write!(f, "embedded null character")
1198+
}
1199+
}
1200+
1201+
pub fn nul_char_error(vm: &VirtualMachine) -> PyBaseExceptionRef {
11921202
vm.new_value_error("embedded null character")
11931203
}
11941204

1205+
pub fn nul_char_type_error(vm: &VirtualMachine) -> PyBaseExceptionRef {
1206+
vm.new_type_error("embedded null character")
1207+
}
1208+
1209+
pub fn nul_byte_error(vm: &VirtualMachine) -> PyBaseExceptionRef {
1210+
vm.new_value_error("embedded null byte")
1211+
}
1212+
11951213
impl ToPyException for alloc::ffi::NulError {
11961214
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
1197-
cstring_error(vm)
1215+
nul_char_error(vm)
1216+
}
1217+
}
1218+
1219+
impl ToPyException for alloc::ffi::FromVecWithNulError {
1220+
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
1221+
nul_char_error(vm)
1222+
}
1223+
}
1224+
1225+
impl ToPyException for core::ffi::FromBytesWithNulError {
1226+
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
1227+
nul_char_error(vm)
1228+
}
1229+
}
1230+
1231+
impl ToPyException for NulError {
1232+
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
1233+
nul_char_error(vm)
11981234
}
11991235
}
12001236

12011237
#[cfg(windows)]
12021238
impl<C> ToPyException for widestring::error::ContainsNul<C> {
12031239
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
1204-
cstring_error(vm)
1240+
nul_char_error(vm)
1241+
}
1242+
}
1243+
1244+
#[cfg(windows)]
1245+
impl ToPyException for widestring::error::MissingNulTerminator {
1246+
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
1247+
vm.new_value_error(self.to_string())
12051248
}
12061249
}
12071250

crates/vm/src/function/fspath.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl FsPath {
4040
if !check_for_nul || memchr::memchr(b'\0', b).is_none() {
4141
Ok(())
4242
} else {
43-
Err(crate::exceptions::cstring_error(vm))
43+
Err(crate::exceptions::nul_char_error(vm))
4444
}
4545
};
4646
let match1 = |obj: PyObjectRef| {

crates/vm/src/stdlib/_codecs.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ mod _codecs {
1313
AsObject, PyObjectRef, PyResult, VirtualMachine,
1414
builtins::{PyStrRef, PyUtf8StrRef},
1515
codecs,
16-
exceptions::cstring_error,
16+
exceptions::nul_char_error,
1717
function::{ArgBytesLike, FuncArgs},
1818
};
1919

@@ -30,7 +30,7 @@ mod _codecs {
3030
#[pyfunction]
3131
fn lookup(encoding: PyUtf8StrRef, vm: &VirtualMachine) -> PyResult {
3232
if encoding.as_str().contains('\0') {
33-
return Err(cstring_error(vm));
33+
return Err(nul_char_error(vm));
3434
}
3535
vm.state
3636
.codec_registry
@@ -106,15 +106,15 @@ mod _codecs {
106106
#[pyfunction]
107107
fn lookup_error(name: PyUtf8StrRef, vm: &VirtualMachine) -> PyResult {
108108
if name.as_str().contains('\0') {
109-
return Err(cstring_error(vm));
109+
return Err(nul_char_error(vm));
110110
}
111111
vm.state.codec_registry.lookup_error(name.as_str(), vm)
112112
}
113113

114114
#[pyfunction]
115115
fn _unregister_error(errors: PyUtf8StrRef, vm: &VirtualMachine) -> PyResult<bool> {
116116
if errors.as_str().contains('\0') {
117-
return Err(cstring_error(vm));
117+
return Err(nul_char_error(vm));
118118
}
119119
vm.state
120120
.codec_registry

crates/vm/src/stdlib/_io.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ mod _io {
132132
},
133133
common::wtf8::{Wtf8, Wtf8Buf},
134134
convert::ToPyObject,
135-
exceptions::cstring_error,
135+
exceptions::nul_char_error,
136136
function::{
137137
ArgBytesLike, ArgIterable, ArgMemoryBuffer, ArgSize, Either, FsPath, FuncArgs,
138138
IntoFuncArgs, OptionalArg, OptionalOption, PySetterValue,
@@ -2855,7 +2855,7 @@ mod _io {
28552855

28562856
fn validate_errors(errors: &PyRef<PyUtf8Str>, vm: &VirtualMachine) -> PyResult<()> {
28572857
if errors.as_str().contains('\0') {
2858-
return Err(cstring_error(vm));
2858+
return Err(nul_char_error(vm));
28592859
}
28602860
vm.state
28612861
.codec_registry
@@ -2896,7 +2896,7 @@ mod _io {
28962896
},
28972897
Some(enc) => {
28982898
if enc.as_str().contains('\0') {
2899-
return Err(cstring_error(vm));
2899+
return Err(nul_char_error(vm));
29002900
}
29012901
enc
29022902
}
@@ -2915,7 +2915,7 @@ mod _io {
29152915
},
29162916
};
29172917
if encoding.as_str().contains('\0') {
2918-
return Err(cstring_error(vm));
2918+
return Err(nul_char_error(vm));
29192919
}
29202920
Ok(encoding)
29212921
}

crates/vm/src/stdlib/nt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ pub(crate) mod module {
552552

553553
// Validate: no null characters in key or value
554554
if key_str.contains('\0') || value_str.contains('\0') {
555-
return Err(vm.new_value_error("embedded null character"));
555+
return Err(exceptions::nul_char_error(vm));
556556
}
557557
// Validate: empty key or '=' in key after position 0
558558
// (search from index 1 because on Windows starting '=' is allowed

0 commit comments

Comments
 (0)