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 fields | union แบบ 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 |
| Performance | Custom allocators, SIMD | ควบคุม memory เอง |
| OS APIs | System calls | Low-level interface |
💡 ตัวอย่างจริง:
Vec<T>และStringimplement ด้วย 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
| Aspect | References | Raw Pointers |
|---|---|---|
| Null | ไม่ได้ | ได้ |
| Dangling | Compiler ป้องกัน | ไม่ป้องกัน |
| 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?
✅ ใช้เมื่อ
- FFI - เรียก C/C++ code
- Performance - hot paths ที่ต้องเร็วมาก
- Hardware - เข้าถึง hardware โดยตรง
- Implement abstractions - สร้าง safe wrapper
❌ ไม่ควรใช้
- ข้าม borrow checker เพราะไม่เข้าใจ
- แก้ compile error แบบขี้เกียจ
- ทุกที่ที่มีทางเลือก 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),
)
}
}
}
ลองทำดู! 🎯
- สร้าง raw pointer และ dereference
- สร้าง unsafe function
- ลองเข้าถึง 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 fn | Function ที่ต้องเรียกใน unsafe |
unsafe trait | Trait ที่ต้อง impl ใน unsafe |
unsafe impl | Implement unsafe trait |
Best Practices
- ลด unsafe ให้น้อยที่สุด
- Document invariants ที่ต้องรักษา
- Test extensively
- Wrap ด้วย safe API
👉 ต่อไป: Raw Pointers