개요
- 메모리 안전성 보장을 강제하지 않는 숨겨진 내부의 두번째 언어
- 빌림 검사기 혹은 다른 어떤 러스트의 안전성 검사 기능을 끄는 것은 아님
- 코드가 필연적으로 위험하다던가 절대적으로 메모리 안전성 문제를 가지고 있음을 의미하는 것이 아님
- 코드가 올바른 방법으로 메모리에 접근할 것임을 확실히 해두는 것
- 존재 이유
- 정적 분석이 선천적으로 보수적이기 때문
- 하드웨어가 선천적으로 안전하지 않기 때문
- 저수준의 시스템 프로그래밍 작업은 이 언어의 목표 중 하나
- 단점
- unsafe 키워드
- 안전하지 않은 러스트로 전환해주는 키워드
- unsafe 뒤에 안전하지 않은 코드를 감싸주는 새 블록을 생성
- 메모리 안전성과 관련된 어떠한 에러라도 unsafe 블록 내에 있을 것임
- unsafe 블록을 최대한 작게 유지
- 외국 함수 인터페이스(Foreign Function Interface, FFI)
- 다른 언어로 작성된 함수를 호출
- extern 키워드를 이용
- 다른 언어에서 러스트 함수 호출
- extern 키워드를 이용
- #[no_mangle] 어노테이션을 추가 필요
안전하지 않은 슈퍼파워(unsafe superpowers)
- 안전하지 않은 러스트 내에서 할 수 있는 4개의 행동
- 로우 포인터(raw pointer)를 역참조
- 불변
- 가변
- 성질
- 빌림 규칙 무시가 허용되어 불변 및 가변 포인터 양쪽 모두를 갖거나 같은 위치에 여러 개의 가변 포인터를 갖을 수 있음
- 유효한 메모리를 가리키고 있음을 보장하지 않음
- 널이 될 수 있음
- 자동 메모리 정리가 구현되어 있지 않음
- 안전하지 않은 함수 혹은 메소드 호출
- unsafe 블록 내에서 호출해야함
- 문서를 읽었고 적절한 사용법을 이해했음을 러스트에게 단언
- 가변 정적 변수(mutable static variable)의 접근 혹은 수정
- 안전하지 않은 트레잇 구현
예제 - 로우 포인터(raw pointer)를 역참조
- 코드
-
fn main() {
let mut i = 1;
let i1 = &i as *const i32;
let i2 = &mut i as *mut i32;
unsafe {
println!("1 : {}, {}", *i1, *i2);
*i2 = 2;
println!("2 : {}, {}", *i1, *i2);
}
}
- 실행 결과
예제 - 안전하지 않은 함수 혹은 메소드 호출
- 코드
-
unsafe fn func() {
let i = 1;
let i1 = &i as *const i32;
println!("{}", *i1);
}
fn main() {
unsafe {
func();
}
}
- 실행 결과
예제 - 외국 함수 인터페이스(Foreign Function Interface, FFI)
- 코드
-
extern "C" {
fn abs(x: i32) -> i32;
}
fn main() {
unsafe {
println!("{}, {}", abs(-1), abs(1));
}
}
- 실행 결과
예제 - 가변 정적 변수(mutable static variable)의 접근 혹은 수정
- 코드
-
static TEST_1: i32 = 1;
static mut TEST_2: &str = "a";
fn main() {
println!("1 : {}", TEST_1);
unsafe {
println!("2 : {}", TEST_2);
}
unsafe {
TEST_2 = "b";
}
unsafe {
println!("3 : {}", TEST_2);
}
}
- 실행 결과
예제 - 안전하지 않은 트레잇 구현
- 코드
-
unsafe trait Test {}
unsafe impl Test for i32 {}
fn main() {}