Unsafety checks

From:
Unsafe Superpowers

To switch to unsafe Rust, use the unsafe keyword and then start a new block that holds the unsafe code. You can take five actions in unsafe Rust that you can’t in safe Rust, which we call unsafe superpowers. Those superpowers include the ability to:

  • Dereference a raw pointer
  • Call an unsafe function or method
  • Access or modify a mutable static variable
  • Implement an unsafe trait
  • Access fields of unions

It’s important to understand that unsafe doesn’t turn off the borrow checker or disable any other of Rust’s safety checks:

This demonstrates that another important safety check is not performed in unsafe code:

unsafe extern "C" fn hotplug_callback(
    ctx: *mut libusb_context,
    device: *mut libusb_device,
    event: libusb_hotplug_event,
    user_data: *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int {
    println!("Event occured");
    let dev_handle: *mut *mut libusb_device_handle = std::ptr::null_mut();
    match usb_sys::libusb_open(device, dev_handle) {
        0 => {
            eprintln!("SUCCESS libusb_open")
        }
        LIBUSB_ERROR_NO_MEM => {
            eprintln!("LIBUSB_ERROR_NO_MEM")
        }
        LIBUSB_ERROR_ACCESS => {
            eprintln!("LIBUSB_ERROR_ACCESS")
        }
        LIBUSB_ERROR_NO_DEVICE => {
            eprintln!("LIBUSB_ERROR_NO_DEVICE")
        }
//NO ENTRY FOR REST OF THE ERRORS, NON THE LESS, IT COMPILES
    }
    0
}

Are you sure? I wonder why, because this doesn't compile:

unsafe fn foo() -> i32 {
    0
}

fn main() {
    unsafe {
        match foo() {
            0 => (),
        }
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
 --> src/main.rs:7:15
  |
7 |         match foo() {
  |               ^^^^^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
  |
  = note: the matched value is of type `i32`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
  |
8 ~             0 => (),
9 ~             i32::MIN..=-1_i32 | 1_i32..=i32::MAX => todo!(),
  |

For more information about this error, try `rustc --explain E0004`.
error: could not compile `playground` due to previous error

2 Likes

I am sure. Strange that your example compiles. I'm glad that it does.
What happens if you add: unsafe extern "C" ?

The problem is that LIBUSB_ERROR_NO_MEM is a wildcard pattern that matches any value, equivalent to _, as the compiler will tell you:

warning: unreachable pattern
  --> src/lib.rs:29:9
   |
26 |         LIBUSB_ERROR_NO_MEM => {
   |         ------------------- matches any value
...
29 |         LIBUSB_ERROR_ACCESS => {
   |         ^^^^^^^^^^^^^^^^^^^ unreachable pattern
   |

This has nothing to do with unsafe or extern "C". To fix it, ensure that LIBUSB_ERROR_NO_MEM and similar are defined as consts and imported under the names you expect.

9 Likes

Thanks, that cleared that out!

What is a wildcard pattern and how can you define one? I don't see any macro invocation. How does it work?

Its just a default match arm binding the value to a new identifier.

1 Like

Oh evil!

fn main() {
    match 37 {
        ELEPHANT => {
            println!("Töröhh!");
        },
        DOG => {
            println!("Woof!")
        },
    }
}

(Playground)

Well that's why it gets five warnings!

Paying attention to what the compiler tells you is important.

9 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.