Skip to content
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
2 changes: 1 addition & 1 deletion crates/common/src/lock/cell_lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ unsafe impl RawRwLock for RawCellRwLock {

#[inline]
unsafe fn unlock_shared(&self) {
self.state.set(self.state.get() - ONE_READER)
self.state.update(|x| x - ONE_READER)
}

#[inline]
Expand Down
10 changes: 7 additions & 3 deletions crates/compiler-core/src/marshal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,17 @@ impl Read for &[u8] {
fn read_slice(&mut self, n: u32) -> Result<&[u8]> {
self.read_slice_borrow(n)
}

fn read_array<const N: usize>(&mut self) -> Result<&[u8; N]> {
let (chunk, rest) = self.split_first_chunk::<N>().ok_or(MarshalError::Eof)?;
*self = rest;
Ok(chunk)
}
}

impl<'a> ReadBorrowed<'a> for &'a [u8] {
fn read_slice_borrow(&mut self, n: u32) -> Result<&'a [u8]> {
let data = self.get(..n as usize).ok_or(MarshalError::Eof)?;
*self = &self[n as usize..];
Ok(data)
self.split_off(..n as usize).ok_or(MarshalError::Eof)
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/codecs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ impl<'a> DecodeErrorHandler<PyDecodeContext<'a>> for SurrogatePass {
let p = &s[byte_range.start..];

fn slice<const N: usize>(p: &[u8]) -> Option<[u8; N]> {
p.get(..N).map(|x| x.try_into().unwrap())
p.first_chunk().copied()
}

let c = match standard_encoding {
Expand Down
27 changes: 11 additions & 16 deletions crates/vm/src/stdlib/ctypes/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -712,27 +712,22 @@ impl PyCArray {
}
Some("f") => {
// c_float
if offset + 4 <= buffer.len() {
let bytes: [u8; 4] = buffer[offset..offset + 4].try_into().unwrap();
let val = f32::from_ne_bytes(bytes);
Ok(vm.ctx.new_float(val as f64).into())
} else {
Ok(vm.ctx.new_float(0.0).into())
}
let val = buffer[offset..]
.first_chunk::<4>()
.copied()
.map_or(0.0, f32::from_ne_bytes);
Ok(vm.ctx.new_float(val as f64).into())
}
Some("d") | Some("g") => {
// c_double / c_longdouble - read f64 from first 8 bytes
if offset + 8 <= buffer.len() {
let bytes: [u8; 8] = buffer[offset..offset + 8].try_into().unwrap();
let val = f64::from_ne_bytes(bytes);
Ok(vm.ctx.new_float(val).into())
} else {
Ok(vm.ctx.new_float(0.0).into())
}
let val = buffer[offset..]
.first_chunk::<8>()
.copied()
.map_or(0.0, f64::from_ne_bytes);
Ok(vm.ctx.new_float(val).into())
}
_ => {
if offset + element_size <= buffer.len() {
let bytes = &buffer[offset..offset + element_size];
if let Some(bytes) = buffer[offset..].get(..element_size) {
Ok(Self::bytes_to_int(bytes, element_size, type_code, vm))
} else {
Ok(vm.ctx.new_int(0).into())
Expand Down
73 changes: 25 additions & 48 deletions crates/vm/src/stdlib/ctypes/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1836,71 +1836,53 @@ pub(super) fn buffer_to_ffi_value(type_code: &str, buffer: &[u8]) -> FfiArgValue
FfiArgValue::U8(v)
}
"h" => {
let v = if buffer.len() >= 2 {
i16::from_ne_bytes(buffer[..2].try_into().unwrap())
} else {
0
};
let v = buffer.first_chunk().copied().map_or(0, i16::from_ne_bytes);
FfiArgValue::I16(v)
}
"H" => {
let v = if buffer.len() >= 2 {
u16::from_ne_bytes(buffer[..2].try_into().unwrap())
} else {
0
};
let v = buffer.first_chunk().copied().map_or(0, u16::from_ne_bytes);
FfiArgValue::U16(v)
}
"i" => {
let v = if buffer.len() >= 4 {
i32::from_ne_bytes(buffer[..4].try_into().unwrap())
} else {
0
};
let v = buffer.first_chunk().copied().map_or(0, i32::from_ne_bytes);
FfiArgValue::I32(v)
}
"I" => {
let v = if buffer.len() >= 4 {
u32::from_ne_bytes(buffer[..4].try_into().unwrap())
} else {
0
};
let v = buffer.first_chunk().copied().map_or(0, u32::from_ne_bytes);
FfiArgValue::U32(v)
}
"l" | "q" => {
let v = if buffer.len() >= 8 {
i64::from_ne_bytes(buffer[..8].try_into().unwrap())
} else if buffer.len() >= 4 {
i32::from_ne_bytes(buffer[..4].try_into().unwrap()) as i64
let v = if let Some(&bytes) = buffer.first_chunk::<8>() {
i64::from_ne_bytes(bytes)
} else if let Some(&bytes) = buffer.first_chunk::<4>() {
i32::from_ne_bytes(bytes).into()
} else {
0
};
FfiArgValue::I64(v)
}
"L" | "Q" => {
let v = if buffer.len() >= 8 {
u64::from_ne_bytes(buffer[..8].try_into().unwrap())
} else if buffer.len() >= 4 {
u32::from_ne_bytes(buffer[..4].try_into().unwrap()) as u64
let v = if let Some(&bytes) = buffer.first_chunk::<8>() {
u64::from_ne_bytes(bytes)
} else if let Some(&bytes) = buffer.first_chunk::<4>() {
u32::from_ne_bytes(bytes).into()
} else {
0
};
FfiArgValue::U64(v)
}
"f" => {
let v = if buffer.len() >= 4 {
f32::from_ne_bytes(buffer[..4].try_into().unwrap())
} else {
0.0
};
let v = buffer
.first_chunk::<4>()
.copied()
.map_or(0.0, f32::from_ne_bytes);
FfiArgValue::F32(v)
}
"d" | "g" => {
let v = if buffer.len() >= 8 {
f64::from_ne_bytes(buffer[..8].try_into().unwrap())
} else {
0.0
};
let v = buffer
.first_chunk::<8>()
.copied()
.map_or(0.0, f64::from_ne_bytes);
FfiArgValue::F64(v)
}
"z" | "Z" | "P" | "O" => FfiArgValue::Pointer(read_ptr_from_buffer(buffer)),
Expand All @@ -1910,11 +1892,7 @@ pub(super) fn buffer_to_ffi_value(type_code: &str, buffer: &[u8]) -> FfiArgValue
}
"u" => {
// wchar_t - 4 bytes on most platforms
let v = if buffer.len() >= 4 {
u32::from_ne_bytes(buffer[..4].try_into().unwrap())
} else {
0
};
let v = buffer.first_chunk().copied().map_or(0, u32::from_ne_bytes);
FfiArgValue::U32(v)
}
_ => FfiArgValue::Pointer(0),
Expand Down Expand Up @@ -2135,11 +2113,10 @@ pub(super) fn get_usize_attr(
#[inline]
pub(super) fn read_ptr_from_buffer(buffer: &[u8]) -> usize {
const PTR_SIZE: usize = core::mem::size_of::<usize>();
if buffer.len() >= PTR_SIZE {
usize::from_ne_bytes(buffer[..PTR_SIZE].try_into().unwrap())
} else {
0
}
buffer
.first_chunk::<PTR_SIZE>()
.copied()
.map_or(0, usize::from_ne_bytes)
}

/// Check if a type is a "simple instance" (direct subclass of a simple type)
Expand Down
6 changes: 2 additions & 4 deletions crates/vm/src/stdlib/ctypes/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -567,10 +567,8 @@ fn extract_ptr_from_arg(arg: &PyObject, vm: &VirtualMachine) -> PyResult<usize>
}
if let Some(simple) = arg.downcast_ref::<PyCSimple>() {
let buffer = simple.0.buffer.read();
if buffer.len() >= core::mem::size_of::<usize>() {
return Ok(usize::from_ne_bytes(
buffer[..core::mem::size_of::<usize>()].try_into().unwrap(),
));
if let Some(&bytes) = buffer.first_chunk::<{ size_of::<usize>() }>() {
return Ok(usize::from_ne_bytes(bytes));
}
Comment on lines +570 to 572
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unqualified size_of will cause a compilation error.

size_of is not imported and needs to be fully qualified. The rest of the file uses core::mem::size_of consistently (e.g., lines 138, 145, 157, 502).

🐛 Proposed fix
-        if let Some(&bytes) = buffer.first_chunk::<{ size_of::<usize>() }>() {
+        if let Some(&bytes) = buffer.first_chunk::<{ core::mem::size_of::<usize>() }>() {
             return Ok(usize::from_ne_bytes(bytes));
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if let Some(&bytes) = buffer.first_chunk::<{ size_of::<usize>() }>() {
return Ok(usize::from_ne_bytes(bytes));
}
if let Some(&bytes) = buffer.first_chunk::<{ core::mem::size_of::<usize>() }>() {
return Ok(usize::from_ne_bytes(bytes));
}
🤖 Prompt for AI Agents
In `@crates/vm/src/stdlib/ctypes/function.rs` around lines 570 - 572, The call to
buffer.first_chunk::<{ size_of::<usize>() }>() uses an unqualified size_of and
will fail to compile; update that generic const to use the fully qualified
core::mem::size_of (or add a use) so it becomes buffer.first_chunk::<{
core::mem::size_of::<usize>() }>() and ensure the surrounding code that returns
usize::from_ne_bytes(bytes) remains unchanged.

}
if let Some(cdata) = arg.downcast_ref::<PyCData>() {
Expand Down
101 changes: 37 additions & 64 deletions crates/vm/src/stdlib/ctypes/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,13 +419,10 @@ impl PyCSimpleType {
if let Some(funcptr) = value.downcast_ref::<PyCFuncPtr>() {
let ptr_val = {
let buffer = funcptr._base.buffer.read();
if buffer.len() >= core::mem::size_of::<usize>() {
usize::from_ne_bytes(
buffer[..core::mem::size_of::<usize>()].try_into().unwrap(),
)
} else {
0
}
buffer
.first_chunk::<{ size_of::<usize>() }>()
.copied()
.map_or(0, usize::from_ne_bytes)
};
return Ok(CArgObject {
tag: b'P',
Expand All @@ -442,13 +439,10 @@ impl PyCSimpleType {
if matches!(value_type_code.as_deref(), Some("z") | Some("Z")) {
let ptr_val = {
let buffer = simple.0.buffer.read();
if buffer.len() >= core::mem::size_of::<usize>() {
usize::from_ne_bytes(
buffer[..core::mem::size_of::<usize>()].try_into().unwrap(),
)
} else {
0
}
buffer
.first_chunk::<{ size_of::<usize>() }>()
.copied()
.map_or(0, usize::from_ne_bytes)
};
return Ok(CArgObject {
tag: b'Z',
Expand Down Expand Up @@ -1360,68 +1354,47 @@ impl PyCSimple {
let buffer = self.0.buffer.read();
let bytes: &[u8] = &buffer;

if core::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u8().as_raw_ptr()) {
if !bytes.is_empty() {
return Some(FfiArgValue::U8(bytes[0]));
}
let ret = if core::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u8().as_raw_ptr()) {
let byte = *bytes.first()?;
FfiArgValue::U8(byte)
} else if core::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::i8().as_raw_ptr()) {
if !bytes.is_empty() {
return Some(FfiArgValue::I8(bytes[0] as i8));
}
let byte = *bytes.first()?;
FfiArgValue::I8(byte as i8)
} else if core::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u16().as_raw_ptr()) {
if bytes.len() >= 2 {
return Some(FfiArgValue::U16(u16::from_ne_bytes([bytes[0], bytes[1]])));
}
let bytes = *bytes.first_chunk::<2>()?;
FfiArgValue::U16(u16::from_ne_bytes(bytes))
} else if core::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::i16().as_raw_ptr()) {
if bytes.len() >= 2 {
return Some(FfiArgValue::I16(i16::from_ne_bytes([bytes[0], bytes[1]])));
}
let bytes = *bytes.first_chunk::<2>()?;
FfiArgValue::I16(i16::from_ne_bytes(bytes))
} else if core::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u32().as_raw_ptr()) {
if bytes.len() >= 4 {
return Some(FfiArgValue::U32(u32::from_ne_bytes([
bytes[0], bytes[1], bytes[2], bytes[3],
])));
}
let bytes = *bytes.first_chunk::<4>()?;
FfiArgValue::U32(u32::from_ne_bytes(bytes))
} else if core::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::i32().as_raw_ptr()) {
if bytes.len() >= 4 {
return Some(FfiArgValue::I32(i32::from_ne_bytes([
bytes[0], bytes[1], bytes[2], bytes[3],
])));
}
let bytes = *bytes.first_chunk::<4>()?;
FfiArgValue::I32(i32::from_ne_bytes(bytes))
} else if core::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::u64().as_raw_ptr()) {
if bytes.len() >= 8 {
return Some(FfiArgValue::U64(u64::from_ne_bytes([
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
])));
}
let bytes = *bytes.first_chunk::<8>()?;
FfiArgValue::U64(u64::from_ne_bytes(bytes))
} else if core::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::i64().as_raw_ptr()) {
if bytes.len() >= 8 {
return Some(FfiArgValue::I64(i64::from_ne_bytes([
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
])));
}
let bytes = *bytes.first_chunk::<8>()?;
FfiArgValue::I64(i64::from_ne_bytes(bytes))
} else if core::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::f32().as_raw_ptr()) {
if bytes.len() >= 4 {
return Some(FfiArgValue::F32(f32::from_ne_bytes([
bytes[0], bytes[1], bytes[2], bytes[3],
])));
}
let bytes = *bytes.first_chunk::<4>()?;
FfiArgValue::F32(f32::from_ne_bytes(bytes))
} else if core::ptr::eq(ty.as_raw_ptr(), libffi::middle::Type::f64().as_raw_ptr()) {
if bytes.len() >= 8 {
return Some(FfiArgValue::F64(f64::from_ne_bytes([
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
])));
}
let bytes = *bytes.first_chunk::<8>()?;
FfiArgValue::F64(f64::from_ne_bytes(bytes))
} else if core::ptr::eq(
ty.as_raw_ptr(),
libffi::middle::Type::pointer().as_raw_ptr(),
) && bytes.len() >= core::mem::size_of::<usize>()
{
let val =
usize::from_ne_bytes(bytes[..core::mem::size_of::<usize>()].try_into().unwrap());
return Some(FfiArgValue::Pointer(val));
}
None
) {
let bytes = *buffer.first_chunk::<{ size_of::<usize>() }>()?;
let val = usize::from_ne_bytes(bytes);
FfiArgValue::Pointer(val)
} else {
return None;
};
Some(ret)
}
}

Expand Down
12 changes: 4 additions & 8 deletions crates/vm/src/stdlib/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2506,15 +2506,11 @@ mod _io {
return None;
}
buf.resize(Self::BYTE_LEN, 0);
let buf: &[u8; Self::BYTE_LEN] = buf.as_slice().try_into().unwrap();
let buf: &[u8; Self::BYTE_LEN] = buf.as_array()?;
macro_rules! get_field {
($t:ty, $off:ident) => {{
<$t>::from_ne_bytes(
buf[Self::$off..][..core::mem::size_of::<$t>()]
.try_into()
.unwrap(),
)
}};
($t:ty, $off:ident) => {
<$t>::from_ne_bytes(*buf[Self::$off..].first_chunk().unwrap())
};
Comment on lines +2509 to +2513
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -name "Cargo.toml" -type f | head -20

Repository: RustPython/RustPython

Length of output: 639


🏁 Script executed:

cat Cargo.toml | grep -A 5 -B 5 "rust-version\|package.version"

Repository: RustPython/RustPython

Length of output: 700


🏁 Script executed:

find . -name "rust-toolchain*" -type f

Repository: RustPython/RustPython

Length of output: 86


🏁 Script executed:

rg -n "rust-version" --type toml

Repository: RustPython/RustPython

Length of output: 1141


🏁 Script executed:

cat rust-toolchain.toml

Repository: RustPython/RustPython

Length of output: 95


🏁 Script executed:

rg -n "as_array|first_chunk" crates/vm/src/stdlib/io.rs -B 3 -A 3

Repository: RustPython/RustPython

Length of output: 480


🏁 Script executed:

cd crates/vm && cargo clippy --lib 2>&1 | head -100

Repository: RustPython/RustPython

Length of output: 204


🏁 Script executed:

cd crates/vm && cargo fmt -- --check 2>&1 | grep -A 5 "io.rs"

Repository: RustPython/RustPython

Length of output: 47


🌐 Web query:

as_array() first_chunk() Rust stabilization version 1.76 1.77

💡 Result:

  • first_chunk() (and related first_chunk_mut, split_first_chunk, etc.) was stabilized in Rust 1.77.0. [1]
  • as_array() (and as_mut_array()) is not from 1.76/1.77; slice::as_array was stabilized much later, in Rust 1.93.0. [2]

Sources: [1] [2]


MSRV and API compatibility confirmed; ensure linting and formatting checks are clean.

The repository's MSRV (1.93.0) supports both slice APIs: as_array() was stabilized in Rust 1.93.0, and first_chunk() in Rust 1.77.0. No toolchain compatibility issues.

Per coding guidelines, run cargo fmt and cargo clippy to verify formatting and linting are clean before submission.

🤖 Prompt for AI Agents
In `@crates/vm/src/stdlib/io.rs` around lines 2509 - 2513, Confirm formatting and
linting are clean: run cargo fmt and cargo clippy, and ensure the slice APIs
used in get_field (the as_array() call on buf, the first_chunk() usage, and the
BYTE_LEN constant on the type implementing this method) are correct per MSRV
1.93.0; if clippy flags any style or safety issues around the macro get_field or
the unchecked unwrap() on first_chunk(), address them (e.g., handle the Option
instead of unwrap or add a clear comment/expect) so the build and lint checks
pass.

}
Some(Self {
start_pos: get_field!(Offset, START_POS_OFF),
Expand Down
22 changes: 10 additions & 12 deletions crates/vm/src/stdlib/winreg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -905,20 +905,18 @@ mod winreg {
match typ {
REG_DWORD => {
// If there isn’t enough data, return 0.
if ret_data.len() < std::mem::size_of::<u32>() {
Ok(vm.ctx.new_int(0).into())
} else {
let val = u32::from_ne_bytes(ret_data[..4].try_into().unwrap());
Ok(vm.ctx.new_int(val).into())
}
let val = ret_data
.first_chunk::<4>()
.copied()
.map_or(0, u32::from_ne_bytes);
Ok(vm.ctx.new_int(val).into())
}
REG_QWORD => {
if ret_data.len() < std::mem::size_of::<u64>() {
Ok(vm.ctx.new_int(0).into())
} else {
let val = u64::from_ne_bytes(ret_data[..8].try_into().unwrap());
Ok(vm.ctx.new_int(val).into())
}
let val = ret_data
.first_chunk::<8>()
.copied()
.map_or(0, u64::from_ne_bytes);
Ok(vm.ctx.new_int(val).into())
}
REG_SZ | REG_EXPAND_SZ => {
let u16_slice = bytes_as_wide_slice(ret_data);
Expand Down
Loading
Loading