Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Unsafe คืออะไร

unsafe ปลดล็อคความสามารถพิเศษที่ compiler ตรวจสอบไม่ได้

🚨 อันตราย!

unsafe หมายความว่าคุณ รับผิดชอบ ความถูกต้องแทน compiler:

  • ❌ Memory corruption
  • ❌ Data races
  • ❌ Undefined behavior
  • ❌ Security vulnerabilities

ใช้ unsafe เมื่อจำเป็นจริงๆ เท่านั้น!

Unsafe Superpowers

ใน unsafe block ทำได้ 5 อย่าง:

Superpowerคำอธิบาย
Dereference raw pointersใช้ *const T, *mut T
Call unsafe functionsฟังก์ชันที่มี unsafe
Access mutable staticsตัวแปร static mut
Implement unsafe traitsเช่น Send, Sync
Access union fieldsunion แบบ C

🔒 Safe vs Unsafe Visualization

+-------------------------------------------------------------------+
|                         Rust's Safety Layers                      |
+-------------------------------------------------------------------+
|                                                                   |
|   +-----------------------------------------------------------+   |
|   |                    SAFE RUST (99% of code)                |   |
|   |  +---------------------------------------------------------+  |
|   |  |  * Ownership rules                                     |   |
|   |  |  * Borrow checker                                      |   |
|   |  |  * Type safety                                         |   |
|   |  |  * Memory safety                                       |   |
|   |  +---------------------------------------------------------+  |
|   +-----------------------------------------------------------+   |
|                              |                                    |
|                              v                                    |
|   +-----------------------------------------------------------+   |
|   |                 UNSAFE BLOCK (1% - when needed)           |   |
|   |  +---------------------------------------------------------+  |
|   |  |  * Raw pointers                                        |   |
|   |  |  * FFI (Foreign Function Interface)                    |   |
|   |  |  * Mutable statics                                     |   |
|   |  |  * You are responsible for correctness!                |   |
|   |  +---------------------------------------------------------+  |
|   +-----------------------------------------------------------+   |
|                                                                   |
+-------------------------------------------------------------------+

🌍 Real-World Use Cases

Use Caseตัวอย่างทำไมต้อง Unsafe
FFIเรียก C libraries (OpenSSL, SQLite)C ไม่มี safety guarantees
Hardwareเข้าถึง memory-mapped I/Oต้อง raw pointer
PerformanceCustom allocators, SIMDควบคุม memory เอง
OS APIsSystem callsLow-level interface

💡 ตัวอย่างจริง: Vec<T> และ String implement ด้วย unsafe ภายใน แต่ให้ safe API ออกมา


1. Dereference Raw Pointers

fn main() {
    let mut num = 5;

    // สร้าง raw pointers (safe - ยังไม่ได้ dereference)
    let r1 = &num as *const i32;  // immutable raw
    let r2 = &mut num as *mut i32; // mutable raw

    // dereference ต้อง unsafe
    unsafe {
        println!("r1 is: {}", *r1);
        *r2 = 10;
        println!("r2 is: {}", *r2);
    }
}

Raw Pointers vs References

AspectReferencesRaw Pointers
Nullไม่ได้ได้
DanglingCompiler ป้องกันไม่ป้องกัน
Aliasingมี rulesไม่มี rules
Auto-cleanupผ่าน Dropไม่มี

2. Call Unsafe Functions

unsafe fn dangerous() {
    println!("Doing dangerous stuff!");
}

fn main() {
    // เรียก unsafe function ต้องอยู่ใน unsafe block
    unsafe {
        dangerous();
    }
}

3. Access Mutable Statics

static mut COUNTER: u32 = 0;

fn add_to_count(inc: u32) {
    unsafe {
        COUNTER += inc;
    }
}

fn main() {
    add_to_count(3);

    unsafe {
        println!("COUNTER: {}", COUNTER);
    }
}

คำเตือน: static mut อันตรายมากใน multi-threaded ใช้ Mutex หรือ Atomic แทน


4. Implement Unsafe Traits

#![allow(unused)]
fn main() {
unsafe trait MyUnsafeTrait {
    fn do_something(&self);
}

unsafe impl MyUnsafeTrait for i32 {
    fn do_something(&self) {
        println!("{}", self);
    }
}
}

ตัวอย่างจริง: Send และ Sync traits


5. Access Union Fields

#[repr(C)]
union MyUnion {
    f1: u32,
    f2: f32,
}

fn main() {
    let u = MyUnion { f1: 1 };

    // อ่าน field ต้อง unsafe เพราะไม่รู้ว่า field ไหนถูก set
    unsafe {
        println!("f1: {}", u.f1);
    }
}

เมื่อไหร่ควรใช้ unsafe?

✅ ใช้เมื่อ

  1. FFI - เรียก C/C++ code
  2. Performance - hot paths ที่ต้องเร็วมาก
  3. Hardware - เข้าถึง hardware โดยตรง
  4. Implement abstractions - สร้าง safe wrapper

❌ ไม่ควรใช้

  1. ข้าม borrow checker เพราะไม่เข้าใจ
  2. แก้ compile error แบบขี้เกียจ
  3. ทุกที่ที่มีทางเลือก safe

FFI: เรียก C Code

ตัวอย่างเรียก function จาก C library:

// ประกาศ external C function
extern "C" {
    fn abs(input: i32) -> i32;
    fn sqrt(input: f64) -> f64;
}

fn main() {
    unsafe {
        println!("abs(-5) = {}", abs(-5));      // 5
        println!("sqrt(9.0) = {}", sqrt(9.0));  // 3.0
    }
}

สร้าง Rust function ที่ C เรียกได้

// export function สำหรับ C
#[no_mangle]
pub extern "C" fn rust_add(a: i32, b: i32) -> i32 {
    a + b
}

Safe Abstractions

วิธีที่ถูกต้อง: ห่อ unsafe ด้วย safe interface

#![allow(unused)]
fn main() {
pub fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
    let len = slice.len();
    let ptr = slice.as_mut_ptr();

    assert!(mid <= len);

    // unsafe ภายใน แต่ interface เป็น safe
    unsafe {
        (
            std::slice::from_raw_parts_mut(ptr, mid),
            std::slice::from_raw_parts_mut(ptr.add(mid), len - mid),
        )
    }
}
}

ลองทำดู! 🎯

  1. สร้าง raw pointer และ dereference
  2. สร้าง unsafe function
  3. ลองเข้าถึง static mut

🌍 Real-World Example: FFI เรียก C Function

ตัวอย่างเรียก strlen จาก C standard library:

use std::ffi::CString;

// ประกาศ external C function
extern "C" {
    fn strlen(s: *const i8) -> usize;
}

fn safe_strlen(s: &str) -> usize {
    // แปลง Rust string เป็น C string
    let c_string = CString::new(s).expect("CString failed");
    
    // เรียก C function ใน unsafe block
    unsafe {
        strlen(c_string.as_ptr())
    }
}

fn main() {
    let text = "Hello, Rust!";
    let len = safe_strlen(text);
    println!("Length: {}", len);  // Length: 12
}

FFI Pattern

+-------------------------------------------------------------------+
|                    Safe Wrapper Pattern                           |
+-------------------------------------------------------------------+
|                                                                   |
|   User Code (Safe)                                                |
|        |                                                          |
|        v                                                          |
|   +--------------------------------------------+                  |
|   |  safe_strlen(s: &str) -> usize             | <--- Safe API    |
|   |    * Validate input                        |                  |
|   |    * Convert to C types                    |                  |
|   |    * Call unsafe code                      |                  |
|   |    * Convert result back                   |                  |
|   +--------------------------------------------+                  |
|        |                                                          |
|        v                                                          |
|   +--------------------------------------------+                  |
|   |  unsafe { strlen(ptr) }                    | <--- Unsafe FFI  |
|   +--------------------------------------------+                  |
|        |                                                          |
|        v                                                          |
|   C Library (libc)                                                |
|                                                                   |
+-------------------------------------------------------------------+

สรุป

Keywordใช้เมื่อ
unsafe { }Block ที่ทำ unsafe operations
unsafe fnFunction ที่ต้องเรียกใน unsafe
unsafe traitTrait ที่ต้อง impl ใน unsafe
unsafe implImplement unsafe trait

Best Practices

  1. ลด unsafe ให้น้อยที่สุด
  2. Document invariants ที่ต้องรักษา
  3. Test extensively
  4. Wrap ด้วย safe API

👉 ต่อไป: Raw Pointers