Home > Mobile >  What is the RUST equivalent of following C code?
What is the RUST equivalent of following C code?

Time:01-04

I have a small C code which demonstrate Runtime Stack functionality by modifying data at a stack address.

#include <stdio.h>

int * fun() {
    int a = 10;
    return &a;
}
int * fun2() {
    int b = 20;
    return &b;
}

int main () {
    int *a = fun();
    int *b = fun2();
    printf("a:%d b:%d\n", *a, *b);
    return 0;
}

Output of this is : a:20 b:20 which shows 'b' in 'fun2' used the same stack address as 'a' in 'fun'.

i want to test this in Rust too. What would be the simplest way to do this?

I tried Borrowing but compiler says "No value to borrow".

CodePudding user response:

If you want to have the same undefined behavior as in C, you can do (luckily, this requires unsafe):

fn fun() -> *const i32 {
    let a = 10;
    &a
}

fn fun2() -> *const i32 {
    let b = 20;
    &b
}

fn main() {
    let a = fun();
    let b = fun2();
    // SAFETY: Don't do this. This is pure Undefined Behavior.
    unsafe {
        println!("a: {} b: {}", *a, *b);
    }
}

And this is UB exactly as with the C version. It prints a: 21885 b: 21885 on the playground on debug mode, and a: -482758656 b: 32767 on release mode. Yours will be different.

If you also want the same result as the C version, you can use printf(). Be careful with the code you use, changes can cause it to no longer "work" as it will use a different stack layout. Of course, this is very fragile:

use std::ffi::c_char;

fn fun() -> *const i32 {
    let a = 10;
    &a
}

fn fun2() -> *const i32 {
    let a = 20;
    &a
}

extern "C" {
    fn printf(format: *const c_char, ...);
}

fn main() {
    let a = fun();
    let b = fun2();
    unsafe {
        printf(b"a: %d b: %d\n\0" as *const u8 as *const c_char, *a, *b);
    }
}

It prints a: 20 b: 20 on debug mode, and a: 1 b: 1 on release (and yours may be different).

CodePudding user response:

What is the RUST equivalent of following C code?

Goal is questionable as C code is bad.


int *a = fun(); is undefined behavior (UB) as code attempts to save an invalid pointer. Copying invalid pointers is UB. The later attempted reference of *a in printf("a:%d b:%d\n", *a, *b); is also UB.

int * fun() {
    int a = 10;
    return &a; // &a invalid when function completes.
}

CodePudding user response:

a and b have automatic storage and are destroyed once the function returns. Once a function returns, it's stack frame is popped (destroyed). Returning the address of (and using) the local variables invokes Undefined Behaviour as per the following clause of the C11 standard:

6.2.4 Storage durations of objects:

2 The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address, and retains its last-stored value throughout its lifetime. If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to reaches the end of its lifetime.

CodePudding user response:

literally the same:

#![no_main]

extern "C" {
    fn printf(format: *const u8, ...); // u8 or i8 doesn't matter in this case
}

#[no_mangle]
extern fn fun() -> *const i32 {
    let a = 10;
    &a
}

#[no_mangle]
extern fn fun2() -> *const i32 {
    let a = 20;
    &a
}

#[no_mangle]
unsafe extern main() -> i32 {
    let a = fun();
    let b = fun2();
    printf("a:%d b:%d\n\0".as_ptr(), *a, *b);
    0
}
  • Related