Get c "*char" at address stored in a c_void variable


#1

I’m calling a c function which returns a memory address of a char. I’ve stored the memory address in a rust c_void variable. How can I get the char stored at the memory address?

To clarify the rust c_void variable holds a memory address for example: 0x123456


#2

If you know it’s a char, why don’t you store it in a *const c_char? (rather than c_void)

You can just dereference it in an unsafe block, e.g. let c = unsafe { *my_ptr };


#3

The c function expects a c_void. I just tried dereference it, it doesn’t work.

Here is some of my code:

// Pretty sure this is incorrect, but works for now. I need to create a variable that can store a memory address.
let mut r = unsafe { malloc(4) as *const c_char };
call_c_func(r as *mut c_void);
let c = unsafe { *r };
println!("{:?}", c);

// Console output is
-44

#4

So the function is filling a pointer in the parameter, like void c_func(void **out_ptr)?

Then I’d do something like:

let mut my_ptr: *mut c_void = ptr::null_mut();
call_c_func(&mut my_ptr); // `&mut *mut c_void` coerces to `*mut *mut c_void`
let c = unsafe { *(my_ptr as *mut c_char) };
println!("{:?}", c);

#5

Now the console output is “51”.
I’m kind of new to ffi in rust I don’t even know if I defined “VerQueryValueA” correctly.

Heres some more code:

/* https://msdn.microsoft.com/en-us/library/windows/desktop/ms647464(v=vs.85).aspx
BOOL WINAPI VerQueryValue(
  _In_  LPCVOID pBlock,
  _In_  LPCTSTR lpSubBlock,
  _Out_ LPVOID  *lplpBuffer, <--- This is what holds the address.
  _Out_ PUINT   puLen
);

*/
extern "stdcall" {
	pub fn VerQueryValueA(info_buff: *const c_void, info_block: *const c_char, result: &mut *mut c_void, ignore: c_ulong) -> c_ulong;
}

This is the function I’m calling. The result argument is what returns the address.

This is how I called the above function in c, and it works.

char *result= (char *) malloc(size);
VerQueryValue(buff, "somestuff", (void **) &result, NULL)

Yes


#6

What value are you expecting? 51 is ASCII ‘3’, if that helps.

The last parameter PUINT should be a pointer too, I guess unsigned int* -> *mut u32. Or use usize with 0 if you want to quickly approximate NULL.

I think your malloc is wasted here. VerQueryValue says it returns a pointer info the buffer you provide in the first parameter. Since this result is an out parameter, it doesn’t matter what it points to going in, and should probably just start NULL.


#7

The expected output is

391fa63bcefd25b35addf678356828dded5ae71e-refs/heads/master@{#427013}

Thanks for the tips, I wasn’t sure if I needed malloc.


#8

Ah, I misunderstood, you said a char, and look, you got the first char ‘3’! :slight_smile:

So I think now you’ll want to end up with a CStr.

let mut my_ptr: *mut c_void = ptr::null_mut();
call_c_func(&mut my_ptr); // `&mut *mut c_void` coerces to `*mut *mut c_void`
let cstr = unsafe { CStr::from_ptr(my_ptr as *const c_char) };
println!("{:?}", cstr);

#9

I realized that after too that it was the first char. Its working now. Thanks for the help, its much appreciated :smile: