스크랩

Rust의 unsafe는 정말 '안전하지 않다'는 뜻일까? Fil-C 논쟁으로 보는 메모리 안전성의 진짜 의미

Rust의 unsafe는 정말 '안전하지 않다'는 뜻일까? Fil-C 논쟁으로 보는 메모리 안전성의 진짜 의미

핵심 요약

최근 개발자 커뮤니티에서 흥미로운 논쟁이 벌어지고 있습니다. "Rust는 unsafe 키워드가 있으니 진짜 메모리 안전 언어가 아니다", "진정으로 안전을 원한다면 Fil-C를 써야 한다"는 주장이 나온 건데요. 오늘은 이 논쟁의 배경과, 왜 이런 절대주의적 기준이 현실을 놓치고 있는지 살펴보겠습니다.

Fil-C는 무엇인가요?

Fil-C는 기존 C/C++ 코드를 재작성 없이 메모리 안전하게 실행할 수 있게 해주는 새로운 컴파일 접근입니다.

  • 범위를 벗어난 접근이나 해제된 메모리 접근(use-after-free) 같은 잘못된 메모리 사용이 발생하면 패닉을 일으켜 막습니다
  • 이를 위해 **가비지 컬렉션(GC)**과, 포인터가 접근 가능한 메모리 범위를 추적하는 InvisiCaps 기술을 결합합니다
  • Zig 진영에서도 Fil-C에 영감을 받은 컴파일 모드가 논의되고 있습니다

기존 C/C++ 생태계 입장에서는 반가운 선택지임에 틀림없습니다.

그런데 왜 논쟁이 됐을까요?

문제는 일부 Fil-C 개발자와 지지자들이 "Rust는 unsafe로 안전 보장을 우회할 수 있으니 진짜 메모리 안전 언어가 아니다"라고 주장하면서 시작됐습니다. Zig 개발자 Andrew Kelley조차 관련 이슈에서 Fil-C 영감 모드를 "Rust와 달리 실제로 메모리 안전한" 모드라고 표현하기도 했죠.

하지만 이 비교에는 중요한 게 빠져 있습니다. 바로 Fil-C를 쓰는 데 드는 현실적인 비용입니다.

Fil-C의 숨겨진 비용

  • 기존에 컴파일된 프로그램과 ABI가 호환되지 않음
  • 일부 상황에서는 수 배 느려질 수 있음
  • GC 도입이 필수

단순한 유틸리티 프로그램이라면 이 정도 제약은 크게 문제되지 않을 수 있습니다. 하지만 GC나 ABI 비호환성을 받아들이기 어려운 인기 프로젝트들도 많습니다. 그리고 공교롭게도, Fil-C가 잘 맞지 않는 바로 그 지점에서 Rust는 좋은 대안이 됩니다.

숫자로 보는 Rust의 실전 성적표

이론이 아니라 실제 데이터를 볼까요? Android 진영에서 공개한 흥미로운 수치가 있습니다.

| 구분 | 취약점 밀도 (100만 줄당) | |---|---| | Android의 C/C++ (과거 데이터) | 약 1,000건 | | Android의 Rust (500만 줄 이상) | 약 0.2건 |

Rust 코드베이스에서는 출시 전에 수정된 잠재적 취약점이 단 1건 발견됐을 뿐입니다. 계산해보면 C/C++ 대비 1,000배 이상 낮은 수치입니다. 물론 프로젝트마다 편차는 있겠지만, 이 정도면 실제 환경에서 Rust가 메모리 안전성 리스크를 획기적으로 낮춘다는 근거로 충분해 보입니다.

100% 안전 vs 99.9% 안전, 꼭 하나만 골라야 할까요?

이 논쟁을 이렇게 바꿔서 생각해볼 수 있습니다.

"모든 프로그램에서 문제의 99.9%를 막는 기술"과 "90%의 프로그램에서 문제의 100%를 막는 기술" 중 뭐가 더 나을까요?

정답은 "둘 다 쓰면 됩니다"입니다.

  • Fil-C의 절충(GC, ABI 비호환, 성능 저하)을 받아들일 수 있는 C/C++/Zig 프로젝트는 Fil-C 바이너리를 제공하면 됩니다
  • Fil-C를 적용하기 어려운 소프트웨어는 Rust처럼 취약점 위험을 크게 낮추는 언어로 작성하면 됩니다

둘은 경쟁 관계가 아니라 상호 보완적인 선택지입니다.

GC를 쓸 수 있어도 굳이 Rust를 쓰는 이유

"Go나 Fil-C처럼 GC 기반 옵션이 있는데 왜 굳이 Rust를 쓰냐"는 질문도 나올 법합니다. 하지만 여기엔 재밌는 역설이 있습니다.

  • GC 언어로 짤 수 있는 프로그램은 대개 unsafe가 필요 없습니다
  • 반대로 unsafe가 필요한 저수준 프로그램은 대개 GC를 쓸 수 없는 영역입니다

또한 Fil-C는 메모리 안전성 취약점을 '크래시'로 바꿔줄 뿐, 그 크래시 자체가 사라지는 건 아닙니다. 과거 밀도(100만 줄당 약 1,000건)가 그대로라면 고쳐야 할 크래시가 여전히 산더미처럼 남고, 크래시를 유발하는 능력이 곧 보안 취약점으로 이어졌던 사례도 있었죠. Rust 사용자들은 작은 메모리 안전성 리스크보다 데이터 경쟁(data race) 방지 같은 다른 언어적 보장을 더 중요하게 평가하는 경우가 많습니다.

결론: 일관된 기준이 필요합니다

만약 Rust의 100만 줄당 0.2건이라는 수치조차 받아들일 수 없다면, 같은 잣대를 일반 C/C++와 Fil-C를 적용하지 않은 Zig에도 똑같이, 아니 더 엄격하게 적용해야 앞뒤가 맞습니다. Rust보다 훨씬 안전성이 낮은 대안은 눈감아주면서 유독 Rust만 unsafe 키워드 하나로 배제하는 태도는 논리적으로 일관되지 않습니다.

메모리 안전성은 성능, ABI 호환성, GC 도입 여부, 데이터 경쟁 방지까지 모두 함께 고려해야 하는 다차원적인 문제입니다. "완벽하지 않으면 무의미하다"는 절대주의보다는, 상황에 맞는 도구를 고르는 실용적인 접근이 필요한 시점입니다.


원문: https://news.hada.io/topic?id=31822