Some libc functions, e.g. sigemptyset(set: *mut sigset_t) take a pointer to a variable, treat it as uninitialized and initialize it.
I end up with this code:
let mut newmask = std::mem::uninitialized();
libc::sigemptyset(&mut newmask);
This is ok, but when I have many of those variables I end up with something like this:
let mut newmask = std::mem::uninitialized();
let mut oldmask = std::mem::uninitialized();
let mut pendmask = std::mem::uninitialized();
I could condense it:
use std::mem::unitialized as uninit;
let (mut newmask, mut oldmask, mut pendmask) = (uninit(), uninit(), uninit());
Is there a nicer way to write this code? For educational purposes I explicitly want to use libc.
Luckily, tuples are normal types, too. So how about:
let (mut newmask, mut oldmask, mut pendmask) = std::mem::uninitialized();
However, it won't get much nicer than this. Your best bet is to combine all your variables into a bigger type (like a tuple or a struct) and un-initialize that.
But it's fine that unsafe things are verbose and annoying to write. Uninitialized variables are really quite dangerous, especially when dealing with Drop types. I am sure you are already aware, but I still want to make sure everyone reads the documentation of uninitialized() to understand all possible pitfalls.
Related
I am a bit confused about how to transfer ownership without the overhead of actual data copy.
I have the following code. I am referring to underlying data copy by OS as memcopy.
fn main() {
let v1 = Vec::from([1; 1024]);
take_ownership_but_memcopies(v1);
let v2 = Vec::from([2; 1024]);
dont_memecopy_but_dont_take_ownership(&v2);
let v3 = Vec::from([3; 1024]);
take_ownership_dont_memcopy(???);
}
// Moves but memcopies all elements
fn take_ownership_but_memcopies(my_vec1: Vec<i32>) {
println!("{:?}", my_vec1);
}
// Doesn't memcopy but doesn't take ownership
fn dont_memecopy_but_dont_take_ownership(my_vec2: &Vec<i32>) {
println!("{:?}", my_vec2);
}
// Take ownership without the overhead of memcopy
fn take_ownership_dont_memcopy(myvec3: ???) {
println!("{:?}", my_vec3);
}
As i understand, if i use reference like v2, i don't get the ownership. If i use it like v1, there could be a memcopy.
How should i need to transfer v3 to guarantee that there is no underlying memcopy by OS?
Your understanding of what happens when you move a Vec is incorrect - it does not copy every element within the Vec!
To understand why, we need to take a step back and look at how a Vec is represented internally:
// This is slightly simplified, look at the source for more details!
struct Vec<T> {
pointer: *mut T, // pointer to the data (on the heap)
capacity: usize, // the current capacity of the Vec
len: usize, // the current number of elements in the Vec
}
While the Vec conceptually 'owns' the elements, they are not stored within the Vec struct - it only holds a pointer to that data. So when you move a Vec, it is only the pointer (plus the capacity and length) that gets copied.
If you are attempting to avoid copying altogether, as opposed to avoiding copying the contents of the Vec, that isn't really possible - in the semantics of the compiler, a move is a copy (just one that prevents you from using the old data afterwards). However, the compiler can and will optimize trivial copies into something more efficient.
How should i need to transfer v3 to guarantee that there is no underlying memcopy by OS?
You can't. Because that's Rust's semantics.
However a Vec is just 3 words on the stack, that's all which gets "memcopy"d, which is intrinsic, it's not like you're going to get a memcpy function call in there or duplicate the entire vector. And that's assuming the function call does not get inlined, and the compiler does not decide to pass in object as a reference anyway. It could also pass all 3 words through registers, at which point there's nothing to memcpy.
Though it's not entirely clear why you care either way, if you only want to read from the collection your function should be
// Take ownership without the overhead of memcopy
fn take_ownership_dont_memcopy(myvec3: &[i32]) {
println!("{:?}", my_vec3);
}
that is the most efficient and flexible signature: it's just two words, there's a single pointer (unlike &Vec), and it allows for non-Vec sources.
I've written a wrapper for a camera library in Rust that commands and operates a camera, and also saves an image to file using bindgen. Once I command an exposure to start (basically telling the camera to take an image), I can grab the image using a function of the form:
pub fn GetQHYCCDSingleFrame(
handle: *mut qhyccd_handle,
w: *mut u32,
...,
imgdata: &mut [u8],) -> u32 //(u32 is a retval)
In C++, this function was:
uint32_t STDCALL GetQHYCCDSingleFrame(qhyccd_handle: *handle, ..., uint8_t *imgdata)
In C++, I could pass in a buffer of the form imgdata = new unsigned char[length_buffer] and the function would fill the buffer with image data from the camera.
In Rust, similarly, I can pass in a buffer in the form of a Vec: let mut buffer: Vec<u8> = Vec::with_capacity(length_buffer).
Currently, the way I have structured the code is that there is a main struct, with settings such as the width and height of image, the camera handle, and others, including the image buffer. The struct has been initialized as a mut as:
let mut main_settings = MainSettings {
width: 9600,
...,
buffer: Vec::with_capacity(length_buffer),
}
There is a separate function I wrote that takes the main struct as a parameter and calls the GetQHYCCDSingleFrame function:
fn grab_image(main_settings: &mut MainSettings) {
let retval = unsafe { GetQHYCCDSingleFrame(main_settings.cam_handle, ..., &mut main_settings.image_buffer) };
}
Immediately after calling this function, if I check the length and capacity of main_settings.image_buffer:
println!("Elements in buffer are {}, capacity of buffer is {}.", main_settings.image_buffer.len(), main_settings.image_buffer.capacity());
I get 0 for length, and the buffer_length as the capacity. Similarly, printing any index such as main_settings.image_buffer[0] or 1 leads to a panic exit saying len is 0.
This would make me think that the GetQHYCCDSingleFrame code is not working properly, however, when I save the image_buffer to file using fitsio and hdu.write_region (fitsio docs linked here), I use:
let ranges = [&(x_start..(x_start + roi_width)), &(y_start..(y_start+roi_height))];
hdu.write_region(&mut fits_file, &ranges, &main_settings.image_buffer).expect("Could not write to fits file");
This saves an actual image to file with the right size and is a perfectly fine image (exactly what it would look if I took using the C++ program). However, when I try to print the buffer, for some reason is empty, yet the hdu.write_region code is able to access data somehow.
Currently, my (not good) workaround is to create another vector that reads data from the saved file and saves to a buffer, which then has the right number of elements:
main_settings.new_buffer = hdu.read_region(&mut fits_file, &ranges).expect("Couldn't read fits file");
Why can I not access the original buffer at all, and why does it report length 0, when the hdu.write_region function can access data from somewhere? And where exactly is it accessing the data from, and how can correctly I access it as well? I am bit new to borrowing and referencing, so I believe I might be doing something wrong in borrowing/referencing the buffer, or is it something else?
Sorry for the long story, but the details would probably be important for everything here. Thanks!
Well, first of all, you need to know that Vec<u8> and &mut [u8] are not quite the same as C or C++'s uint8_t *. The main difference is that Vec<u8> and &mut [u8] have the size of the array or slice saved within themselves, while uint8_t * doesn't. The Rust equivalent to C/C++ pointers are raw pointers, like *mut [u8]. Raw pointers are safe to build, but requires unsafe to be used. However, even tho they are different types, a smart pointer as &mut [u8] can be casted to a raw pointer without issue AFAIK.
Secondly, the capacity of a Vec is different of its size. Indeed, to have good performances, a Vec allocates more memory than you use, to avoid reallocating on each new element added into vector. The length however is the size of the used part. In your case, you ask the Vec to allocate a heap space of length length_buffer, but you don't tell them to consider any of the allocated space to be used, so the initial length is 0. Since C++ doesn't know about Vec and only use a raw pointer, it can't change the length written inside the Vec, that stays at 0. Thus the panicking.
To resolve it, I see multiple solutions:
Changing the Vec::with_capacity(length_buffer) into vec![0; length_buffer], explicilty asking to have a length of length_buffer from the start
Using unsafe code to explicitly set the length of the Vec without touching what is inside (using Vec::from_raw_parts). This might be faster than the first solution, but I'm not sure.
Using a Box<[u8; length_buffer]>, which is like a Vec but without reallocation and with the length that is the capacity
If your length_buffer is constant at compile time, using a [u8; length_buffer] would be much more efficient as no allocation is needed, but it comes with downsides, as you probably know
I am updating some old code and I am now getting errors: ERROR: setfield! immutable struct cannot be changed in Julia when I try to change the values of an immutable struct. Is there a common workaround for how I can edit/mutate those values (this may be a rather silly question given that the type is explicitly immutable so it's not a good idea generally to try and change it).
As far as I remember immutables can not be safely manipulated even if you get a memory pointer to them and try to use ccal.
However, as an imperfect workaround you can consider using Setfield package as in the example below.
using Setfield
struct S
a::Int
b::String
end
Using:
julia> s = S(2, "hello")
S(2, "hello")
julia> s = #set s.a = 5
S(5, "hello")
Note that in many scenarios this might be faster than actually changing type of S to mutable.
I just started developing a frama-c plugin that is doing some kind of alias analysis. I'm using the Dataflow.Backwards analysis and now I have to go through the different assignment statements and collect some stuff about the lvalues.
Does frama-c provide me with 3-address code? Do I have some guarantees about the shape of the lvalue (or any memory access)? I mean, sth like in soot or wala that there is at most one field access, s.t., for a->b->c, there would be a temp variable like tmp=a->b; tmp->c;? I checked the manuals, but I couldn't find anything related to this.
No, there is no such normalization in Frama-C. If you really need it, you can first use a visitor in order to normalize the code so that it suits the requirements of your plug-in. It'd go like that:
class normalize prj: Visitor.frama_c_visitor =
object
inherit Visitor.frama_c_copy prj
method vinstr i =
match i with
| Set (lv,e) -> ...
....
end
let analyze () = ...
let run () =
let my_prj = File.create_project_from_visitor "my_project" (fun prj -> new normalize prj) in
Project.on my_prj analyze ()
The following module from Cil does probably what you want:
http://www.cs.berkeley.edu/~necula/cil/ext.html#toc26. Be aware that the type of the resulting AST is the standard Cil one. You won't be getting any help from the OCaml compiler as to which constructs can be present in the simplified AST, and which ones cannot.
Note also that this module has not been ported to Frama-C so far. You will need some minor adaptation to make it work within Frama-C.
I wrote the following two functions:
let requestAsync qry = dispatcher.PostAndAsyncReply (fun chan -> Query (qry chan))
let request qry = qry |> requestAsync |> Async.RunSynchronously
Now I was wondering if I would have any incentive to writing request like this instead:
let request qry = dispatcher.PostAndReply (fun chan -> Query(qry chan))
I wasn't able to decompile the two implementations and as such, I don't know if the second one might be more efficient or whatnot.
The code is at
https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/control.fs
though not exactly perspicuous... I don't think there's much difference; I would call PostAndReply, but they're both doing roughly the same thing and I would not expect a significant difference. (As always, if you care deeply, then measure for your exact scenario.)