توابع ناامن

فراخوانی متدهای ناامن

یک function یا method را می‌توان unsafe علامت‌گذاری کرد، اگر دارای پیش‌شرط‌های اضافی باشد که باید برای جلوگیری از رفتار نامشخص رعایت کنید:

extern "C" {
    fn abs(input: i32) -> i32;
}

fn main() {
    let emojis = "🗻∈🌏";

    // SAFETY: The indices are in the correct order, within the bounds of the
    // string slice, and lie on UTF-8 sequence boundaries.
    unsafe {
        println!("emoji: {}", emojis.get_unchecked(0..4));
        println!("emoji: {}", emojis.get_unchecked(4..7));
        println!("emoji: {}", emojis.get_unchecked(7..11));
    }

    println!("char count: {}", count_chars(unsafe { emojis.get_unchecked(0..7) }));

    // SAFETY: `abs` doesn't deal with pointers and doesn't have any safety
    // requirements.
    unsafe {
        println!("مقدار مطلق ۳- طبق C: {}", abs(-3));
    }

    // Not upholding the UTF-8 encoding requirement breaks memory safety!
    // println!("emoji: {}", unsafe { emojis.get_unchecked(0..3) });
    // println!("char count: {}", count_chars(unsafe {
    // emojis.get_unchecked(0..3) }));
}

fn count_chars(s: &str) -> usize {
    s.chars().count()
}

نوشتن متدهای ناامن

اگر عملکردهای خود را برای جلوگیری از رفتار نامشخص به شرایط خاصی نیاز دارند، می‌توانید به‌عنوانunsafe علامت‌گذاری کنید.

/// Swaps the values pointed to by the given pointers.
///
/// # Safety
///
/// The pointers must be valid and properly aligned.
unsafe fn swap(a: *mut u8, b: *mut u8) {
    let temp = *a;
    *a = *b;
    *b = temp;
}

fn main() {
    let mut a = 42;
    let mut b = 66;

    // SAFETY: ...
    unsafe {
        swap(&mut a, &mut b);
    }

    println!("a = {}, b = {}", a, b);
}
This slide should take about 5 minutes.

فراخوانی متدهای ناامن

تابع get_unchecked، مانند اکثر توابع _unchecked، ناامن است، زیرا اگر در محدوده نادرست باشد، می‌تواند یک UB ایجاد کند. abs به دلیل دیگری نادرست است: این یک تابع خارجی (FFI) است. فراخوانی توابع خارجی معمولاً زمانی مشکل‌ساز است که آن توابع کارهایی را با اشاره‌گرهایی انجام می‌دهند که ممکن است مدل حافظه Rust را نقض کنند، اما به طور کلی هر تابع C ممکن است تحت هر شرایط دلخواه رفتار نامشخصی داشته باشد.

زبان برنامه‌نویسی "C" در این مثال ABI است. ABIهای دیگر نیز در دسترس هستند.

نوشتن متدهای ناامن

ما در واقع از pointerها برای یک تابعswap استفاده نمی‌کنیم - این کار را می‌توان به‌طور ایمن با referenceها انجام داد.

توجه داشته باشید که کد ناامن در یک تابع ناامن بدون بلوک unsafe مجاز است. ما می‌توانیم این کار را با #[deny(unsafe_op_in_unsafe_fn)] غیرمجاز کنیم. سعی کنید آن را اضافه کنید و ببینید چه اتفاقی می افتد. این احتمالاً در نسخه بعدی Rust تغییر خواهد کرد.