애플의 폰트 인터프리터가 이제 Swift로 작성되어 13% 더 빨라졌습니다
애플 보안팀이 논쟁을 끝내는 종류의 결과를 발표했습니다. 1991년부터 애플 플랫폼에서 신뢰할 수 없는 폰트 데이터를 파싱해 온 바이트코드 인터프리터인 TrueType 힌팅 인터프리터가 C에서 메모리 안전한 Swift로 다시 작성되었고, “평균적으로 우리의 Swift 인터프리터는 자신이 대체한 C 인터프리터보다 13% 더 빠르게 실행됩니다.”1 이 글은 Swift 도입에 집중하는 애플 보안팀의 일원인 Scott Perry가 작성했으며, 소스 코드는 참조 구현으로 GitHub에 공개되어 있고, 정확성의 기준은 “테스트 통과”가 아니라 C 원본과 픽셀 단위로 동일한 렌더링이었습니다.1 메모리 안전하고, C보다 빠르며, 2025년 가을 릴리스부터 프로덕션에 출시되었습니다. 이 글은 메모리 안전성이 성능을 희생시킨다는 주장에 대한 지금까지 나온 가장 강력한 경험적 답변입니다.
TL;DR
- 애플이 TrueType 힌팅 인터프리터를 C에서 Swift로 다시 작성한 이유는 폰트 파서가 보안에 결정적인 공격 표면이기 때문입니다. 이 인터프리터는 폰트에 내장된 바이트코드를 실행하는데, 여기에는 “입력에 따라 결정되는 제어 흐름, 복잡한 데이터 구조, 그리고 세심한 메모리 관리가 결합되어 있습니다. 정확히 완벽하게 만들기 어렵고 메모리 오류를 악용하기 더 쉬운 종류의 코드입니다.”1
- 그 결과는 2025년 가을 릴리스에 출시되었고, “활성화된 이후 보고된 버그가 없으며”, C 구현보다 평균 13% 더 빠릅니다.1
- 성능 향상은 구체적이고 이식 가능한 기법에서 나왔습니다. 참조 카운팅과 배타성(exclusivity) 오버헤드를 제거하기 위한
~Copyable및~Escapable값 타입, 안전한 시퀀스 접근을 위한Span, 런타임의 약 20%를 차지하던 복사를 제거한 C 구조체에 대한 프로젝션 타입, 그리고 제네릭을 특수화 가능하게 유지하는 것입니다.1 - 검증은 조용한 걸작이었습니다. 두 구현 모두에서 99.7%의 커버리지를 갖춘 단위 테스트 묶음, 퍼저로 최소화하여 1,000만 개의 PDF를 25,572개의 폰트를 임베딩한 4,200개의 문서로 줄인 코퍼스, 각각 네 가지 변환을 거쳐 렌더링하고 비트맵 단위로 비교한 2,700만 개의 글리프, 그리고 인터프리터 코드의 거의 네 배에 달하는 테스트 코드가 그것입니다.1
- 인터프리터 소스는
apple/truetype-hinting-interpreter-example에 MIT 라이선스로, 참조 구현을 의도한 프로덕션 코드로서 공개되어 있습니다.2
폰트 인터프리터가 보안 이야기인 이유
TrueType 폰트는 프로그램을 담을 수 있습니다. 애플이 1980년대 후반에 만든 이 포맷에는 특수 목적의 바이트코드 인터프리터를 중심으로 구축된 힌팅 엔진이 들어 있으며, 이는 저해상도 디스플레이에서 윤곽선이 충실하게 래스터화되도록 설계되었습니다.1 TrueType이 1994년에 PDF에, 2008년에 웹 페이지에 임베딩될 수 있게 되면서, 그 인터프리터는 “인터넷 어디에서든 오는 신뢰할 수 없는 폰트”의 프로그램을 실행하기 시작했습니다.1 iOS 보안 역사를 따라온 사람이라면 그 이야기가 어떻게 흘러가는지 압니다. 폰트 파서는 플랫폼에서 가장 유명한 익스플로잇 체인 일부를 짊어져 왔으며, 이 글은 그 역사 강의 없이도 구조적 원인을 짚어냅니다. 입력에 따라 결정되는 제어 흐름과 수동 메모리 관리가 결합되는 곳, 그곳에 메모리 오류가 산다는 것입니다.
팀의 제약 조건은 이 재작성을 백지 상태에서의 포팅보다 어렵게 만들었습니다. 바이너리 호환성이란 기존 프로그램이 “새 구현이 자리 잡았다는 사실을 사실상 인지하지 못한 채, 이전과 똑같이 계속 동작해야 한다”는 것을 의미했고, 힌팅이 화면상 글리프의 모습을 근본적으로 바꿀 수 있기 때문에 정확성은 “C 구현 출력과의 정확한 호환성”으로 정의되었습니다.1 대략 맞는 것이 아니라 픽셀 단위로 동일해야 했습니다.
검증 방법론이 곧 장인 정신의 이야기입니다
성능 작업에 앞서, 팀은 증명을 위한 장치를 먼저 구축했습니다. 단위 테스트 묶음은 C와 Swift 구현 모두를 대상으로 철저한 커버리지를 노렸으며, 두 구현 모두 99.7%였고, 오픈소스 릴리스에 함께 제공됩니다.1 실제 환경에 가까운 커버리지를 위해, 팀은 퍼저를 사용해 1,000만 개의 PDF 파일 코퍼스를 코드 커버리지 손실 없이 4,200개로 최소화했습니다. 이 문서들은 25,572개의 폰트를 임베딩하고 있으며, 그 폰트들의 2,700만 개 글리프를 각각 네 가지 변환을 거쳐 렌더링한 뒤, 그 결과 비트맵을 참조 인터프리터와 비교했습니다.1 작업이 끝날 무렵, 팀은 인터프리터 코드의 거의 네 배에 달하는 줄의 테스트 코드를 작성한 상태였습니다.1
그 비율이 바로 체화할 가치가 있는 부분입니다. 모든 최적화가 비트맵 단위로 동작이 바뀌었는지 답해 주는 오라클을 상대로 돌아갔기 때문에, 이 재작성은 공격적으로 진행할 수 있었습니다. 이 글은 바로 그 루프를 공로로 인정합니다. 철저한 커버리지와 잘 정의된 내부 경계는 “리팩터링을 상당히 쉽게 만들고, 이는 다시 버그를 도입할 위험을 최소화하면서 측정-수정 최적화 루프를 가속합니다.”1
13%는 어디에서 왔는가
이 글은 성능 작업을 네 가지 범주로 나누며, 각각에 이식 가능한 교훈을 담고 있습니다.1
비복사 타입으로 참조 카운팅과 배타성 검사를 없앤다. Swift의 ARC와 런타임 배타성 검사는 앨리어싱(aliasing)이 더 악화시키는 오버헤드를 부과하며, 인터프리터의 명세에는 줄일 수 없는 양의 앨리어싱이 본질적으로 내재되어 있습니다. 해법은 구조적이었습니다. 전반에 걸쳐 ~Copyable 값 타입을 채택하고 참조 타입은 고수준 추상화를 위해 남겨 두었으며, Swift 6.2에서 도입되어 macOS 10.14.4 및 iOS 12.2까지 백배포(back-deploy)되는 Span이 시퀀스에 대한 효율적인 접근을 제공했습니다.1
언어 경계에서 복사를 멈춘다. C 코드는 글리프 포인트를 여덟 개 배열로 이루어진 하나의 구조체로 저장했는데, 이는 캐시 친화적이지만 Swift답지는 않았습니다. 첫 번째 브리징 코드는 그 데이터를 Swift로, 그리고 다시 C로 복사했고, 그 복사가 새 인터프리터 런타임의 약 20%를 차지했습니다.1 그 대체물은 C 구조를 감싸고 복사 없이 경계 검사가 보장된 접근을 중개하는 프로젝션 타입으로, WebKit의 Safer Swift Guidelines를 따랐습니다. C 요소에 대한 Ref를 담은 @safe 비복사·비탈출 구조체이며, 모든 안전하지 않은 표현식에는 그것을 정당화하는 불변식을 문서화하는 // SAFETY: 주석이 달려 있습니다.1
수명이 짧은 할당을 제거한다. filter나 map 같은 연산은 할당을 일으키지만, 그 할당은 값이 탈출하는 경우에만 의미가 있습니다. 인터프리터의 스택 팝 연산은, 팝된 요소의 배열을 할당하던 명백한 버전에서 연속 전달(continuation-passing) 버전으로 발전했습니다. 호출자가 클로저를 전달하면, 그 클로저는 요소들이 제거되기 전에 그것들의 borrowing Span을 대상으로 동작하며, 컴파일 타임 배타성 검사가 클로저 내부에서 스택이 변경될 수 없음을 보장합니다.1 힙 할당도 없고, 요소 복사도 없으며, 안전성 논증은 관례가 아니라 구조에 기반합니다.
제네릭을 특수화 가능하게 유지한다. 프로토콜과 제네릭에서 비롯되는 동적 디스패치는 대개 최적화로 제거할 수 있지만, 무조건 그런 것은 아닙니다. 프로파일링에 대한 팀의 지침은 이렇습니다. “핫 패스에서 특수화되지 않은 제네릭이나 프로토콜 위트니스 테이블이 보인다면, 그것은 옵티마이저가 충분한 가시성을 갖지 못했다는 신호입니다.” 이 경우 구현은 인라이닝으로 이득을 볼 수 있습니다.1
그 결과는 가독성을 속도와 맞바꾸지 않았습니다. 이 글의 관점은, Swift의 타입 시스템이 추상화를 가능하게 했다는 것입니다. 고정 소수점 숫자 타입, 변환 기능이 내장된 스택 요소, 프로젝션 타입 같은 것들은, 최적화를 켜고 구축했을 때 “비용을 전혀 더하지 않으면서 가독성을 상당히 개선했습니다.”1 그리고 팀은 범위에 대해 솔직합니다. 인터프리터의 내부 상태는 모두 비복사 구조이지만, 최상위 타입은 Objective-C++에서 호출되는 @objc 클래스로 남아 있습니다. “핫 패스는 빠르고, 콜드 패스는 편리하기” 때문입니다.1
조용한 에이전트 측면
글 말미 가까이에 있는 한 단락은 그 위치가 시사하는 것보다 더 많은 관심을 받을 만합니다. 마이그레이션을 완료한 뒤, 팀은 “우리가 배운 것을 LLM 코딩 어시스턴트를 위한 지침으로 정제했고, 그 이후로 다른 프로젝트들에서 성공적으로 사용해 왔습니다.” LLM은 C와 C++를 Swift로 변환하는 팀의 효율을 높여 주었습니다.1 애플 보안팀은 마이그레이션 전문성을 에이전트 지침으로 인코딩하고 코드베이스 전반에서 재사용하고 있습니다. 이는 애플이 이번 사이클에 내보낼 수 있는 에이전트 스킬로 제품화한 바로 그 패턴으로, Xcode 27의 에이전트 스킬 내보내기에서 다룬 바 있습니다. 손으로 만든 마이그레이션 하나가 플레이북이 되고, 그 플레이북은 다음 열 번의 마이그레이션을 위한 지렛대가 됩니다.
여기서 무엇을 가져갈 것인가
이 글은 한때 논쟁의 여지가 있던 세 가지 주장을 확실히 매듭짓습니다. 메모리 안전한 Swift는 가장 뜨거운 핫 패스, 즉 바이트코드 인터프리터에서도 보안에 결정적인 C를 대체할 수 있습니다. 그 대체물은 마법이 아니라 비복사 타입, 복사 제거, 그리고 특수화 친화적인 설계를 통해 더 빠를 수 있습니다. 그리고 그 마이그레이션은, 팀이 구현 대비 대략 4:1로 규모를 잡은 충분한 테스트 투자만 있다면 픽셀 단위로 동일한 동등성까지 검증될 수 있습니다. 신뢰할 수 없는 입력을 다루는 C나 C++ 파싱 코드를 가진 사람이라면 누구에게나, 이 글과 공개 저장소, 그리고 Swift 6.4의 세분화된 엄격 메모리 안전성 옵트인의 조합은 “언젠가 마이그레이션할 것”이라는 말을 지난주보다 측정 가능할 만큼 더 변호하기 어렵게 만듭니다.
FAQ
애플이 정확히 무엇을 다시 작성했나요?
TrueType 힌팅 인터프리터입니다. 글리프 윤곽선이 잘 래스터화되도록 폰트에 내장된 힌팅 프로그램을 실행하는 바이트코드 인터프리터로, 1991년 System 7 이래로 폰트 스택의 일부였습니다.1 이것이 2025년 가을 릴리스에서 C에서 메모리 안전한 Swift로 바뀌었으며, 렌더링 출력은 C 구현과 픽셀 단위로 동일합니다.1
여기서 Swift가 정말로 C보다 빠른가요?
평균적으로는 그렇습니다. 대체한 C 인터프리터보다 13% 더 빠르며, 이는 macOS에 출시되는 모든 힌팅 폰트와 시스템 외 폰트 표본에 걸쳐 글리프당 CPU 메가사이클로 측정되었습니다.1 그 이득은 비복사 타입을 통한 참조 카운팅 제거, 프로젝션 타입을 통한 언어 간 복사 제거, 수명이 짧은 할당 제거, 그리고 제네릭을 특수화 가능하게 유지한 데서 나왔습니다.1
코드를 읽어볼 수 있나요?
네. 애플은 인터프리터를 apple/truetype-hinting-interpreter-example에 MIT 라이선스로 공개했으며, 이는 지속적인 오픈소스 프로젝트라기보다는 참조 구현을 의도한 프로덕션 코드로 설명됩니다.2 단위 테스트 묶음도 함께 제공됩니다.1
폰트 인터프리터가 왜 보안에 중요한가요?
신뢰할 수 없는 입력의 프로그램을 실행하기 때문입니다. 폰트는 어디에서든 웹 페이지와 PDF를 통해 도착하며, 입력에 따라 결정되는 제어 흐름과 세심한 메모리 관리가 결합된 인터프리터는 정확히 메모리 손상 익스플로잇이 역사적으로 살아온 곳입니다.1 그 표면을 메모리 안전한 언어로 옮기면 버그의 부류 전체가 사라지며, 이 글은 Swift 구현이 활성화된 이후 버그가 없었다고 보고합니다.1
이 마이그레이션은 Swift의 도구 체계가 이번 달 내내 신호로 보내 온 방향을 입증합니다. What’s New in Swift (2026)의 세분화된 메모리 안전성 진단, 실전에서의 Swift 6.2 동시성의 기본값으로서의 성능 이야기, 그리고 애플이 프롬프트 인젝션에 대한 1차 답변으로 공식 기록에 남긴 보안 관점이 그것입니다. 전체 시리즈 허브는 Apple Ecosystem Series입니다.
References
-
Scott Perry, Swift at Apple: Migrating the TrueType Hinting Interpreter, Swift.org blog, June 12, 2026. Source for the author’s role (Apple Security team, focusing on Swift adoption), the security framing (font parsers process untrusted data; “input-driven control flow, complex data structures, and careful memory management—exactly the kind of code that’s hard to make perfect and where memory errors are easier to exploit”), the TrueType history (developed by Apple in the late 1980s, shipped with System 7 in 1991, embeddable in PDFs in 1994 and web pages in 2008), the Fall 2025 ship date, the 13% average performance improvement measured in CPU megacycles per glyph, the no-bugs-since-enabled statement, the binary-compatibility and pixel-identical correctness requirements, the verification methodology (99.7% coverage across both implementations, the 10-million-PDF corpus fuzzer-minimized to 4,200 documents, 25,572 embedded fonts, 27 million glyphs under four transformations, nearly 4x test code), the four optimization categories (
~Copyablevalue types andSpanwith back-deployment to macOS 10.14.4 and iOS 12.2; projection types over C structs after copies cost about 20% of runtime, following WebKit’s Safer Swift Guidelines with@safeand// SAFETY:comments; continuation-passing stack pops overborrowing Span; specialization and inlining guidance), the zero-cost-abstractions framing, the@objctop-level boundary (“the hot paths are fast, and the cold paths are convenient”), and the LLM-assistant instructions distilled from the migration and reused on other C/C++-to-Swift projects. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple, truetype-hinting-interpreter-example, GitHub, MIT license. Source for the repository’s existence, license, and its description as the Swift TrueType Interpreter, published as production code intended as a reference implementation. ↩↩