Updated:

2 minute read

개요

  • 메모리 안전성 보장을 강제하지 않는 숨겨진 내부의 두번째 언어
  • 빌림 검사기 혹은 다른 어떤 러스트의 안전성 검사 기능을 끄는 것은 아님
  • 코드가 필연적으로 위험하다던가 절대적으로 메모리 안전성 문제를 가지고 있음을 의미하는 것이 아님
  • 코드가 올바른 방법으로 메모리에 접근할 것임을 확실히 해두는 것
  • 존재 이유
    • 정적 분석이 선천적으로 보수적이기 때문
    • 하드웨어가 선천적으로 안전하지 않기 때문
      • 저수준의 시스템 프로그래밍 작업은 이 언어의 목표 중 하나
  • 단점
    • 개발자가 위험성을 고스란히 받아들여야 함
  • unsafe 키워드
    • 안전하지 않은 러스트로 전환해주는 키워드
    • unsafe 뒤에 안전하지 않은 코드를 감싸주는 새 블록을 생성
    • 메모리 안전성과 관련된 어떠한 에러라도 unsafe 블록 내에 있을 것임
    • unsafe 블록을 최대한 작게 유지
  • 외국 함수 인터페이스(Foreign Function Interface, FFI)
    • 다른 언어로 작성된 함수를 호출
    • extern 키워드를 이용
    • 다른 언어에서 러스트 함수 호출
      • extern 키워드를 이용
      • #[no_mangle] 어노테이션을 추가 필요
        • 맹글링(mangling)
          • 컴파일 과정에서 함수의 이름을 변경


안전하지 않은 슈퍼파워(unsafe superpowers)

  • 안전하지 않은 러스트 내에서 할 수 있는 4개의 행동
    • 로우 포인터(raw pointer)를 역참조
      • 불변
        • *const T
      • 가변
        • *mut T
      • 성질
        • 빌림 규칙 무시가 허용되어 불변 및 가변 포인터 양쪽 모두를 갖거나 같은 위치에 여러 개의 가변 포인터를 갖을 수 있음
        • 유효한 메모리를 가리키고 있음을 보장하지 않음
        • 널이 될 수 있음
        • 자동 메모리 정리가 구현되어 있지 않음
    • 안전하지 않은 함수 혹은 메소드 호출
      • 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);
           }
       }
      
  • 실행 결과
    •  1 : 1, 1
       2 : 2, 2
      


예제 - 안전하지 않은 함수 혹은 메소드 호출

  • 코드
    •  unsafe fn func() {
           let i = 1;
              
           let i1 = &i as *const i32;
              
           println!("{}", *i1);
       }
              
       fn main() {
           unsafe {
               func();
           }
       }
      
  • 실행 결과
    •  1
      


예제 - 외국 함수 인터페이스(Foreign Function Interface, FFI)

  • 코드
    •  extern "C" {
           fn abs(x: i32) -> i32;
       }
              
       fn main() {
           unsafe {
               println!("{}, {}", abs(-1), abs(1));
           }
       }
      
  • 실행 결과
    •  1, 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);
           }
       }
      
  • 실행 결과
    •  1 : 1
       2 : a
       3 : b
      


예제 - 안전하지 않은 트레잇 구현

  • 코드
    •  unsafe trait Test {}
              
       unsafe impl Test for i32 {}
              
       fn main() {}