I have a string parsing function using regex: fn parse(s: &str) -> Option<MyObj>. It works when testing with parse("test string"). But failed when using Args. The failure is that the regex could not matching anything from s.
The way I used Args is: args().map(|arg| parse(&arg)).collect(). I could not see type error here. And println in parse shows s is the same string as "test string".
Updated my description. I am not sure if my problem is related with how String and str are different. Because I was using str and it still failed.
extern crate regex;
use regex::Regex;
use std::env::args;
struct IPRange {
start: u32,
mask: u8,
}
fn parse_iprange(ipr: &str) -> Option<IPRange> {
let parser = Regex::new(
r"^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/(\d+|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$",
)
.unwrap();
let caps = parser.captures(ipr).unwrap();
return Some(IPRange { start: 0, mask: 0 });
}
fn main() {
let v: Vec<_> = args().map(|arg| parse_iprange(&arg)).collect();
}
$ RUST_BACKTRACE=1 cargo run 192.168.3.1/24
Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Running `target/debug/ip_helper 192.168.3.1/24`
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:345:21
stack backtrace:
0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
at src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:39
1: std::sys_common::backtrace::_print
at src/libstd/sys_common/backtrace.rs:70
2: std::panicking::default_hook::{{closure}}
at src/libstd/sys_common/backtrace.rs:58
at src/libstd/panicking.rs:200
3: std::panicking::default_hook
at src/libstd/panicking.rs:215
4: std::panicking::rust_panic_with_hook
at src/libstd/panicking.rs:478
5: std::panicking::continue_panic_fmt
at src/libstd/panicking.rs:385
6: rust_begin_unwind
at src/libstd/panicking.rs:312
7: core::panicking::panic_fmt
at src/libcore/panicking.rs:85
8: core::panicking::panic
at src/libcore/panicking.rs:49
9: <core::option::Option<T>>::unwrap
at /rustc/2aa4c46cfdd726e97360c2734835aa3515e8c858/src/libcore/macros.rs:10
10: ip_helper::parse_iprange
at src/main.rs:18
The first item of args() is implementation behavior:
The first element is traditionally the path of the executable, but it can be set to arbitrary text, and may not even exist. This means this property should not be relied upon for security purposes.
So, you should skip it in your case:
let v: Vec<_> = args().skip(1).map(|arg| parse_iprange(&arg)).collect();
Related
I'm trying to generate a random number in a Near smart contract using Rust. However when I run this code:
pub fn get_last(&self) -> u64 {
let mut rng = rand::thread_rng();
println!("i32: {}, i32: {}", rng.gen::<i32>(), rng.gen::<i32>());
return self.lastval;
}
I've got this error message:
$ near view $ID get_last '{}'
View call: dev-1643558356736-93385541578458.get_last({})
An error occured
Error: Querying [object Object] failed: wasm execution failed with error: FunctionCallError(HostError(GuestPanic { panic_msg: "panicked at 'internal error: entered unreachable code', C:\\Users\\GANSOR-PC\\.cargo\\registry\\src\\github.com-1ecc6299db9ec823\\rand-0.4.6\\src\\jitter.rs:703:9" })).
----------------
jitter.rs:703:9
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub fn get_nstime() -> u64 {
unreachable!()
}
in lib.rs I have:
use rand::{thread_rng, Rng};
extern crate rand;
And in Cargo.toml I have:
[dependencies]
near-sdk = "3.1.0"
near-contract-standards = "3.1.1"
rand = "*"
So, where am I wrong?
you can't use a typical random number generator since you are running inside of a virtual machine with no access to typical random seed generators like hardware clock or other machine data
instead consider using the provided random seed you can get through a couple of functions exposed on env like env::random_seed https://github.com/near/near-sdk-rs/blob/master/near-sdk/src/environment/env.rs#L236-L254
/// Returns the random seed from the current block. This 32 byte hash is based on the VRF value from
/// the block. This value is not modified in any way each time this function is called within the
/// same method/block.
pub fn random_seed() -> Vec<u8> {
random_seed_array().to_vec()
}
/// Returns the random seed from the current block. This 32 byte hash is based on the VRF value from
/// the block. This value is not modified in any way each time this function is called within the
/// same method/block.
pub fn random_seed_array() -> [u8; 32] {
//* SAFETY: random_seed syscall will always generate 32 bytes inside of the atomic op register
//* so the read will have a sufficient buffer of 32, and can transmute from uninit
//* because all bytes are filled. This assumes a valid random_seed implementation.
unsafe {
sys::random_seed(ATOMIC_OP_REGISTER);
read_register_fixed_32(ATOMIC_OP_REGISTER)
}
}
here's an example
https://github.com/near-apps/coin-flip/blob/1476bbdf0fee3b6647766ee6e94e40254f728191/contracts/src/lib.rs#L50-L59
pub fn play(&mut self) -> u8 {
let account_id = env::signer_account_id();
let mut credits = self.credits.get(&account_id).unwrap_or(0);
assert!(credits > 0, "no credits to play");
credits = credits - ONE_NEAR;
let rand: u8 = *env::random_seed().get(0).unwrap();
if rand < PROB {
credits = credits + 10 * ONE_NEAR;
}
self.credits.insert(&account_id, &credits);
rand
}
Let's say I have a struct as follows:
struct Abc {
a: i32,
b: fn(i32) -> bool
}
where a is just a stored value and b is a user-supplied closure that checks some condition upon a. If the condition evaluates to false at some point, I want to panic! and print some debug information about what went wrong.
For example, if I set b to be |x| x < 10, it's fairly easy to assert upon result of b(a), but if the assertion fails the output looks something like:
panicked at 'assertion failed: (self.b)(self.a)'
which isn't very helpful. What I'd like to be able to print is something like:
panicked at 'Abc condiditon failed: x < 10'
Basically, is there some way to get the 'text' of some code for debug message purposes? Getting it just as a string is enough, I don't need anything easily parseable. I suspect it'll involve some macro trickery if it's possible at all, but I wouldn't know where to begin.
While the original code is not normally preserved in the binary in Rust, you can indeed build this using a macro:
struct LambdaAndText(fn(i32) -> bool, &'static str);
impl LambdaAndText {
fn call(&self, arg: i32) {
assert!((self.0)(arg), "Abc condiditon failed: {}", self.1);
}
}
macro_rules! lambda_and_text {
(|$p:pat| $e:expr) => {
LambdaAndText(|$p| $e, stringify!($e))
};
}
fn main() {
let l = lambda_and_text!(|x| x < 10);
l.call(5);
l.call(42);
}
This prints thread 'main' panicked at 'Abc condiditon failed: x < 10', src/main.rs:5:9 as expected.
I am trying to write a rustdoc test of a method called insert.
The testing function is called in the last line of the test, and when I comment it out the test passes just fine.
Error message:
$ cargo test
Compiling reproduce v0.1.0
(file:///home/user/reproduce)
Finished dev [unoptimized + debuginfo] target(s) in 2.03s
Running target/debug/deps/reproduce-17ad4bb50aa9c47e
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Doc-tests reproduce
running 1 test
test src/lib.rs - MyStruct::method (line 19) ... FAILED
failures:
failures:
src/lib.rs - MyStruct::method (line 19)
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
error: test failed, to rerun pass '--doc'
Code:
impl MyStruct {
pub fn new(lsb: u8, step: usize) -> MyStruct {
let mask: u8 = match lsb {
1 => 0b0000_0001,
2 => 0b0000_0011,
_ => 0b0000_1111
};
MyStruct { lsb, mask, step }
}
/// # Examples
/// ```
/// extern crate reproduce;
/// extern crate rgb;
///
/// use std::slice;
/// use rgb::RGB;
///
/// let msg = "This is a secret message".as_bytes();
/// let img = vec![RGB {r: 0, g: 0, b: 0}; 800*500];
///
/// // Create a reference to the bytes of img
/// let p: *const Vec<RGB<u8>> = &img;
/// let p: *const u8 = p as *const u8;
/// let p: &[u8] = unsafe {
/// slice::from_raw_parts(p, 3*800*500)
/// };
///
/// let settings = reproduce::MyStruct::new(2, 12);
/// let new_data = settings.method(p, &msg);
/// ```
pub fn method(&self, img: &[u8], msg: &[u8]) -> Vec<u8> {
let mut ret = img.to_vec();
let mut n = 0;
for ch in msg.iter() {
for i in 1..=8/self.lsb {
let shift = (self.lsb*i) as u32;
ret[n] = (ret[n] & !self.mask) |
(ch & self.mask.rotate_right(shift)).rotate_left(shift);
n += self.step;
}
}
ret
}
}
Could it be that there are special rules for a rustdoc test to pass (for example the use of assert! macro to prove that it returns a proper value)?
I am asking because my method passes integration test with very similar code, so I am pretty confident it's correct
This has nothing to do with the fact that it's running in a rustdoc test. Your code is exhibiting Undefined Behaviour because it is unsound. Running the same code outside of a test also panics for me.
You are making assumptions about how memory is laid out - assumptions that are in no way backed up by any compiler guarantees. A "correct" way to get the pointer would be this:
let p = img.as_ptr() as *const u8;
However, while this removes the assumption on how the Vec is laid out, the rest of the code is still assuming the layout of RGB. This change stops it panicking for me, but I can't be sure that it is working correctly and I can't know if it will break on some other computer, or on mine after the next Rust update.
I am asking because my method passes integration test with very similar code, so I am pretty confident it's correct
This is exactly the danger of Undefined Behaviour, and it's why unsafe should be used only in code that is not only well tested but also where the assumptions and guarantees are well understood.
Is there a way to make the user prompt for the bytes inside brackets and separated by commas or something similar?
./main bytes [0, 1, 2, 3, 4, 5]
I managed to make it look like this:
./main bytes 0 1 2 3 4 5
This is my code:
extern crate docopt;
#[macro_use]
extern crate serde_derive;
use docopt::Docopt;
const USAGE: &'static str = "
Puzzle Solver.
Usage:
puzzle_solver string <text>
puzzle_solver bytes [<bin>...]
puzzle_solver (-h | --help)
puzzle_solver --version
Options:
-h --help Show this screen.
--version Show version.
";
#[derive(Debug, Deserialize)]
struct Args {
cmd_string: bool,
arg_text: Option<String>,
cmd_bytes: bool,
arg_bin: Option<Vec<u8>>,
}
fn main() {
let args: Args = Docopt::new(USAGE)
.and_then(|d| d.deserialize())
.unwrap_or_else(|e| e.exit());
println!("ARGS: {:?}", args);
}
It's possible, but you have to implement Deserialize by hand.
Vec<u8> already implements Deserialize, and that implementation doesn't know about strings containing comma-delimited bracketed lists, nor does docopt::Deserializer, since the normal way to pass a list on the command line is element-by-element. So you have to make a new type that will deserialize from the format you want.
Naturally, you can also implement Deref<Target = Vec<u8>> and DerefMut for Bytes, if you want to treat it as a Vec<u8>. Some people might consider this a slight misuse of Deref, but it's probably fine in a situation like this.
extern crate docopt;
extern crate serde;
#[macro_use]
extern crate serde_derive;
use docopt::Docopt;
use serde::de;
use std::fmt;
const USAGE: &'static str = "
Puzzle Solver.
Usage:
puzzle_solver string <text>
puzzle_solver bytes <bin>
puzzle_solver (-h | --help)
puzzle_solver --version
Options:
-h --help Show this screen.
--version Show version.
";
#[derive(Debug, Deserialize)]
struct Args {
cmd_string: bool,
arg_text: Option<String>,
cmd_bytes: bool,
arg_bin: Option<Bytes>,
}
#[derive(Debug)]
struct Bytes(Vec<u8>);
impl<'de> de::Deserialize<'de> for Bytes {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct BytesVisitor;
impl<'de> de::Visitor<'de> for BytesVisitor {
type Value = Bytes;
fn expecting(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(formatter, "a bracketed, comma-delimited string")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
let v = if v.starts_with('[') && v.ends_with(']') {
&v[1..v.len() - 1]
} else {
return Err(E::custom(format!("expected a bracketed list, got {:?}", v)));
};
let values: Result<Vec<u8>, _> = v.split(",").map(|s| s.trim().parse()).collect();
Ok(Bytes(values.map_err(E::custom)?))
}
}
deserializer.deserialize_str(BytesVisitor)
}
}
Here it is in the playground. These are the changes I made to get this to work:
Replace [<bin>...] with <bin> so docopt will know to look for a single thing and not a sequence of... things. (If you don't do this, docopt actually just throws you an empty string.)
Introduce the newtype Bytes wrapper around Vec<u8>.
Implement serde::de::Deserialize for Bytes. This entails creating a struct that implements the serde::de::Visitor trait, putting the code that picks apart the string inside its visit_str method, and passing the visitor to deserialize_str, which tells the Deserializer to expect a string and pass it to the visitor's visit_str.
I didn't realize it until almost done, but you could implement visit_seq instead, and make it parse bytes [1, 2, 3] (without quoting the list). But I wouldn't, because that defies command line convention; if you're using the shell to split the arguments anyway, you should go the whole way and just accept bytes 1 2 3.
When I use rustc 1.rs to compile the following code, it runs endlessly as expected.
use std::thread;
fn main() {
thread::spawn(|| {
let a = 2;
loop {
a*a;
}
}).join();
}
A shorter version:
use std::thread;
fn main() {
thread::spawn(|| {
loop {}
}).join();
}
However, if I use rustc -O 1.rs to compile two programs above, they crash:
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 0, message: "Success" } }', src/libcore/result.rs:837
stack backtrace:
1: 0x5650bd0acada - std::sys::imp::backtrace::tracing::imp::write::h917062bce4ff48c3
at /build/rustc-1.14.0+dfsg1/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:42
2: 0x5650bd0b068f - std::panicking::default_hook::{{closure}}::h0bacac31b5ed1870
at /build/rustc-1.14.0+dfsg1/src/libstd/panicking.rs:247
3: 0x5650bd0aee7c - std::panicking::default_hook::h5897799da33ece67
at /build/rustc-1.14.0+dfsg1/src/libstd/panicking.rs:263
4: 0x5650bd0af4d7 - std::panicking::rust_panic_with_hook::h109e116a3a861224
at /build/rustc-1.14.0+dfsg1/src/libstd/panicking.rs:451
5: 0x5650bd0af364 - std::panicking::begin_panic::hbb38be1379e09df0
at /build/rustc-1.14.0+dfsg1/src/libstd/panicking.rs:413
6: 0x5650bd0af289 - std::panicking::begin_panic_fmt::h26713cea9bce3ab0
at /build/rustc-1.14.0+dfsg1/src/libstd/panicking.rs:397
7: 0x5650bd0af217 - rust_begin_unwind
at /build/rustc-1.14.0+dfsg1/src/libstd/panicking.rs:373
8: 0x5650bd0e2f3d - core::panicking::panic_fmt::hcfbb59eeb7f27f75
at /build/rustc-1.14.0+dfsg1/src/libcore/panicking.rs:69
9: 0x5650bd0a6e84 - core::result::unwrap_failed::h15a0fc826f4081f4
10: 0x5650bd0b7ffa - __rust_maybe_catch_panic
at /build/rustc-1.14.0+dfsg1/src/libpanic_unwind/lib.rs:97
11: 0x5650bd0a6fc1 - <F as alloc::boxed::FnBox<A>>::call_box::he32a93ebea7bc7ad
12: 0x5650bd0ae6c4 - std::sys::imp::thread::Thread::new::thread_start::ha102a6120fc52763
at /build/rustc-1.14.0+dfsg1/src/liballoc/boxed.rs:605
at /build/rustc-1.14.0+dfsg1/src/libstd/sys_common/thread.rs:21
at /build/rustc-1.14.0+dfsg1/src/libstd/sys/unix/thread.rs:84
13: 0x7fc2d0042423 - start_thread
14: 0x7fc2cfb6e9be - __clone
15: 0x0 - <unknown>
If I remove all code in the closure, it exits with no error:
use std::thread;
fn main() {
thread::spawn(|| {
}).join();
}
If I add println!() in the loop, it works well too:
use std::thread;
fn main() {
thread::spawn(|| {
loop {
println!("123")
}
}).join();
}
I tested this on Rust 1.14 and 1.15, the same problem appears in both.
Is this because I'm using something wrong or is it a bug?
This is a known issue (#28728). In short, LLVM optimizes away loops that have no observable side-effects:
The implementation may assume that any thread will eventually do one
of the following:
terminate
make a call to a library I/O function
access or modify a volatile object, or
perform a synchronization operation or an atomic operation
In the cases here, none of these hold, so LLVM removes the loop entirely. However, the Rust compiler has generated code that assumes the loop never returns. This mismatch causes the crash.
Since having an infinite loop with no side-effects is basically useless, this issue is not of critical priority. The Rust team is currently waiting for LLVM to provide a better solution.
As a workaround, you should simply do something inside the loop, which is likely what you want to do anyway ^_^