These are chat archives for rust-lang/rust

16th
Aug 2018
James McCoy
@jamessan
Aug 16 2018 02:48 UTC
Copy the link from the timestamp on the message
So I have this peace of code
let mut o = v.unwrap();

                unsafe {
                    let c_string = CString::from_raw((*o.ClientDetail).AccountNumber);
                    println!("xxx1111111111: {:?}", c_string);
                }

                //let input = &mut o as *mut ns2__AddressValidationRequest;
                //std::mem::forget(o);


                let soap = unsafe { create_soap() };

                let base_url = "123";

                let mut sr: ns2__AddressValidationReply =
                    unsafe { validate_address(soap, CString::new(base_url).unwrap().as_ptr(), &mut o as *mut ns2__AddressValidationRequest) };
And println!("xxx1111111111: {:?}", c_string); gives me what expected
But then I C, when I want to print printf("2: %s\n", ptr_AddressValidationRequest->ClientDetail->AccountNumber);
It gives me NULL! What could be the trick?
I print also other stuff, and it's wrong. Number with digit 4, show up as 10 etc
Some weird memory games
So that rust says Pointer is good and not null, that means nothing?
Results even change when I add remove some println in rust code. Nightmare
Michal 'vorner' Vaner
@vorner
Aug 16 2018 11:24 UTC
That sounds like UB somewhere. Like, maybe not matching the right signature of the function or like that.
UB stands for what?
Michal 'vorner' Vaner
@vorner
Aug 16 2018 11:26 UTC
Undefined Behaivour
apiraino
@apiraino
Aug 16 2018 11:26 UTC
"Undefined Behaviour" (yes, it took me a while to adjust too to the new lingo)
Signature is matched.
Michal 'vorner' Vaner
@vorner
Aug 16 2018 11:27 UTC
Like, both C and unsafe lets you do things that, if you do it wrong, do weird stuff.
struct ns2__AddressValidationReply validate_address(struct soap *soap, char *base_url, struct ns2__AddressValidationRequest *ptr_AddressValidationRequest)
extern "C" {
    fn validate_address(
        soap: *mut libc::c_void,
        base_url: *const libc::c_char,
        ptr_AddressValidationRequest: *mut ns2__AddressValidationRequest,
    ) -> ns2__AddressValidationReply;
}
Michal 'vorner' Vaner
@vorner
Aug 16 2018 11:28 UTC
Is the API generated by bindgen, or manually?
It worked before. When I was setting ptr_AddressValidationRequest whery satically
Michal 'vorner' Vaner
@vorner
Aug 16 2018 11:28 UTC
Yep, that's what undefined behaviour does. It is allowed to randomly work.
Now I creating it more generic, trough functions
And Boom
Coode looks Fine, when debug in Rust it's fine, and then In C it's dead
Is the API generated by bindgen, or manually?
Bindgen
And what can I do witth this UB :D ?
Hang my self :D ?
Michal 'vorner' Vaner
@vorner
Aug 16 2018 11:41 UTC
Hanging doesn't help. Either reading the code very carefully, asking someone else to read it, looking through it in debugger, or maybe running in something like valgrind, which is often quite helpful pointing out suspicious things
Denis Lisov
@tanriol
Aug 16 2018 11:43 UTC
And keeping the amount of unsafe as low as reasonably possible :-)
Michal 'vorner' Vaner
@vorner
Aug 16 2018 11:43 UTC
Yeh, but you can hardly avoid it if you call FFI.
Ghhh
Felling is that rust frees some memory
Along the process
Denis Lisov
@tanriol
Aug 16 2018 12:16 UTC
@trsh Could you show the whole function?
Also, are all the operations synchronous?
Bottom validate_address call is the start point to look
Code is generated by Macro
again funny part, if I add //println!("TRALALALAAAA"); back, it no segm foult :D
But screwed up results
So TRAALALAAA is making better code :D
I changed c code to printf("2: %d\n", ptr_AddressValidationRequest->ClientDetail->AccountNumber); and ir prints 9, nerveless it's supposed to be a char by headers. And sometimes it is. So it's all bananas
Denis Lisov
@tanriol
Aug 16 2018 12:38 UTC
Looks like you're doing it wrong :-)
Look at your code
        let root_ClientDetail_ov = if ClientDetail.is_some() {
            let mut kk = ClientDetail.unwrap(); 
            &mut kk as *mut ns2__ClientDetail /* This is a pointer to `kk`, which is a temporary on the stack, but you return it from this function */
        } else {
            /* not important */
        };
@tanriol &mut ClientDetail.unwrap() as *mut ns2__ClientDetail
Produces same issue
Denis Lisov
@tanriol
Aug 16 2018 12:47 UTC
Exactly, because ClientDetail.unwrap() produces a temporary either way.
So...
I should put outside of If?
Clone orsmth?
Denis Lisov
@tanriol
Aug 16 2018 12:47 UTC
By the way, did you think about generating more idiomatic Rust code?
@tanriol I had another version, bet some JSONS are really huge
So I had to spilt in fn's
Denis Lisov
@tanriol
Aug 16 2018 12:49 UTC
How about let root_ClientDetail_ov = ClientDetail.as_mut().unwrap_or(ptr::null_mut());?
No, this will not help you as ClientDetail is a temporary itself...
What could help?
Some pointer copy thing i Guess. Looking at docs
Denis Lisov
@tanriol
Aug 16 2018 12:54 UTC
Not so easy.
First, you really need to understand which structure owns the data.
The leafs in the tree?
Denis Lisov
@tanriol
Aug 16 2018 13:02 UTC
Do you ever expect hand-written Rust code to touch this data, or only generated one?
For input not really
Denis Lisov
@tanriol
Aug 16 2018 13:04 UTC
And after that?
I have other macro, that doe's reverse
Pointers to JSON
Its more simple
Denis Lisov
@tanriol
Aug 16 2018 13:07 UTC
So this is supposed to be just a shim between some source of JSON and some C library with no logic in Rust at all?
Well no, Rust is main plan
My framework is on Actix
C i need only for Gsoap
So no big change here in phylosophy, I just need to nail this code
t gets out of the scope, but still the pointer is valid and hold the memory of value
SO i guess &mut t as *mut K when doing this it writes mem. And anything should be fine?
Hoever in my case, also stuff works on Rust side, not on C side anymore
Also rust should cryabout scopes, as there no unsafe flag at this point
Franz Gregor
@fzgregor
Aug 16 2018 13:28 UTC
How can I tell the cc crate to use a different compiler for a certain target? Is there some more elegant way than defining CC and CXX environment variables?
Denis Lisov
@tanriol
Aug 16 2018 13:29 UTC
I'm asking this because in your code I see direct translation between some JSON objects and something with raw pointers, but not actually seeing anything like normal Rust structures with normal ownership for these :-)
@trsh Not "working", but "not yet failing". It may do so randomly :-)
@tanriol ns2__AddressValidationRequestis rust struct
for ex
Duno for what you are aiming, but its classical FFI scenario
Bindgen objects that u need, fill them in rust, and the send to C
Not safe?
However I can not redo all of my work, so @tanriol , please, If you have any advice how to fix that code I pasted, please fill me in. Im off for a while now :)
Denis Lisov
@tanriol
Aug 16 2018 13:39 UTC
@trsh You're telling the compiler you're working with unsafe. It's your job now to know whether this is safe or not :-)
You're doing something like this
You need to box your structures and convert the boxes from/into raw pointers when allocating and deallocating.
This old static code, working > https://pastebin.com/VnqxTqSL
I think I got the Point :/
I actually Use unsafe only for reading
Ok will try the boxes
@tanriol would be very nice, if you do your example with boxes, and working :)))
So I got a kickstart
Michal 'vorner' Vaner
@vorner
Aug 16 2018 13:44 UTC
I haven't read the code. But „seems to be working“ doesn't mean it is correct. The worst thing ever about UB is that it sometimes works, mostly by accident. If you're interested in it, I wrote a blog post about UB (in general, not about this actual problem with referring to already dead struct). https://vorner.github.io/undefined.html
@vorner yeah. @tanriol presented it very well by adding on Redundant println
And it all went to hell
It also behaves different on OS's
There was some thing that gave me 0 headache on UNIX< and then in windows crashed with 100%
Denis Lisov
@tanriol
Aug 16 2018 13:47 UTC
I meant something like this
@tanriol Thanks. As I generate code from Macro, should't be to much Of the work
Box shifts the ownership, as I understand, makes sense
(clap)
Will read about it
Denis Lisov
@tanriol
Aug 16 2018 13:52 UTC
Or, possibly, this
Michal 'vorner' Vaner
@vorner
Aug 16 2018 13:55 UTC
@tanriol Do you leak stuff on purpose?
Denis Lisov
@tanriol
Aug 16 2018 13:56 UTC
Hmm... no, I've just forgotten about the strings. That's why I don't like working with FFI :-)
These are the things a compiler should deal with, not the user :-)
Michal 'vorner' Vaner
@vorner
Aug 16 2018 13:57 UTC
Well, usually, it does. Unless you tell it to get out of your way.
@vorner what do u mean with leak?
Denis Lisov
@tanriol
Aug 16 2018 13:59 UTC
Exactly... but this has to be done for FFI work :-(
Both examples above allocate a CString with CString::new and fail to ever free it...
Where is the leak?
How can I free it?"
Denis Lisov
@tanriol
Aug 16 2018 14:00 UTC
Or possibly...
mem::forget?
Denis Lisov
@tanriol
Aug 16 2018 14:01 UTC
...looks like I'm being wrong again :-)
Michal 'vorner' Vaner
@vorner
Aug 16 2018 14:01 UTC
You probably should implement Drop for that structure.
So the second exmaple isn't leaking?
Denis Lisov
@tanriol
Aug 16 2018 14:02 UTC
Yeah, generating a Drop impl is pretty much the only bulletproof way to do it :-)
Michal 'vorner' Vaner
@vorner
Aug 16 2018 14:03 UTC
It is. CString::new("123").unwrap().into_raw() ‒ this one creates a new CString, but then forgets about the data structure and gives you only a pointer. It is up to you to decide what you do with the pointer.
But you eventually should turn it back to CString with something like from_raw and drop the CString, so it gets freed.
And that part doesn't exist anywhere in the code.
Denis Lisov
@tanriol
Aug 16 2018 14:04 UTC
@vorner Actually, it does exist in the println! invocation, no?
@vorner , @tanriol can you update the example with drop, because Im confused. Can't aford memory leaks
Michal 'vorner' Vaner
@vorner
Aug 16 2018 14:05 UTC
Ah, right, sorry, it does.
here println!("{:?}", unsafe{CString::from_raw((*p).i)});
Michal 'vorner' Vaner
@vorner
Aug 16 2018 14:05 UTC
But then it „damages“ the structure ‒ it is no longer valid to use.
When I do from_raw, before submiting to extern C, it becomes invalid
That I have observed
Michal 'vorner' Vaner
@vorner
Aug 16 2018 14:07 UTC
Well, dropping the CString makes it invalid. If you do from_raw, but save the string around, you're still OK.
But in my case, when I have lot's of structures inside structures, and Cstring pointers inside thouse
How to I free all that after Submiting to C?
Denis Lisov
@tanriol
Aug 16 2018 14:14 UTC
@trsh I'd structure your code roughly like this
Why is calling fn drop
?
Michal 'vorner' Vaner
@vorner
Aug 16 2018 14:16 UTC
Mostly to be explicit about that it happens there and that you actually create the object only to destroy the pointer it takes ownership of.
It would work the same without it, but this way it is more readable
Ah I think I got it