How do C and Rust differs in memory safety ? example 1
Looks at the below program, how crazy the ‘main’ function snatches the password from the function ‘assign’. We only return the pointer to the ‘user’, but ‘main’ gets ‘password’ from it.
It took some trials for me to find number nine(9) as the offset (byte) ( difference between the “user” and " password" address ) .
C code
l 1
2 #include<stdlib.h>
3
4 char* assign(){
5
6 char password = 'a'; //password stored here
7 char b[3] = "ab";
8
9 int* username = &b;
10
11 return username;
12 }
13
14
15
16 int main(){
17
18 char* user = NULL;
19
20 user = assign();
21 // you can just do some address offseting with "-" or "+" to get the "password" field
22 printf("%c\n",*(user - 9));
23
24 }
Output is ‘a’ which is the password here.
a
Rust code:
In rust it is very difficult or not even possible ( I don’t know a method) without unsafe code to offset the address and get another variables or string slices(literals).
Interestingly “password” and “username” variables are referring to the program memory itself ( not stack or heap ) as &str ( string slice) hard coding in program binary.
We can try with "unsafe " code to do some manipulation on the username address to snatch the “password”.
But if you are making sure that no ‘unsafe’ code in your program , you can avoid this scenario in rust or you will catch those scenario on compile time itself ( that is AWESOME! )
2 fn assign() -> &'static str{
3
4 let password = "q";
5 let username = "asdasd";
6
7 let q = username;
8
9
10 println!("pointer = {:p}, {:p}",password,q);
11
12 q
13
14 }
15
16
17 fn main() {
18
19 let p:&str = assign();
20
21 let ptr: *const u8 = p.as_ptr();
22
/// you really need to write unsafe code and
/// do some trick to get offset address of the
/// "password" here. The + , - operators won't work with address in rust.
23 unsafe {
24 println!("Hello, world! : {}",*ptr.sub(1) as char);
25 }
26
27 }
Output is
pointer = 0x5638e3aa3d70, 0x5638e3aa3d71
Hello, world! : q