These are chat archives for rust-lang/rust

16th
Aug 2018
James McCoy
@jamessan
Aug 16 2018 02:48
Copy the link from the timestamp on the message
trsh
@trsh
Aug 16 2018 10:28
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
trsh
@trsh
Aug 16 2018 11:10
So that rust says Pointer is good and not null, that means nothing?
trsh
@trsh
Aug 16 2018 11:19
Results even change when I add remove some println in rust code. Nightmare
Michal 'vorner' Vaner
@vorner
Aug 16 2018 11:24
That sounds like UB somewhere. Like, maybe not matching the right signature of the function or like that.
trsh
@trsh
Aug 16 2018 11:25
UB stands for what?
Michal 'vorner' Vaner
@vorner
Aug 16 2018 11:26
Undefined Behaivour
apiraino
@apiraino
Aug 16 2018 11:26
"Undefined Behaviour" (yes, it took me a while to adjust too to the new lingo)
trsh
@trsh
Aug 16 2018 11:26
Signature is matched.
Michal 'vorner' Vaner
@vorner
Aug 16 2018 11:27
Like, both C and unsafe lets you do things that, if you do it wrong, do weird stuff.
trsh
@trsh
Aug 16 2018 11:27
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
Is the API generated by bindgen, or manually?
trsh
@trsh
Aug 16 2018 11:28
It worked before. When I was setting ptr_AddressValidationRequest whery satically
Michal 'vorner' Vaner
@vorner
Aug 16 2018 11:28
Yep, that's what undefined behaviour does. It is allowed to randomly work.
trsh
@trsh
Aug 16 2018 11:28
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
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
And keeping the amount of unsafe as low as reasonably possible :-)
Michal 'vorner' Vaner
@vorner
Aug 16 2018 11:43
Yeh, but you can hardly avoid it if you call FFI.
trsh
@trsh
Aug 16 2018 12:14
Ghhh
Felling is that rust frees some memory
Along the process
Denis Lisov
@tanriol
Aug 16 2018 12:16
@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
trsh
@trsh
Aug 16 2018 12:36
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
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 */
        };
trsh
@trsh
Aug 16 2018 12:46
@tanriol &mut ClientDetail.unwrap() as *mut ns2__ClientDetail
Produces same issue
Denis Lisov
@tanriol
Aug 16 2018 12:47
Exactly, because ClientDetail.unwrap() produces a temporary either way.
trsh
@trsh
Aug 16 2018 12:47
So...
I should put outside of If?
Clone orsmth?
Denis Lisov
@tanriol
Aug 16 2018 12:47
By the way, did you think about generating more idiomatic Rust code?
trsh
@trsh
Aug 16 2018 12:48
@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
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...
trsh
@trsh
Aug 16 2018 12:52
What could help?
Some pointer copy thing i Guess. Looking at docs
Denis Lisov
@tanriol
Aug 16 2018 12:54
Not so easy.
First, you really need to understand which structure owns the data.
trsh
@trsh
Aug 16 2018 12:57
The leafs in the tree?
Denis Lisov
@tanriol
Aug 16 2018 13:02
Do you ever expect hand-written Rust code to touch this data, or only generated one?
trsh
@trsh
Aug 16 2018 13:04
For input not really
Denis Lisov
@tanriol
Aug 16 2018 13:04
And after that?
trsh
@trsh
Aug 16 2018 13:04
I have other macro, that doe's reverse
Pointers to JSON
Its more simple
Denis Lisov
@tanriol
Aug 16 2018 13:07
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?
trsh
@trsh
Aug 16 2018 13:09
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
trsh
@trsh
Aug 16 2018 13:14
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
trsh
@trsh
Aug 16 2018 13:26
Also rust should cryabout scopes, as there no unsafe flag at this point
Franz Gregor
@fzgregor
Aug 16 2018 13:28
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
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 :-)
trsh
@trsh
Aug 16 2018 13:30
@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
@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.
trsh
@trsh
Aug 16 2018 13:41
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
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
trsh
@trsh
Aug 16 2018 13:45
@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
I meant something like this
trsh
@trsh
Aug 16 2018 13:48
@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
Or, possibly, this
Michal 'vorner' Vaner
@vorner
Aug 16 2018 13:55
@tanriol Do you leak stuff on purpose?
Denis Lisov
@tanriol
Aug 16 2018 13:56
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
Well, usually, it does. Unless you tell it to get out of your way.
trsh
@trsh
Aug 16 2018 13:59
@vorner what do u mean with leak?
Denis Lisov
@tanriol
Aug 16 2018 13:59
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...
trsh
@trsh
Aug 16 2018 14:00
Where is the leak?
How can I free it?"
Denis Lisov
@tanriol
Aug 16 2018 14:00
Or possibly...
trsh
@trsh
Aug 16 2018 14:01
mem::forget?
Denis Lisov
@tanriol
Aug 16 2018 14:01
...looks like I'm being wrong again :-)
Michal 'vorner' Vaner
@vorner
Aug 16 2018 14:01
You probably should implement Drop for that structure.
trsh
@trsh
Aug 16 2018 14:02
So the second exmaple isn't leaking?
Denis Lisov
@tanriol
Aug 16 2018 14:02
Yeah, generating a Drop impl is pretty much the only bulletproof way to do it :-)
Michal 'vorner' Vaner
@vorner
Aug 16 2018 14:03
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
@vorner Actually, it does exist in the println! invocation, no?
trsh
@trsh
Aug 16 2018 14:04
@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
Ah, right, sorry, it does.
trsh
@trsh
Aug 16 2018 14:05
here println!("{:?}", unsafe{CString::from_raw((*p).i)});
Michal 'vorner' Vaner
@vorner
Aug 16 2018 14:05
But then it „damages“ the structure ‒ it is no longer valid to use.
trsh
@trsh
Aug 16 2018 14:06
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
Well, dropping the CString makes it invalid. If you do from_raw, but save the string around, you're still OK.
trsh
@trsh
Aug 16 2018 14:08
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
@trsh I'd structure your code roughly like this
trsh
@trsh
Aug 16 2018 14:15
Why is calling fn drop
?
Michal 'vorner' Vaner
@vorner
Aug 16 2018 14:16
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
trsh
@trsh
Aug 16 2018 14:17
Ah I think I got it