Skip to content

Commit 4645a79

Browse files
committed
Auto merge of #139849 - thaliaarchi:args/zkvm, r=ibraheemdev
Fix `env::ArgsOs` for zkVM The zkVM implementation of `env::ArgsOs` incorrectly reports the full length even after having iterated. Instead, use a range approach which works out to be simpler. Also, implement more iterator methods like the other platforms in #139847. cc `@flaub` `@jbruestle` `@SchmErik`
2 parents 5d1b897 + 0009598 commit 4645a79

File tree

1 file changed

+58
-45
lines changed

1 file changed

+58
-45
lines changed

library/std/src/sys/args/zkvm.rs

Lines changed: 58 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,94 @@
1-
use crate::ffi::OsString;
2-
use crate::fmt;
3-
use crate::sys::os_str;
1+
use crate::ffi::{OsStr, OsString};
2+
use crate::num::NonZero;
3+
use crate::sync::OnceLock;
44
use crate::sys::pal::{WORD_SIZE, abi};
5-
use crate::sys_common::FromInner;
6-
7-
pub struct Args {
8-
i_forward: usize,
9-
i_back: usize,
10-
count: usize,
11-
}
5+
use crate::{fmt, ptr, slice};
126

137
pub fn args() -> Args {
14-
let count = unsafe { abi::sys_argc() };
15-
Args { i_forward: 0, i_back: 0, count }
8+
Args { iter: ARGS.get_or_init(|| get_args()).iter() }
169
}
1710

18-
impl Args {
19-
/// Use sys_argv to get the arg at the requested index. Does not check that i is less than argc
20-
/// and will not return if the index is out of bounds.
21-
fn argv(i: usize) -> OsString {
22-
let arg_len = unsafe { abi::sys_argv(crate::ptr::null_mut(), 0, i) };
11+
fn get_args() -> Vec<&'static OsStr> {
12+
let argc = unsafe { abi::sys_argc() };
13+
let mut args = Vec::with_capacity(argc);
14+
15+
for i in 0..argc {
16+
// Get the size of the argument then the data.
17+
let arg_len = unsafe { abi::sys_argv(ptr::null_mut(), 0, i) };
2318

2419
let arg_len_words = (arg_len + WORD_SIZE - 1) / WORD_SIZE;
2520
let words = unsafe { abi::sys_alloc_words(arg_len_words) };
2621

2722
let arg_len2 = unsafe { abi::sys_argv(words, arg_len_words, i) };
2823
debug_assert_eq!(arg_len, arg_len2);
2924

30-
// Convert to OsString.
31-
//
32-
// FIXME: We can probably get rid of the extra copy here if we
33-
// reimplement "os_str" instead of just using the generic unix
34-
// "os_str".
35-
let arg_bytes: &[u8] =
36-
unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, arg_len) };
37-
OsString::from_inner(os_str::Buf { inner: arg_bytes.to_vec() })
25+
let arg_bytes = unsafe { slice::from_raw_parts(words.cast(), arg_len) };
26+
args.push(unsafe { OsStr::from_encoded_bytes_unchecked(arg_bytes) });
3827
}
28+
args
3929
}
4030

31+
static ARGS: OnceLock<Vec<&'static OsStr>> = OnceLock::new();
32+
33+
pub struct Args {
34+
iter: slice::Iter<'static, &'static OsStr>,
35+
}
36+
37+
impl !Send for Args {}
38+
impl !Sync for Args {}
39+
4140
impl fmt::Debug for Args {
4241
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43-
f.debug_list().finish()
42+
self.iter.as_slice().fmt(f)
4443
}
4544
}
4645

4746
impl Iterator for Args {
4847
type Item = OsString;
4948

5049
fn next(&mut self) -> Option<OsString> {
51-
if self.i_forward >= self.count - self.i_back {
52-
None
53-
} else {
54-
let arg = Self::argv(self.i_forward);
55-
self.i_forward += 1;
56-
Some(arg)
57-
}
50+
self.iter.next().map(|arg| arg.to_os_string())
5851
}
5952

53+
#[inline]
6054
fn size_hint(&self) -> (usize, Option<usize>) {
61-
(self.count, Some(self.count))
55+
self.iter.size_hint()
6256
}
63-
}
6457

65-
impl ExactSizeIterator for Args {
66-
fn len(&self) -> usize {
67-
self.count
58+
#[inline]
59+
fn count(self) -> usize {
60+
self.iter.len()
61+
}
62+
63+
fn last(self) -> Option<OsString> {
64+
self.iter.last().map(|arg| arg.to_os_string())
65+
}
66+
67+
#[inline]
68+
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
69+
self.iter.advance_by(n)
6870
}
6971
}
7072

7173
impl DoubleEndedIterator for Args {
7274
fn next_back(&mut self) -> Option<OsString> {
73-
if self.i_back >= self.count - self.i_forward {
74-
None
75-
} else {
76-
let arg = Self::argv(self.count - 1 - self.i_back);
77-
self.i_back += 1;
78-
Some(arg)
79-
}
75+
self.iter.next_back().map(|arg| arg.to_os_string())
76+
}
77+
78+
#[inline]
79+
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
80+
self.iter.advance_back_by(n)
81+
}
82+
}
83+
84+
impl ExactSizeIterator for Args {
85+
#[inline]
86+
fn len(&self) -> usize {
87+
self.iter.len()
88+
}
89+
90+
#[inline]
91+
fn is_empty(&self) -> bool {
92+
self.iter.is_empty()
8093
}
8194
}

0 commit comments

Comments
 (0)