← Wszystkie wpisy

Interpreter czcionek Apple jest teraz w Swifcie i o 13% szybszy

Zespół bezpieczeństwa Apple opublikował wynik z gatunku tych, które rozstrzygają spory. Interpreter hintingu TrueType, czyli interpreter bytecode, który od 1991 roku parsuje niezaufane dane czcionek na platformach Apple, został przepisany z C na bezpieczny pamięciowo Swift, a „średnio nasz interpreter w Swifcie działa o 13% szybciej niż interpreter w C, który zastąpił”.1 Wpis napisał Scott Perry, członek zespołu bezpieczeństwa Apple skupiony na adopcji Swifta, kod źródłowy znajduje się na GitHub jako implementacja referencyjna, a poprzeczką poprawności nie było „przechodzenie testów”, lecz renderowanie identyczne piksel w piksel względem oryginału w C.1 Bezpieczny pamięciowo, szybszy niż C i obecny w produkcji od wydań z jesieni 2025 roku — ten wpis stanowi najsilniejszą jak dotąd empiryczną odpowiedź na twierdzenie, że bezpieczeństwo pamięci kosztuje wydajność.

TL;DR

  • Apple przepisało interpreter hintingu TrueType z C na Swift, ponieważ parsery czcionek to krytyczna z punktu widzenia bezpieczeństwa powierzchnia ataku: interpreter uruchamia bytecode osadzony w czcionce, charakteryzujący się „przepływem sterowania zależnym od danych wejściowych, złożonymi strukturami danych i ostrożnym zarządzaniem pamięcią — czyli dokładnie takim rodzajem kodu, który trudno doprowadzić do perfekcji i w którym błędy pamięci łatwiej wykorzystać”.1
  • Rezultat trafił do wydań z jesieni 2025 roku, „od chwili włączenia nie zgłoszono w nim żadnych błędów” i jest średnio o 13% szybszy niż implementacja w C.1
  • Wydajność wzięła się z konkretnych, przenośnych technik: typy wartościowe ~Copyable i ~Escapable eliminujące narzut zliczania referencji i kontroli wyłączności, Span zapewniający bezpieczny dostęp do sekwencji, typy projekcji nad strukturami C, które usunęły kopiowania pochłaniające około 20% czasu działania, oraz utrzymywanie generyków w stanie umożliwiającym specjalizację.1
  • Weryfikacja była cichym arcydziełem: zestaw testów jednostkowych o pokryciu 99,7% dla obu implementacji, zminimalizowany przez fuzzer korpus 10 milionów plików PDF zredukowany do 4200 dokumentów osadzających 25 572 czcionki, 27 milionów glifów wyrenderowanych w czterech transformacjach każdy i porównanych bitmapa po bitmapie, a także prawie czterokrotnie więcej kodu testów niż kodu interpretera.1
  • Kod źródłowy interpretera opublikowano jako apple/truetype-hinting-interpreter-example na licencji MIT — jest to kod produkcyjny pomyślany jako implementacja referencyjna.2

Dlaczego interpreter czcionek to historia o bezpieczeństwie

Czcionki TrueType mogą zawierać programy. Format stworzony przez Apple pod koniec lat 80. zawiera silnik hintingu zbudowany wokół wyspecjalizowanego interpretera bytecode, zaprojektowanego tak, by zarys liter wiernie rasteryzował się na wyświetlaczach o niskiej rozdzielczości.1 Gdy w 1994 roku TrueType stał się osadzalny w plikach PDF, a w 2008 roku w stronach internetowych, ten interpreter zaczął wykonywać programy z „niezaufanych czcionek pochodzących z dowolnego miejsca w internecie”.1 Każdy, kto śledził historię bezpieczeństwa iOS, wie, jak to się zwykle kończy: parsery czcionek bywały elementem najsłynniejszych łańcuchów exploitów platformy, a wpis nazywa strukturalną przyczynę bez potrzeby sięgania po lekcję historii. Przepływ sterowania zależny od danych wejściowych w połączeniu z ręcznym zarządzaniem pamięcią to miejsce, w którym mieszkają błędy pamięci.

Ograniczenia, w jakich działał zespół, sprawiły, że przepisanie kodu było trudniejsze niż port pisany od zera. Zgodność binarna oznaczała, że istniejące programy „musiały nadal działać tak samo jak wcześniej, w praktyce nieświadome, że wdrożono nową implementację”, a ponieważ hinting może radykalnie zmienić wygląd glifów na ekranie, poprawność zdefiniowano jako „dokładną zgodność z wynikami implementacji w C”.1 Identyczność piksel w piksel, a nie tylko przybliżona poprawność.

Metodyka weryfikacji to właściwa historia o rzemiośle

Zanim przystąpiono do prac nad wydajnością, zespół zbudował aparat dowodowy. Zestaw testów jednostkowych obejmuje zarówno implementację w C, jak i w Swifcie z wyczerpującym pokryciem — 99,7% dla obu — i jest dostarczany razem z wydaniem open source.1 Aby uzyskać pokrycie odpowiadające realnym danym, użyto fuzzera do zminimalizowania korpusu 10 milionów plików PDF do 4200 bez utraty pokrycia kodu; te dokumenty osadzają 25 572 czcionki, których 27 milionów glifów wyrenderowano w czterech transformacjach każdy, a powstałe bitmapy porównano z interpreterem referencyjnym.1 Ostatecznie zespół napisał prawie czterokrotnie więcej wierszy kodu testów niż kodu interpretera.1

To właśnie ten stosunek warto przyswoić. Przepisanie kodu można było przeprowadzić agresywnie, ponieważ każda optymalizacja konfrontowana była z wyrocznią odpowiadającą, bitmapa po bitmapie, czy zachowanie się zmieniło. Wpis przypisuje zasługę dokładnie tej pętli: wyczerpujące pokrycie i dobrze zdefiniowane wewnętrzne granice „znacząco ułatwiają refaktoryzację, co z kolei przyspiesza pętlę optymalizacji typu mierz-i-popraw, jednocześnie minimalizując ryzyko wprowadzenia błędów”.1

Skąd wzięło się te 13%

Wpis dzieli pracę nad wydajnością na cztery kategorie, każda z przenośną lekcją.1

Wyeliminuj zliczanie referencji i kontrole wyłączności dzięki typom niekopiowalnym. Mechanizm ARC w Swifcie oraz kontrola wyłączności w czasie wykonania nakładają narzut, który aliasowanie jeszcze pogłębia, a specyfikacja interpretera wymusza nieredukowalną ilość aliasowania. Rozwiązanie było architektoniczne: przyjęto wszędzie typy wartościowe ~Copyable, a typy referencyjne zarezerwowano dla abstrakcji wysokiego poziomu, przy czym Span — wprowadzony w Swift 6.2 i wstecznie wdrażalny aż do macOS 10.14.4 oraz iOS 12.2 — zapewnia wydajny dostęp do sekwencji.1

Przestań kopiować na granicy języków. Kod w C przechowywał punkty glifów jako jedną strukturę z ośmiu tablic — przyjazną dla pamięci podręcznej, lecz niezgodną z duchem Swifta. Pierwszy kod pomostowy kopiował te dane do Swifta i z powrotem, a owe kopie pochłaniały około 20% czasu działania nowego interpretera.1 Zastąpiono to typami projekcji, które opakowują strukturę C i pośredniczą w bezpiecznym względem zakresów dostępie bez kopiowania, zgodnie z Safer Swift Guidelines projektu WebKit: niekopiowalna, nieuciekająca struktura @safe przechowująca Ref do elementu C, w której każde niebezpieczne wyrażenie opatrzono komentarzem // SAFETY: dokumentującym uzasadniający je inwariant.1

Pomijaj krótkotrwałe alokacje. Operacje takie jak filter i map dokonują alokacji, a alokacja ma znaczenie tylko wtedy, gdy wartość ucieka. Operacja zdejmowania ze stosu interpretera ewoluowała od oczywistej wersji alokującej tablicę zdjętych elementów do wersji z przekazywaniem kontynuacji: wywołujący przekazuje domknięcie, które operuje na borrowing Span elementów, zanim zostaną one usunięte, a sprawdzanie wyłączności w czasie kompilacji gwarantuje, że stosu nie da się zmodyfikować z wnętrza domknięcia.1 Brak alokacji na stercie, brak kopiowania elementów, a argument bezpieczeństwa ma charakter strukturalny, nie zaś wynikający z konwencji.

Utrzymuj generyki w stanie umożliwiającym specjalizację. Dynamiczne wiązanie wynikające z protokołów i generyków da się zwykle wyoptymalizować, lecz nie bezwarunkowo. Wskazówka zespołu dotycząca profilowania: „jeśli na gorących ścieżkach widzisz niewyspecjalizowane generyki albo tablice świadków protokołów, to znak, że optymalizator nie ma wystarczającej widoczności”, a implementacja może skorzystać na wstawianiu kodu w miejscu wywołania.1

Rezultat nie wymienił czytelności na szybkość. Wpis ujmuje to tak, że system typów Swifta umożliwił abstrakcje — typy numeryczne stałoprzecinkowe, element stosu z wbudowanymi konwersjami, wspomniane typy projekcji — które „nie dodały żadnego kosztu, a jednocześnie znacząco poprawiły czytelność”, gdy zbudowano je z optymalizacjami.1 Zespół jest też szczery co do zakresu: cały wewnętrzny stan interpretera to struktury niekopiowalne, lecz typ najwyższego poziomu pozostaje klasą @objc wywoływaną z Objective-C++, ponieważ „gorące ścieżki są szybkie, a zimne ścieżki są wygodne”.1

Cichy wątek agentowy

Jeden akapit pod koniec zasługuje na więcej uwagi, niż sugeruje jego umiejscowienie. Po ukończeniu migracji zespół „przekuł zdobytą wiedzę w instrukcje dla asystentów programistycznych opartych na LLM i od tamtej pory z powodzeniem stosuje je w innych projektach”, przy czym modele LLM poprawiły efektywność zespołu w przekształcaniu C i C++ na Swift.1 Zespół bezpieczeństwa Apple koduje wiedzę migracyjną jako instrukcje dla agentów i wykorzystuje ją ponownie w różnych bazach kodu — to ten sam wzorzec, który Apple uproduktowiło w tym cyklu jako eksportowalne umiejętności agentowe, opisane w eksporcie umiejętności agentowych w Xcode 27. Ręcznie zbudowana migracja staje się scenariuszem działania; scenariusz staje się dźwignią dla kolejnych dziesięciu migracji.

Co z tego wynieść

Wpis stawia trzy tezy, które jeszcze niedawno były dyskusyjne. Bezpieczny pamięciowo Swift może zastąpić krytyczny dla bezpieczeństwa kod w C na najgorętszej z gorących ścieżek — w interpreterze bytecode. Zamiennik może być szybszy, nie za sprawą magii, lecz dzięki typom niekopiowalnym, eliminacji kopiowania i projektowaniu sprzyjającemu specjalizacji. A migrację da się zweryfikować do identyczności piksel w piksel przy wystarczającej inwestycji w testy, którą zespół oszacował na mniej więcej 4:1 względem implementacji. Dla każdego, kto utrzymuje kod parsujący w C lub C++ stykający się z niezaufanymi danymi wejściowymi, połączenie tego wpisu, otwartego repozytorium i szczegółowych opcji włączania ścisłego bezpieczeństwa pamięci w Swift 6.4 sprawia, że „zmigrujemy kiedyś” jest wymiernie trudniejsze do obrony niż jeszcze w zeszłym tygodniu.

FAQ

Co dokładnie przepisało Apple?

Interpreter hintingu TrueType: interpreter bytecode, który wykonuje osadzone w czcionce programy hintingu, aby zarys glifów dobrze się rasteryzował — element stosu czcionek od czasów System 7 w 1991 roku.1 Przeszedł z C na bezpieczny pamięciowo Swift w wydaniach z jesieni 2025 roku, a jego wynik renderowania jest identyczny piksel w piksel z implementacją w C.1

Czy Swift jest tu naprawdę szybszy niż C?

Średnio tak: o 13% szybszy niż interpreter w C, który zastąpił, mierzone w megacyklach CPU na glif dla wszystkich czcionek z hintingiem dostarczanych w macOS oraz dla próbki czcionek niesystemowych.1 Zyski wzięły się z wyeliminowania zliczania referencji za pomocą typów niekopiowalnych, usunięcia kopiowania między językami dzięki typom projekcji, pomijania krótkotrwałych alokacji oraz utrzymywania generyków w stanie umożliwiającym specjalizację.1

Czy mogę przeczytać kod?

Tak. Apple opublikowało interpreter jako apple/truetype-hinting-interpreter-example na licencji MIT, opisując go jako kod produkcyjny pomyślany jako implementacja referencyjna, a nie jako stale rozwijany projekt open source.2 Zestaw testów jednostkowych jest dostarczany razem z nim.1

Dlaczego interpreter czcionek ma znaczenie dla bezpieczeństwa?

Ponieważ wykonuje programy pochodzące z niezaufanych danych wejściowych. Czcionki trafiają do stron internetowych i plików PDF z dowolnego miejsca, a połączenie przepływu sterowania zależnego od danych wejściowych z ostrożnym zarządzaniem pamięcią to dokładnie miejsce, w którym historycznie mieszkają exploity wykorzystujące uszkodzenia pamięci.1 Przeniesienie tej powierzchni do języka bezpiecznego pamięciowo usuwa całą klasę błędów, a wpis informuje, że od włączenia implementacji w Swifcie nie wystąpiły żadne błędy.1


Migracja potwierdza kierunek, który narzędzia Swifta sygnalizowały przez cały miesiąc: szczegółowa diagnostyka bezpieczeństwa pamięci w What’s New in Swift (2026), historia współbieżności wydajnej domyślnie w praktyce współbieżności w Swift 6.2 oraz ujęcie kwestii bezpieczeństwa, które Apple zaprotokołowało w swojej własnej odpowiedzi na prompt injection. Centrum całej serii to Apple Ecosystem Series.

Bibliografia


  1. Scott Perry, Swift at Apple: Migrating the TrueType Hinting Interpreter, blog Swift.org, 12 czerwca 2026. Źródło informacji o roli autora (zespół bezpieczeństwa Apple, skupiony na adopcji Swifta), ujęciu kwestii bezpieczeństwa (parsery czcionek przetwarzają niezaufane dane; „przepływ sterowania zależny od danych wejściowych, złożone struktury danych i ostrożne zarządzanie pamięcią — czyli dokładnie taki rodzaj kodu, który trudno doprowadzić do perfekcji i w którym błędy pamięci łatwiej wykorzystać”), historii TrueType (opracowany przez Apple pod koniec lat 80., dostarczony z System 7 w 1991 roku, osadzalny w plikach PDF w 1994 roku i w stronach internetowych w 2008 roku), dacie wdrożenia z jesieni 2025 roku, średniej poprawie wydajności o 13% mierzonej w megacyklach CPU na glif, stwierdzeniu o braku błędów od włączenia, wymaganiach zgodności binarnej i poprawności identycznej piksel w piksel, metodyce weryfikacji (pokrycie 99,7% dla obu implementacji, korpus 10 milionów plików PDF zminimalizowany przez fuzzer do 4200 dokumentów, 25 572 osadzone czcionki, 27 milionów glifów w czterech transformacjach, prawie czterokrotnie więcej kodu testów), czterech kategoriach optymalizacji (typy wartościowe ~Copyable i Span z wstecznym wdrożeniem do macOS 10.14.4 oraz iOS 12.2; typy projekcji nad strukturami C po tym, jak kopiowanie pochłaniało około 20% czasu działania, zgodnie z Safer Swift Guidelines projektu WebKit z komentarzami @safe i // SAFETY:; zdejmowanie ze stosu z przekazywaniem kontynuacji nad borrowing Span; wskazówki dotyczące specjalizacji i wstawiania kodu w miejscu wywołania), ujęciu abstrakcji o zerowym koszcie, granicy najwyższego poziomu @objc („gorące ścieżki są szybkie, a zimne ścieżki są wygodne”) oraz instrukcjach dla asystentów LLM przekutych z migracji i wykorzystanych ponownie w innych projektach przekształcania C i C++ na Swift. 

  2. Apple, truetype-hinting-interpreter-example, GitHub, licencja MIT. Źródło informacji o istnieniu repozytorium, jego licencji i opisie jako interpretera TrueType w Swifcie, opublikowanego jako kod produkcyjny pomyślany jako implementacja referencyjna. 

Powiązane artykuły

Nakaz scen w UIKit: co nie uruchomi się na iOS 27

Aplikacje zbudowane z użyciem SDK iOS 27 muszą przyjąć oparty na scenach cykl życia UIKit, inaczej nie uruchomią się. Ha…

8 min czytania

Container machines: trwałe środowisko Linux na Macu

Narzędzie container od Apple osiąga wersję 1.0 wraz z container machine: szybkim, trwałym środowiskiem Linux na macOS, w…

9 min czytania

Od 76 do 100: Osiągnięcie idealnego wyniku Lighthouse

Jak osobista strona portfolio przeszła od mobilnego wyniku wydajności Lighthouse na poziomie 76 z CLS 0,493 do idealnego…

6 min czytania