How to typecast fixed size byte array as struct? - memory

I want to reinterpret a stack allocated byte array as a stack allocated (statically guaranteed) struct without doing any work - just to tell the compiler that "Yes, I promise they are the same size and anything". How do I do that?
I tried transmute, but it doesn't compile.
fn from_u8_fixed_size_array<T>(arr: [u8; size_of::<T>()]) -> T {
unsafe { mem::transmute(arr) }
}
cannot transmute between types of different sizes, or dependently-sized types E0512
Note: source type: `[u8; _]` (this type does not have a fixed size)
Note: target type: `T` (this type does not have a fixed size)
There is also this variant of such a function, that compiles, but it requires T to be Copy:
fn from_u8_fixed_size_array(arr: [u8; size_of::<T>()]) -> T {
unsafe { *(&arr as *const [u8; size_of::<T>()] as *const T) }
}

With Rust 1.64 I have a compilation error on [u8; size_of::<T>()] (cannot perform const operation using T).
I tried with a const generic parameter but the problem is still the same (I cannot introduce a where clause to constrain this constant to match size_of::<T>()).
Since the array is passed by value and the result is a value, some bytes have to be copied ; this implies a kind of memcpy().
I suggest using a slice instead of an array and checking the size at runtime.
If you are ready to deal with undefined behaviour, you might consider the second version which does not copy anything: it just reinterprets the storage as is.
I'm not certain I would do that, however...
Edit
The original code was compiled with nightly and a specific feature.
We can simply use transmute_copy() to get the array by value and emit a value.
And, I think the functions themselves should be qualified with unsafe instead of just some of their operations, because nothing guaranties (statically) that these conversions are correct.
#![feature(generic_const_exprs)] // nightly required
unsafe fn from_u8_slice_v1<T>(arr: &[u8]) -> T {
let mut result = std::mem::MaybeUninit::<T>::uninit();
let src = &arr[0] as *const u8;
let dst = result.as_mut_ptr() as *mut u8;
let count = std::mem::size_of::<T>();
assert_eq!(count, arr.len());
std::ptr::copy_nonoverlapping(src, dst, count);
result.assume_init()
}
unsafe fn from_u8_slice_v2<T>(arr: &[u8]) -> &T {
let size = std::mem::size_of::<T>();
let align = std::mem::align_of::<T>();
assert_eq!(size, arr.len());
let addr = &arr[0] as *const _ as usize;
assert_eq!(addr % align, 0);
&*(addr as *const T) // probably UB
}
unsafe fn from_u8_fixed_size_array<T>(
arr: [u8; std::mem::size_of::<T>()]
) -> T {
std::mem::transmute_copy(&arr)
}
fn main() {
let a = [1, 2];
println!("{:?}", a);
let i1 = unsafe { from_u8_slice_v1::<i16>(&a) };
println!("{:?}", i1);
let i2 = unsafe { from_u8_slice_v2::<i16>(&a) };
println!("{:?}", i2);
let i3 = unsafe { from_u8_fixed_size_array::<i16>(a) };
println!("{:?}", i3);
}
/*
[1, 2]
513
513
513
*/

Related

Parsing an f64 variable into a usize variable in Rust

I have currently been dabbling in the Rust programming language and decided a good way to test my skills was to program an application that would find the median of any given list of numbers.
Eventually I got into the Final stretch of code and stumbled into a problem.
I needed to parse an f64 variable into a usize variable.
However, I don't know how to go about doing this (Wow what a surprise!).
Take a look at the second function, calc_med() in my code. The variable n2 is supposed to take n and parse it into a usize. The code is not finished yet, but if you can see any more problems with the code please let me know.
use std::io;
use std::sync::Mutex;
#[macro_use]
extern crate lazy_static;
lazy_static! {
static ref v1: Mutex<Vec<f64>> = Mutex::new(Vec::new());
}
fn main() {
loop {
println!("Enter: ");
let mut inp: String = String::new();
io::stdin().read_line(&mut inp).expect("Failure");
let upd_inp: f64 = match inp.trim().parse() {
Ok(num) => num,
Err(_) => if inp.trim() == String::from("q") {
break;
} else if inp.trim() == String::from("d"){
break
{
println!("Done!");
calc_med();
}
} else {
continue;
}
};
v1.lock().unwrap().push(upd_inp);
v1.lock().unwrap().sort_by(|a, b| a.partial_cmp(b).unwrap());
println!("{:?}", v1.lock().unwrap());
}
}
fn calc_med() { // FOR STACKOVERFLOW: THIS FUNCTION
let n: f64 = ((v1.lock().unwrap().len()) as f64 + 1.0) / 2.0;
let n2: usize = n.to_usize().expect("Failure");
let median: f64 = v1[n2];
println!("{}", median)
}

Issue with parsing String to Unsigned in Rust language

This is the code I have:
fn main() {
use std::io::stdin;
let mut s=String::new();
stdin().read_line(&mut s).expect("Wrong input");
let n = s.parse::<u32>();
println!("Try: {:?}", n);
}
I get no error while compiling, but it prints this in running time:
Err(ParseIntError { kind: InvalidDigit })
You have a trailing \n in your string, use String::trim_end:
fn main() {
let n = "10\n".trim_end().parse::<u32>();
println!("Try: {:?}", n);
}
From BufRead::read_line documentation:
This function will read bytes from the underlying stream until the
newline delimiter (the 0xA byte) or EOF is found. Once found, all
bytes up to, and including, the delimiter (if found) will be appended
to buf.

How to unsafely increase the size of a mutable slice of bytes?

I have this function:
use std::io;
pub fn recv(mut buf: &mut [u8]) -> io::Result<usize> {
let size_to_extend = 50; // I want to increase the size of "buf" by 50
unsafe {
/* ??? */
}
}
How can I adjust the size of the array buf, even though it's a parameter? It is necessary that this method needs to happen.
What you are attempting to do is all-but-guaranteed to cause undefined behavior. Find a better API.
If you want the changes to be reflected outside of the function, you are out of luck. There's no way that this function signature will allow for that to happen, for the same reason that fn foo(x: i32) won't allow you to change the value passed in as observed by the caller.
If you just need this inside of the function, use slice::from_raw_parts. I've marked the entire function as unsafe because certain inputs will cause undefined behavior and this code cannot possibly guard against it:
use std::slice;
pub unsafe fn recv(buf: &mut [u8]) {
let size_to_extend = 50;
let ptr = buf.as_mut_ptr();
let len = buf.len();
let bad_idea = slice::from_raw_parts_mut(ptr, len + size_to_extend);
for b in bad_idea.iter_mut() {
*b = 10;
}
}
If you can change the API, something like this works to expose the change outside the function:
pub unsafe fn recv(buf: &mut &mut [u8]) {
let size_to_extend = 50;
let ptr = buf.as_mut_ptr();
let len = buf.len();
let bad_idea = slice::from_raw_parts_mut(ptr, len + size_to_extend);
for b in bad_idea.iter_mut() {
*b = 10;
}
*buf = bad_idea;
}
See also:
How can I get an array or a slice from a raw pointer?

How to parse an octal string as a float in Rust?

I need to take an octal string, such as "42.1", and get a float from it (34.125). What's the best way to do this in Rust? I see there previously was a from_str_radix function, but it's now removed.
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseFloatError {
_private: (),
}
impl ParseFloatError {
fn new() -> ParseFloatError {
ParseFloatError { _private: () }
}
}
impl fmt::Display for ParseFloatError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Could not parse float")
}
}
pub fn parse_float_radix(s: &str, radix: u32) -> Result<f64, ParseFloatError> {
let s2 = s.replace(".", "");
let i = i64::from_str_radix(&s2, radix).map_err(|_| ParseFloatError::new())?;
let count = s.split('.').count();
let fraction_len: usize;
match count {
0 => unreachable!(),
1 => fraction_len = 0,
2 => fraction_len = s.split('.').last().unwrap().len(),
_ => return Err(ParseFloatError::new()),
}
let f = (i as f64) / f64::from(radix).powi(fraction_len as i32);
Ok(f)
}
fn main() {
println!("{}", parse_float_radix("42.1", 8).unwrap());
}
It first parses the input as an integer and then divides it by radix^number_of_fractional_digits.
It doesn't support scientific notation or special values like infinity or NaN. It also fails if the intermediate integer overflows.
Since posting this question, a crate has appeared that solves this: lexical. Compiling with the radix feature enables a parse_radix function, which can parse strings into floats with radices from 2 to 36.

Why would the F# compiler check if the newly created array is null?

I am playing around with F# and wanted to check how it generates code compared to C# and found a strange line.
I am using dotTrace to decompile code and make C# equivalent. I have also tried to check IL code using LinqPad.
My code is quite small.
open System
[<EntryPoint>]
let main argv =
let mutable sum = 0
// 1000 or 997
//let arr : int array = Array.zeroCreate 997
//let arr = Enumerable.Range(0, 997).ToArray()
let arr :int array = [|0..997|]
arr |> Array.iter (fun x -> sum <- sum + x)
printfn "%i" sum
0
And this is what I get.
{
int func = 0;
int[] numArray = SeqModule.ToArray<int>(Operators.CreateSequence<int>(Operators.OperatorIntrinsics.RangeInt32(0, 1, 997)));
if ((object) numArray == null)
throw new ArgumentNullException("array");
int length = numArray.Length;
int index = 0;
int num1 = length - 1;
if (num1 >= index)
{
do
{
int num2 = numArray[index];
func += num2;
++index;
}
while (index != num1 + 1);
}
PrintfModule.PrintFormatLineToTextWriter<FSharpFunc<int, Unit>>(Console.Out, (PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit>) new PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit, int>("%i")).Invoke(func);
return 0;
}
}
And this is how IL looks like.
// IL_0019: stloc.1 // 'numArray [Range(Instruction(IL_0019 stloc.1)-Instruction(IL_0040 ldloc.1))]'
// IL_001a: ldloc.1 // 'numArray [Range(Instruction(IL_0019 stloc.1)-Instruction(IL_0040 ldloc.1))]'
// IL_001b: box int32[]
// IL_0020: brfalse.s IL_0025
// IL_0022: nop
// IL_0023: br.s IL_0030
// IL_0025: ldstr "array"
// IL_002a: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string)
// IL_002f: throw
Compiled using Release, .Net 4.6, FSharp.Core 4.4.0.0, Optimize code, Generate Tail Calls.
I am very curious about the NULL check and cast.
(object) numArray == null
I do understand why the obj cast is done. The array is not a null and can't be checked without.
I am curious (don't thinks it is a problem) and the question is more about compiler.
Why would it be useful to check for null? I am not defining an option type.
Under what conditions the exception will fire.
That check is part of the implementation of Array.iter. The compiler just seems not to be smart enough to figure out that box arg in this case is never going to be null.

Resources