TECH 으로 돌아가기
TECH HACKER NEWS 오늘 7분 읽기 23 READS

C언어를 메모리 안전하게 — Fil-C가 인라인 어셈블리까지 품은 방법

C언어를 '메모리 안전하게' 만든다는 도전

C와 C++은 빠르고 강력하지만, 딱 하나 무서운 약점이 있어요. 바로 메모리 안전성(memory safety)이에요. 이게 뭐냐면, 프로그램이 자기가 쓰면 안 되는 메모리 영역을 건드릴 수 있다는 거예요. 배열 끝을 넘어서 읽거나(버퍼 오버플로), 이미 해제한 메모리를 또 쓰거나(use-after-free) 하는 실수죠. 이런 버그가 보안 취약점의 압도적 다수를 차지해요. 그래서 미국 정부 기관까지 나서서 '이제 메모리 안전한 언어 쓰자'며 러스트(Rust) 같은 언어를 권장하고 있을 정도예요.

문제는, 세상엔 이미 C로 짜인 코드가 산더미처럼 쌓여 있다는 거예요. 운영체제, 데이터베이스, 네트워크 라이브러리... 이걸 다 러스트로 다시 짠다? 현실적으로 거의 불가능하죠. 그래서 등장한 게 'Fil-C'예요. 기존 C/C++ 코드를 거의 그대로 가져다가, 메모리 안전하게 실행시켜 주는 컴파일러거든요. 자바스크립트 엔진(JavaScriptCore)으로 유명한 필립 피즐로(Filip Pizlo)가 만들고 있어요.

Fil-C는 어떻게 안전을 보장할까

Fil-C의 핵심 아이디어는 포인터를 그냥 '주소 숫자'가 아니라 '권한이 붙은 똑똑한 포인터'로 바꾸는 거예요. 이걸 케이퍼빌리티(capability)라고 부르는데, 포인터마다 '넌 여기서 여기까지만 접근할 수 있어'라는 범위 정보가 따라다녀요. 그래서 배열 끝을 넘어가려고 하면 즉시 잡아내서 프로그램을 멈춰 세워요. 게다가 가비지 컬렉션(쓰레기 메모리 자동 정리)까지 붙여서, 이미 해제한 메모리를 다시 건드리는 일도 막아요. 덕분에 C 코드인데도 자바나 러스트처럼 '안전한' 실행이 되는 거예요.

그런데 인라인 어셈블리가 골칫거리

여기서 까다로운 녀석이 하나 등장해요. 바로 인라인 어셈블리(inline assembly)예요. 이게 뭐냐면, C 코드 중간에 CPU가 알아듣는 기계어 명령을 직접 끼워 넣는 기능이에요. 암호화, 멀티미디어 처리, 운영체제 저수준 코드처럼 '마지막 한 방울까지 성능을 짜내야 하는' 곳에서 자주 써요.

문제는 인라인 어셈블리가 컴파일러의 안전장치를 통째로 우회한다는 점이에요. 어셈블리는 컴파일러한테 '나 이제 직접 메모리 만질 거니까 넌 빠져 있어' 하고 말하는 거나 마찬가지거든요. 그러면 Fil-C가 애써 붙여둔 케이퍼빌리티 검사도 다 무력화돼요. 어셈블리 한 줄이 범위를 벗어난 주소에 막 써버려도 막을 방법이 없는 거죠. 그래서 그동안 '메모리 안전한 C'를 표방하는 시스템들은 인라인 어셈블리를 아예 금지하거나 회피하는 경우가 많았어요.

Fil-C가 푼 방법

Fil-C는 인라인 어셈블리를 무작정 막는 대신, '안전하게 쓸 수 있는 길'을 열어줬어요. 핵심은 어셈블리에 메모리를 넘길 때 그냥 날것의 주소를 던져주지 않는다는 거예요. 포인터를 어셈블리로 전달하는 순간, Fil-C가 그 케이퍼빌리티가 가리키는 범위를 검사하고 유효한지 확인한 뒤에야 실제 주소를 넘겨줘요. 또 어셈블리가 어떤 메모리를 읽고 쓸지 개발자가 명시하도록 해서, 안전 시스템이 그 범위를 함께 추적할 수 있게 했어요. 한마디로 '어셈블리를 쓰되, 그 어셈블리가 손대는 메모리도 안전망 안에 들어오도록' 만든 거예요.

이게 왜 중요하냐면요, 진짜 현실의 C 코드들은 성능을 위해 인라인 어셈블리를 꽤 많이 쓰거든요. 여기서 막혀버리면 '기존 코드를 그대로 안전하게 돌린다'는 Fil-C의 약속이 반쪽짜리가 돼요. 인라인 어셈블리까지 품었다는 건, 이론적인 장난감을 넘어 실제 프로덕션 코드를 감당할 수 있는 방향으로 한 걸음 더 갔다는 뜻이에요.

업계 맥락에서 보면

메모리 안전은 요즘 시스템 프로그래밍 분야의 가장 뜨거운 주제예요. 러스트는 '처음부터 안전하게 다시 짜자'는 노선이고, 구글이나 마이크로소프트도 핵심 코드를 러스트로 옮기고 있어요. 반면 Fil-C는 '기존 C를 버리지 않고 안전하게 감싸자'는 정반대 노선이에요. 둘은 경쟁이라기보단 서로 다른 상황을 위한 답이에요. 새 프로젝트라면 러스트가 매력적이지만, 수십 년 쌓인 레거시 C 자산을 당장 안전하게 만들어야 한다면 Fil-C 같은 접근이 훨씬 현실적이거든요. 물론 케이퍼빌리티 검사와 가비지 컬렉션을 붙이는 만큼 약간의 성능 비용은 따라와요. 이 '안전 대 속도'의 줄다리기를 어디서 타협하느냐가 관건이죠.

한국 개발자에게는?

당장 실무에 Fil-C를 도입할 일은 많지 않을 수 있어요. 아직 연구·실험 단계에 가깝거든요. 하지만 임베디드, 보안, 시스템 프로그래밍을 하는 분이라면 이 흐름은 꼭 눈여겨봐야 해요. '메모리 안전을 어떻게 보장하는가'는 앞으로 면접이나 코드 리뷰에서 점점 더 중요한 질문이 될 거거든요. 포인터에 범위 정보를 붙인다거나, 어셈블리의 메모리 효과를 명시한다는 발상 자체가 좋은 공부거리예요. 우리가 평소 무심코 쓰는 포인터가 사실 얼마나 위험한 물건인지 다시 돌아보게 되니까요.

정리하면

Fil-C의 인라인 어셈블리 지원은 '메모리 안전한 C는 현실적으로 불가능하다'는 통념에 던지는 반박이에요. 가장 안전을 망가뜨리기 쉬운 어셈블리조차 안전망 안으로 끌어들였으니까요.

여러분은 어떻게 생각하세요? 레거시 C 코드를 Fil-C처럼 감싸서 안전하게 만드는 길과, 아예 러스트로 다시 짜는 길—둘 중 어느 쪽이 더 현실적인 미래일까요?


🔗 출처: Hacker News

SOURCE · HACKER NEWS
원문 전체 보기 → https://fil-c.org/inlineasm
SHARE
처리 중...