Skip to content

Split View: Ferrocene의 인증된 core — 컴파일러는 ASIL D인데 라이브러리는 왜 ASIL B에서 멈추나

|

Ferrocene의 인증된 core — 컴파일러는 ASIL D인데 라이브러리는 왜 ASIL B에서 멈추나

들어가며 — "ASIL D 인증 Rust 컴파일러"라는 말의 함정

임베디드 Rust 이야기가 나올 때마다 반복되는 문장이 있습니다. "Ferrocene이 ISO 26262 ASIL D 인증을 받았다." 이 문장 자체는 틀리지 않습니다. Ferrous Systems의 공개 문서가 정확히 그렇게 적고 있으니까요.

문제는 이 문장에서 사람들이 유추하는 결론입니다. "그럼 이제 Rust로 ASIL D 소프트웨어를 짜면 되겠네." 아닙니다. 여기엔 서로 다른 두 개의 주장이 하나로 뭉개져 있고, 2026년 상반기에 실제로 움직인 것은 뭉개진 쪽이 아니라 그 아래에 있던 쪽 — core 라이브러리 — 입니다.

이 글은 그 이야기입니다. Ferrocene이 2025년 12월부터 2026년 5월까지 무엇을 실제로 인증했는지, 왜 컴파일러는 ASIL D인데 라이브러리는 ASIL B에서 멈추는지, 그 천장이 어디서 오는지, 그리고 무엇이 여전히 당신 몫으로 남는지를 봅니다. 결론부터 말하면, 이 이야기의 가장 값진 부분은 벤더가 감춘 것이 아니라 벤더가 스스로 적어 둔 것에 있습니다.

도구 자격심사와 소프트웨어 인증은 다른 물건이다

먼저 용어 정리입니다. 이게 이 글 전체의 뼈대입니다.

Ferrocene 컴파일러(rustc)도구로서 자격심사(qualification)를 받았습니다. Ferrocene 자격심사 보고서(Qualification Report)의 첫 문장이 이렇게 적습니다 — 이 문서는 자동차 ISO 26262:2018 (ASIL D / TCL 3), 산업 IEC 61508:2010 (class T3), 의료 IEC 62304:2006 + AMD 1:2015 표준 인증을 위해 개발된 자격심사 자료의 보고서다.

여기서 핵심 약어가 TCL입니다. Tool Confidence Level — 도구 신뢰 수준. ISO 26262 part 8의 clause 11이 다루는 것은 "소프트웨어 도구 사용에 대한 확신"이지 도구가 뱉어낸 코드의 무결성 수준이 아닙니다. TCL 3에서 ASIL D 자격심사를 받았다는 건 "ASIL D 개발에 이 컴파일러를 써도 좋다"는 뜻입니다. "컴파일 결과물이 ASIL D"라는 뜻이 아닙니다.

core 라이브러리 서브셋 은 완전히 다른 물건입니다. 이건 도구가 아니라 소프트웨어 컴포넌트이고, 소프트웨어로서 인증(certification)을 받았습니다. 같은 자격심사 보고서가 이어서 이렇게 적습니다 — 이 문서의 일부는 자동차 ISO 26262:2018 (ASIL B) 및 산업 IEC 61508:2010 (SIL 2) 소프트웨어 표준 인증을 위해 개발된 Core Library Certification에서 참조될 수 있다.

이 두 숫자는 마케팅 문구가 아니라 문서 빌드 시스템의 설정 파일에 기계가 읽을 수 있는 형태로 박혀 있습니다. Ferrocene 저장소의 ferrocene/doc/sphinx-substitutions.toml을 열면 이렇습니다.

iso_26262_ferrocene_asil = "ASIL D"
iso_26262_core_asil = "ASIL B"
iso_26262_ferrocene_tcl = "TCL 3"
iso_26262_ferrocene_tql = "class T3"

iec_61508_core_sil = "SIL 2"

컴파일러는 ASIL D / TCL 3, core는 ASIL B. 26.02.0 브랜치와 26.05.0 브랜치의 이 파일은 한 글자도 다르지 않습니다. 즉 ASIL B 천장은 최신 릴리스에서도 그대로입니다.

그리고 안전 매뉴얼(Safety Manual)의 "Qualification scope" 장은 사용자 책임을 이렇게 못 박습니다 — ISO 26262:2018 part 8의 clause 11.4.2에 따라, 사용자는 안전 관련 개발에 이 소프트웨어 도구를 쓰기 전에 사전 결정된 TCL의 유효성을 검증해야 한다. 그리고 clause 11.4.3에 따라, 사용자는 이 도구의 사용법·환경·기능적 제약이 그 평가 기준 또는 자격심사에 부합하는지 보장해야 한다.

읽어 보면 알겠지만, 이건 "우리가 다 해 뒀으니 갖다 쓰세요"가 아니라 "우리 자격심사의 유효 범위를 당신이 검증하라"는 문장입니다.

2025년 12월에서 2026년 5월까지 — 실제로 일어난 일

시간순으로 정리하면 이렇습니다.

2025년 12월 3일 — 첫 core 서브셋, IEC 61508 SIL 2. Ferrous Systems가 보도자료로 발표했습니다. TÜV SÜD가 Rust core 라이브러리의 첫 서브셋을 IEC 61508 (SIL 2)로 인증했고, 이 서브셋은 Ferrocene 25.11.0에 포함됩니다. 인증은 Ferrocene 툴체인과 자격심사된 타깃(Armv7E-M, Armv8-A 포함)에서의 사용에 적용됩니다. 작업은 2023년에 시작됐고 Cryspen과 Thoughtworks가 도구와 시간을 보탰습니다. Ferrous의 매니징 디렉터 Florian Gilcher의 말을 그대로 옮기면 — "Rust는 core 없이 임베디드나 안전 필수 환경에서 돌리는 게 비현실적이고, core는 Ferrocene 같은 툴체인으로 엄밀히 검증하지 않으면 인증될 수 없다."

같은 자료가 실제 도입 사례를 둘 듭니다. Sonair는 자율 로봇용 3D 초음파 센서 ADAR에 쓰고 있고(쿼드코어 Armv8-A 위에서, Armv7E-M 서브시스템과 함께 돌아갑니다), Kiteshield는 지하 광산의 수동·자율 장비 충돌 방지 시스템에 쓰고 있으며 최종적으로 IEC 61508 SIL 3까지 요구되는 컴포넌트가 있다고 합니다.

2026년 2월 15일 — ASIL B 추가, 서브셋 확대. 26.02.0 릴리스입니다. 인증된 core 서브셋에 ISO 26262 (ASIL B)가 추가됐고, SIL 2 서브셋 자체도 크게 넓어졌습니다. 벤더 발표 수치로 인증 함수 개수가 2,903개에서 5,169개로 늘었고, core::slice, core::iter, core::ffi, core::result 같은 모듈이 확장됐으며 최소 인증 패닉 훅이 들어갔습니다. 저장소의 ferrocene/version 파일이 확인해 주듯 이 릴리스의 rustc는 1.92입니다. eeNews Europe도 독립적으로 보도했습니다 — embedded world 2026에서 공개됐고, 요점은 인증이 컴파일러 툴체인을 넘어 라이브러리 계층으로 내려왔다는 것.

2026년 5월 — core::fmt 인증, 그리고 강제 방식 교체. 여기서부터 흥미로워집니다. 26.05.0에는 발표 블로그 글이 없습니다. ferrous-systems.com/blog/ferrocene-26-05-0/는 404이고, 블로그 인덱스의 마지막 Ferrocene 릴리스 공지는 여전히 26.02.0입니다. 하지만 릴리스는 나갔습니다 — 저장소의 release/1.95 브랜치에서 ferrocene/version26.05.0을 담고 있고, 릴리스 노트에서 :upcoming-release: 마커가 제거돼 있습니다(반면 release/1.97의 26.08은 아직 그 마커를 달고 있습니다). 내용은 이렇습니다.

  • core::fmt 모듈이 ISO 26262 (ASIL B)와 IEC 61508 (SIL 2)로 인증됐습니다. Rust 자료구조를 사람이 읽을 수 있는 출력으로 포맷하는 코드입니다.
  • 그 결과로 "인증 패닉 런타임" 타깃들(aarch64-ferrocene-none, thumbv7em-ferrocene-none-eabi 등)이 퇴역했습니다. 포맷 코드를 인증하지 않은 채로 패닉만 인증하려고 만든 물건이었는데, 이제 필요가 없어진 겁니다.
  • ferrocene::unvalidated 린트가 도입되고 "서브셋 타깃"들이 퇴역했습니다. 뒤에서 자세히 다룹니다.
  • 새 자격심사 타깃 aarch64-rhivos2-linux-gnu가 추가됐고(aarch64-unknown-linux-gnu 호스트에서 컴파일할 때만), proc_macro 크레이트 타입이 허용됐습니다.
  • thumbv7em-m4-none-eabihfaarch64-a53-none이 제거됐습니다. 26.02.0에서 새로 추가됐던 그 타깃들인데, 이제 베이스 타깃에서 -C target-cpu=cortex-m4 / -C target-cpu=cortex-a53을 쓰면 같은 일이 됩니다.

26.05.0의 core::fmt 인증은 사용자 매뉴얼에서도 흔적이 보입니다. 26.02.0의 core/using.rst에는 이런 경고가 있었습니다 — 인증 타깃을 쓸 때 core 라이브러리의 동작이 다르다, 특히 panic! 매크로가 임의의 format_args!가 아니라 정적 문자열만 지원하므로 패닉 메시지가 덜 유익할 수 있다. 26.05.0의 같은 파일에서 이 문단은 통째로 사라졌습니다.

독립 검증. 저장소에는 인증된 심볼의 권위 있는 목록이 CSV로 들어 있습니다(ferrocene/doc/symbol-report.csv, core-certification 문서의 Safety Report 장이 이 파일을 그대로 포함합니다). 두 릴리스 브랜치에서 받아 세어 보면 이렇습니다.

release/1.92 (26.02.0):  5,235 unique symbols   core::fmt 심볼:   0
release/1.95 (26.05.0):  8,790 unique symbols   core::fmt 심볼: 535
                         (추가 3,597 / 제거 42)

core::fmt 인증이 실제로 반영됐다는 걸 릴리스 노트와 무관하게 확인해 주는 숫자입니다. 다만 정직하게 덧붙이면, 26.02.0 CSV의 5,235개는 벤더가 발표한 "5,169개 인증 함수"와 정확히 맞아떨어지지 않습니다. 파일 이름이 말해 주듯 이건 심볼 리포트고 발표문은 함수를 셌으니 집계 기준이 다를 가능성이 큽니다. 그러니 5,169라는 숫자는 벤더 자체 집계로 읽으시고, 확실한 건 자릿수와 방향입니다 — 한 릴리스에 서브셋이 대략 1.7배가 됐습니다.

제거된 42개도 재미있습니다. 대부분 core::panicking::PanicArguments::as_str 같은 옛 인증 패닉 런타임 부품과 derive 내부 마커(assert_receiver_is_total_eq)입니다. 서브셋은 늘기만 하는 게 아니라 줄기도 합니다.

2026년 8월(예정). release/1.97의 26.08은 아직 upcoming 마커를 달고 있고, 세 개의 새 자격심사 타깃을 예고합니다 — aarch64-unknown-qnx, armv7r-none-eabihf, x86_64-pc-qnx. flip-link가 quality managed로 올라갑니다.

왜 core 전체가 아니라 서브셋인가

Ferrous의 컴파일러 엔지니어 Jynn이 쓴 Callgraph analysis(2026년 4월 1일)가 이유를 대놓고 설명합니다. 인증 대상은 IEC 61508 (SIL 2)이었고, 이 표준의 요구사항 중 코드베이스 크기에 비례해 늘어나는 것이 Annex A.9 "Software verification"입니다. Ferrous는 방법 3과 4(정적 분석, 동적 분석)를 씁니다. 문서화한 접근은 인증 core가 있는 모든 타깃 플랫폼에서 테스트를 돌리고, 모든 함수가 테스트됐음을 검증하는 코드 커버리지를 수집하는 것입니다.

그러니까 코드가 많을수록 테스트를 더 써야 합니다. 원문의 표현을 그대로 옮기면 — 제품이 나오기까지 몇 년치 작업을 하는 걸 피하려고, core의 서브셋만 검증하기로 했다. 함수들을 validated로 표시하고, 각각에 대해 테스트를 돌려 커버리지를 모으고, 고객에게는 그 검증된 함수만 쓰라고 말하는 방식입니다.

인증의 형식적 경로도 문서에 적혀 있습니다. core-certification 문서의 Certification scope 장에 따르면, IEC 61508 쪽은 section 7.4.2.12의 Route 3S — "비준수 개발의 평가(Assessment of non-compliant development)" — 이고, ISO 26262 쪽은 SEooC(Safety Element out of Context) 소프트웨어 개발로 part 2/6/8을 테일러링한 것입니다.

Route 3S가 무슨 뜻인지 감이 안 온다면 이렇게 생각하면 됩니다. Rust의 core는 IEC 61508을 염두에 두고 개발된 적이 없습니다. 애초에 표준을 따라 개발되지 않은 물건을 사후에 평가해서 쓸 만한지 판정하는 경로가 Route 3S입니다. 그리고 ISO 26262의 적용 절 목록을 보면 흥미로운 항목이 하나 있습니다 — "8-12 소프트웨어 컴포넌트의 자격심사"는 적용 안 함으로 적혀 있고, 사유는 "자격심사를 적용하지 않고 신규 개발로 취급"입니다. 즉 기존 소프트웨어 자격심사 경로를 타지 않고 새로 개발하는 것처럼 증거를 쌓았다는 뜻입니다.

서브셋을 어떻게 강제하는가 — cfg 해킹에서 콜그래프 린트로

여기가 이 이야기에서 가장 엔지니어링다운 부분입니다.

문제는 이렇습니다. "인증된 함수만 쓰세요"라고 말하는 건 쉬운데, 사용자가 자기가 core의 어느 부분을 쓰고 있는지 알 방법이 없습니다. Callgraph 글이 정확히 짚습니다 — core는 평범한 라이브러리가 아니라 컴파일러·언어와의 광범위한 통합을 품고 있습니다. do_io()?처럼 무해해 보이는 걸 쓰면 실제로는 core::ops::try_trait::Try::branch 호출이 나갑니다. 어느 함수가 어느 함수를 부르는지 알려면 진짜 컴파일러 통합이 필요합니다.

1차 시도(25.11, 26.02): cfg 포크 + 가짜 서브셋 타깃. 표준 라이브러리를 포크해서 패닉 기계장치 전체에 cfg를 발라 버리는 방식입니다. 그런데 이러면 인증에 관심 없는 모든 사용자까지 영향을 받으니, 깨는 변경을 피하려고 aarch64-unknown-ferrocene.subset 같은 새 타깃을 통째로 만들었습니다. Ferrous 스스로의 평가는 냉정합니다 — 빌드 스크립트가 타깃 이름을 파싱하지 못했고, libtest가 cfg로 잘려나간 core 부분을 쓰기 때문에 그 타깃에서 컴파일할 수 없었으며, 실무적으로는 사람들에게 "cargo check --target aarch64-unknown-none.subset은 돌리되 풀 빌드에는 쓰지 마세요"라고 안내해야 했고, 이건 매우 나쁜 사용자 경험이었다.

안전 매뉴얼도 같은 말을 경고 상자로 적어 뒀습니다 — 서브셋 타깃은 오직 서브셋 준수 검증에만 쓸 수 있고, 런타임에 인증 타깃으로 쓸 수 없다.

2차 시도(26.05): 커스텀 rustc 드라이버 위의 린트. 26.05.0이 도입한 ferrocene::unvalidated 린트입니다. 지금 준수를 증명하는 절차는 안전 매뉴얼 기준으로 이렇게 짧아졌습니다.

// 1. 각 크레이트 루트에서 린트를 켠다
#![warn(ferrocene::unvalidated)]

// 2. -D warnings 로 컴파일한다. 성공하면 서브셋을 지킨 것이다.
//
// 실패하면 넷 중 하나:
//   a) 그 함수가 내 크레이트 것이면 #[ferrocene::prevalidated] 를 붙인다
//   b) core의 함수면 Ferrous에 연락해 서브셋 추가를 논의한다
//   c) 호출을 지우고 같은 의미로 다시 쓴다
//   d) 계속 쓰되 안전성을 직접 증명하고 #[allow(ferrocene::unvalidated)] 를 단다

린트가 지키는 불변식은 한 문장으로 정리됩니다 — core의 validated 함수 집합은 함수 호출 연산에 대해 닫혀 있어야 한다. validated 함수 안에서 호출이 보이면 호출되는 쪽도 validated여야 한다는 뜻입니다. 반대 방향은 상관없습니다. 인증되지 않은 core::async_iter::from_iter가 인증된 usize::checked_add를 부르는 건 아무 문제가 없습니다.

구현은 두 개의 패스로 나뉩니다.

  • pre-mono 패스(THIR 기반). cargo check에서 빠른 피드백을 주고, ? 같은 내장 문법을 desugar할 만큼 늦게 돕니다. 함수 타입에서 함수 포인터로의 unsizing cast를 잡아내서 "인증 안 된 함수 포인터를 인증된 함수에 넘기는" 우회를 막고, dyn Trait 객체로의 캐스트도 잡습니다(supertrait와 dyn-to-dyn 강제 변환까지 고려해서).
  • post-mono 패스(MIR 기반). 이쪽이 인증이 실제로 의존하는 패스입니다. 제네릭이 인스턴스화되기 전에는 x.clone()이 어느 clone인지 알 수 없으니, 모노모피제이션된 루트에서 시작해 타입을 대입해 가며 콜그래프를 따라 들어갑니다. 대신 cargo check에서는 안 돌고 cargo build에서만 돕니다(공개 제네릭 함수가 있는 라이브러리면 더 늦게 나오기도 합니다).

설계 원칙도 명시돼 있습니다 — 거짓 음성보다 거짓 양성을 선호한다. 유효한 코드를 실수로 거부하는 게 무효한 코드가 인증되는 것보다 낫다는 겁니다. 안전 도구로서는 옳은 방향이고, 실무적으로는 "멀쩡한 코드가 린트에 걸려서 #[allow]을 달며 안전 논증을 쓰게 되는 일"이 생긴다는 뜻이기도 합니다.

이 전환 자체가 하나의 신호입니다. 인증의 강제 메커니즘이 "표준 라이브러리 포크 + 이름이 이상한 가짜 타깃"에서 "컴파일러 패스"로 올라갔습니다. 전자는 해킹이고 후자는 엔지니어링입니다.

ASIL B 천장의 정체 — 벤더가 스스로 적어 둔 것

이제 이 글의 핵심 질문입니다. 컴파일러가 ASIL D 도구로 자격심사를 받았는데 라이브러리는 왜 ASIL B에서 멈추나?

답은 추측할 필요가 없습니다. Ferrous가 ISO 26262 6-Method Tables라는 문서를 MIT/Apache-2.0 라이선스의 공개 저장소에 그대로 올려 뒀습니다. ISO 26262 part 6의 각 방법 표에 대해 "ASIL B에서 얼마나 권고되는지 / ASIL D에서 얼마나 권고되는지 / 우리는 적용했는지"를 한 줄씩 적은 물건입니다.

Table 9, 소프트웨어 유닛 수준의 구조적 커버리지 지표는 이렇습니다.

No.  Method            ASIL B  ASIL D  Justification
1a   Statement coverage   ++      +     Applied, 100% line coverage with
                                        explanations for any coverage gaps
1b   Branch coverage      ++      ++    Not applied, 1a applied instead
1c   MC/DC                 +      ++    Not applied, 1a applied instead

여기 다 있습니다. 적용된 건 구문 커버리지(statement coverage) 하나뿐이고, 분기 커버리지와 MC/DC는 "미적용, 대신 1a 적용"입니다. 그런데 표가 보여 주듯 분기 커버리지는 ASIL B와 D 모두에서 강력 권고(++)이고 MC/DC는 ASIL D에서 강력 권고입니다. 반대로 구문 커버리지는 ASIL D에서는 그냥 권고(+)로 떨어집니다.

즉 ASIL B가 상한인 게 아니라, 현재 쌓아 둔 증거가 ASIL B까지만 지지한다는 겁니다. ASIL D를 주장하려면 Table 9의 1b와 1c를 채워야 하고, 그건 core의 서브셋 전체에 대해 분기 커버리지와 MC/DC를 다시 확보한다는 뜻입니다. 공개 문서 어디에도 그 계획은 없습니다.

같은 문서에서 임베디드 엔지니어가 특히 눈여겨봐야 할 칸이 몇 개 더 있습니다.

  • Table 7, 1m 리소스 사용 평가(Resource usage evaluation). ASIL D 강력 권고. 판정은 "미적용, 라이브러리일 뿐이므로 통합자 책임". 임베디드 문맥으로 번역하면 스택 깊이 분석과 WCET입니다. 인증된 core를 쓴다고 해서 스택을 얼마나 먹는지, 최악 실행 시간이 얼마인지에 대한 답이 딸려 오지 않습니다. 그건 당신 일입니다.
  • Table 6, 1j 재귀 금지. ASIL D 강력 권고. 판정은 "미적용". 정확한 문장은 — 무조건 재귀는 금지되지만(컴파일러가 본문을 대체하는 #[lang_item] 제외), 조건부 재귀는 허용된다. 스택 한계가 빡빡한 MCU에서 이건 그냥 넘길 문장이 아닙니다.
  • Table 7, 1g 데이터 흐름 분석. ASIL D 강력 권고. "미적용, 분석할 내부 데이터 흐름 없음, 전역 상태 없음, 전부 명확한 인터페이스로만".
  • Table 1, 모델링·코딩 가이드라인. 판정이 아예 이렇습니다 — 인증된 core 라이브러리에는 코딩 표준이 없다. 이유는 업스트림 Rust의 lint와 테스트를 그대로 쓰는 게 업스트림과의 괴리를 줄이기 때문이고, 괴리가 커지면 유지보수 부담과 버그 원천이 늘어난다는 논리입니다. MISRA에 익숙한 사람에게는 낯선 대답이지만, 논리 자체는 방어 가능합니다.
  • Table 2/3/4, 소프트웨어 아키텍처 설계. 전부 "해당 없음, 아키텍처가 없으므로". core-certification의 요구사항 문서도 같은 말을 합니다 — core 라이브러리는 크기가 작아서 소프트웨어 아키텍처가 필요 없다.
  • Table 8, 1b/1c 등가 클래스 생성·분석과 경계값 분석. ASIL B/D 모두 강력 권고. 판정은 "부분 적용". 원문이 정직합니다 — coretests의 테스트 케이스는 매우 정성껏 만들어졌지만, Ferrous Systems는 경계값과 극단값이 항상 테스트되는지 전수 검토를 하지 않았다. 100% 라인 커버리지 달성이 모든 코드 경로가 실행됐고 특정 입력에 대한 테스트가 없어 미테스트로 남은 코드가 없음을 보장한다는 게 그 뒤에 붙는 논거입니다.

그리고 요구사항 관리 방식 자체가 논쟁적입니다. core-certification의 Requirements Management 장은 이렇게 시작합니다 — 요구사항은 doc-comment로 구현된다. 함수의 doc-comment가 그 함수의 요구사항이고, 모듈의 doc-comment가 모듈 설계이며, 요구사항 식별자는 "Ferrocene 버전 + 함수의 모듈 경로"입니다. 요구사항을 테스트에 추적하는 방법은 이렇습니다 — 함수의 요구사항은 그 함수 위의 doc-comment이므로 요구사항은 함수로 추적된다, 인증은 코드 커버리지에 의존해 각 함수가 충분히 테스트됨을 보장한다, 따라서 모든 함수가 테스트로 커버되면 모든 요구사항도 커버된다, 그러므로 테스트를 요구사항에 수동으로 추적할 필요가 없다.

이 논증이 마음에 드는지 아닌지는 각자 판단할 문제입니다. 다만 이게 왜 영리한 선택인지는 분명합니다 — Rust core의 doc-comment는 실제로 이례적으로 잘 쓰여 있고 doctest로 강제 실행되므로 코드와 어긋나기 어렵습니다. 없는 요구사항 명세를 새로 지어내는 것보다 이미 있고 이미 검증되는 문서를 요구사항으로 승격시키는 편이 낫다는 판단입니다.

한 가지 강조하고 넘어가겠습니다. 위의 "미적용" 칸들은 제가 파헤쳐서 찾아낸 벤더의 허점이 아닙니다. Ferrous가 자기 손으로 써서 오픈소스 저장소에 올린 것들입니다. 안전 필수 도구 벤더의 norm mapping은 보통 NDA 뒤에 있고, 평가 리포트를 보려면 계약서에 서명해야 합니다. 이 표들이 git clone 한 번으로 읽힌다는 사실 자체가 이 프로젝트에서 가장 좋은 부분일지도 모릅니다. 그리고 이 표들은 천장을 감추는 게 아니라 설명합니다. ASIL B가 어디서 오는지 알고 싶으면 Table 9만 보면 됩니다.

당신의 칩은 아마 목록에 없다

인증 논의를 하기 전에 확인해야 할 게 있습니다. 당신 타깃이 목록에 있느냐입니다.

26.05.0 안전 매뉴얼의 자격심사 범위는 이 조합들로 한정됩니다.

Host                       Target                        Certified  Uncertified          Qualified
aarch64-unknown-linux-gnu  aarch64-rhivos2-linux-gnu     core       alloc
x86_64-unknown-linux-gnu   aarch64-unknown-none          core       alloc
x86_64-unknown-linux-gnu   aarch64-unknown-nto-qnx710    core       alloc, std, test     proc_macro
x86_64-unknown-linux-gnu   thumbv7em-none-eabi           core       alloc
x86_64-unknown-linux-gnu   thumbv7em-none-eabihf         core       alloc
x86_64-unknown-linux-gnu   x86_64-unknown-linux-gnu      core       alloc, std, test     proc_macro
x86_64-unknown-linux-gnu   x86_64-pc-nto-qnx710          core       alloc, std, test     proc_macro

여기서 읽어야 할 것들.

인증된 라이브러리는 core뿐입니다. alloc, std, test는 전부 미인증입니다. 문서의 표현 그대로 — 제공되는 미인증 라이브러리들은 컴파일러 사용 목적으로만 Ferrocene 자격심사 범위 안에서 평가·테스트됐다. 최종 사용자 코드가 이 라이브러리를 쓰는 것은 현재 Ferrocene 자격심사의 범위 밖이다. 사용한다면 인증은 최종 사용자 책임이다. 힙 할당이 필요한 설계라면 alloc부터 당신 숙제입니다.

MCU 쪽 자격심사 타깃은 thumbv7em 둘뿐입니다. Cortex-M4/M7입니다. 그럼 없는 건 뭘까요. Ferrocene의 타깃 지원 등급 문서에서 Supported(지원) 등급에 있는 목록이 이렇습니다 — riscv64gc-unknown-linux-gnu, thumbv6m-none-eabi(Cortex-M0/M0+), thumbv8m.base-none-eabi, thumbv8m.main-none-eabi, thumbv8m.main-none-eabihf(Cortex-M23/M33), armv7r-none-eabihf, armv8r-none-eabihf, wasm32-unknown-unknown, x86_64-pc-windows-msvc(호스트), 그 외. 26.05.0은 여기에 s390xpowerpc64le를 더했습니다.

즉 요즘 새로 나오는 보안 MCU의 절반이 쓰는 Cortex-M33도, RISC-V도, 자격심사 목록에 없습니다. 26.08이 armv7r-none-eabihf를 자격심사로 올릴 예정이니 방향은 맞습니다만, 오늘 기준으로는 "Rust가 인증됐다"가 "내 칩에서 인증된 Rust를 쓸 수 있다"를 뜻하지 않습니다.

Supported와 Qualified의 차이도 문서가 표로 정리해 뒀습니다. Qualified는 병합 전마다 전체 테스트 스위트를 돌리고, 알려진 문제를 추적·제공하며, 2년 지원 창과 LTS가 있습니다. Supported는 테스트가 "최선 노력"이고, 알려진 이슈는 "문서화만", 지원 패치는 "치명적인 것만"입니다. 요청하면 자격심사나 quality managed로 올릴 수 있다고 적혀 있는데, 이건 곧 계약 이야기입니다. Ferrous는 자기들 개발 모델을 "contract-driven"이라고 부르고, 회사에 가장 중요한 기능에 집중하도록 돈을 낼 수 있다고 명시합니다.

호스트는 x86-64 리눅스 하나입니다. macOS(aarch64-apple-darwin)는 quality managed, Windows(x86_64-pc-windows-msvc)는 supported입니다. 둘 다 자격심사가 아닙니다. 인증 대상 빌드를 만드는 기계는 x86-64 리눅스여야 합니다. RHIVOS 행만 예외적으로 aarch64-unknown-linux-gnu 호스트를 씁니다.

그래서 무엇이 여전히 당신 몫인가

안전 매뉴얼의 제약(Constraints) 목록은 각 항목에 식별자가 붙어 있습니다. core 쪽만 추리면 이렇습니다.

  • CORE_CSTR_0020_PANIC_ABORT — 사용자는 rustc에 항상 -C panic=abort를 줘야 한다.
  • CORE_CSTR_0030_SUBSET_ONLY_STABLE — 인증 서브셋의 실험적 함수는 쓰면 안 된다. nightly 기능은 논외입니다.
  • CORE_CSTR_0060_VERIFY_MACROS — 매크로가 생성한 모든 코드가 올바른지 사용자가 검증해야 한다. 매크로를 즐겨 쓰는 Rust 코드베이스에는 만만치 않은 문장입니다.
  • CORE_CSTR_0060_VERIFY_ARCH — 아키텍처 특화 코드는 애플리케이션 문맥에서 추론하고 테스트해야 한다. 원문이 선명합니다 — 우리는 컴파일러가 당신이 요청한 명령어를 올바르게 뱉는다는 것만 보장하지, 그 명령어들이 문맥상 말이 되는지는 보장하지 않는다. 대상은 core::arch 모듈 전체와 core::hint::spin_loop입니다.
  • CORE_CSTR_0070_VERIFY_FLOATS — 부동소수점 코드는 어떤 FPU를 쓰는지, 어떤 연산이 하드웨어로 구현됐는지 같은 외부 조건에 의존한다. 사용자는 자신의 애플리케이션과 하드웨어 문맥에서 부동소수점 계산을 철저히 테스트해야 하며, 컴파일러와 라이브러리 자격심사를 유일한 논거로 삼아서는 안 된다.
  • CORE_CSTR_0040_MATCHING_VERSION — core와 rustc 버전이 일치하는지 검증해야 한다.

여기에 rustc 쪽 안전 매뉴얼의 "Handling Unsafety" 장이 붙습니다. unsafe를 쓸 때의 최소 의무가 이렇습니다 — 불안전성 사용을 최대한 국소화하고 모듈 수준을 절대 넘지 않을 것, 그 모듈이 정확히 하나의 작업만 수행할 것, 불안전 코드와 그 클라이언트 양쪽에 단언·사전조건·사후조건·불변식을 사용할 것, 양쪽에 안전 관련 주석을 달 것. 검증할 때의 최소 의무는 더 셉니다 — 최소 두 명의 시니어 엔지니어가 코드 리뷰를 하거나 서드파티 리뷰를 활용할 것, 불안전 코드가 있는 모듈 전체를 리뷰할 것, 불안전 코드와 그 클라이언트에 단위 테스트와 통합 테스트를 수행할 것. 그리고 완화 전략을 개발할 것.

운영 쪽 의무도 있습니다. 알려진 문제(Known Problems) 데이터베이스는 활성 구독이 있는 고객만 접근할 수 있습니다(problems.ferrocene.dev는 로그인 벽 뒤입니다). 그리고 안전 매뉴얼이 못 박습니다 — 새 문제가 발견되는 것을 인지하고 새 DB 항목에 기술된 절차를 적용하는 것은 고객의 책임이다. 알림을 구독하거나 주기적으로 모니터링해서. 자격심사된 컴파일러를 샀다고 끝이 아니라, 그 컴파일러의 결함 공지를 감시하는 프로세스를 조직 안에 만들어야 한다는 뜻입니다.

마지막으로 환경. Degraded Environment 장은 RUST_TARGET_PATHRUSTC_BOOTSTRAP을 잠재적 오류 원천으로 지목하고, 사용자가 이 변수들이 설정돼 있지 않은지 확인해야 한다고 적습니다. RUSTC_BOOTSTRAP은 안정 컴파일러에서 nightly 기능을 강제로 여는 탈출구니 당연합니다.

언제 쓰지 말아야 하나

정직하게 정리하면 이렇습니다.

쓰지 마세요, 만약

  • 애플리케이션이 ASIL D 또는 SIL 3인데 core에 기대려 한다면. 라이브러리는 ASIL B / SIL 2입니다. 컴파일러가 ASIL D 도구라는 사실이 이 간극을 메워 주지 않습니다. 메우려면 당신이 직접 논증해야 하고, Table 9가 무엇이 비어 있는지 정확히 알려 줍니다.
  • 타깃이 목록에 없다면. RISC-V, Cortex-M0/M23/M33에서는 잘 도는 컴파일러를 받을 뿐 인증 논거를 받지는 못합니다. 계약으로 올릴 수 있다지만 그건 예산과 일정 이야기입니다.
  • 설계가 힙을 요구한다면. alloc은 인증 범위 밖이고, 문서가 명시적으로 최종 사용자 책임이라고 적습니다.
  • 인증 대상 빌드를 리눅스가 아닌 곳에서 만들어야 한다면. 호스트 자격심사는 x86-64 리눅스뿐입니다.
  • 애초에 안전 필수 프로젝트가 아니라면. 이게 가장 흔한 경우일 겁니다. 인증에서 얻는 게 0인데 구독료(벤더 공지 기준 사용자당 월 25유로 또는 연 240유로, 2026년 2월 시점)와 서브셋 규율을 지불하게 됩니다. 업스트림 Rust를 쓰세요. 임베디드 Rust를 처음 만져 보는 거라면 no_std 핸즈온 쪽이 훨씬 도움이 됩니다.

써서 값을 하는 경우

  • ASIL B / SIL 2 / IEC 62304 Class C 범위의 제품이고, 타깃이 Cortex-M4/M7이나 Armv8-A(또는 QNX 7.1)이며, no_std로 설계할 수 있을 때. Sonair와 Kiteshield가 정확히 이 자리에 있습니다.
  • 인증 자체보다 인증 자료가 필요할 때. Ferrocene의 안전 매뉴얼·자격심사 보고서·norm mapping이 오픈소스라는 건 심사원에게 보여 줄 것이 있다는 뜻이고, 이건 생각보다 큽니다.
  • 서브셋 규율을 감당할 조직일 때. 린트가 걸릴 때마다 결정이 하나 발생합니다 — 다시 쓸 것인가, Ferrous에 요청할 것인가, 직접 안전 논증을 쓰고 #[allow]을 달 것인가. 이걸 리뷰 프로세스로 흡수할 수 있어야 합니다.

마치며

한 줄로 줄이면 이렇습니다. 컴파일러는 ASIL D 도구이고, 라이브러리는 ASIL B 소프트웨어입니다. 두 문장은 다르고, 둘 다 사실이며, 하나로 뭉개는 순간 틀린 계획이 나옵니다.

2026년의 진짜 뉴스는 "Rust가 인증됐다"가 아닙니다. 그건 이미 몇 년 된 이야기이고 절반만 맞는 이야기입니다. 진짜 뉴스는 세 가지입니다. 첫째, 인증 서브셋이 실제로 자라고 있습니다 — 한 릴리스에 심볼이 5.2천에서 8.8천으로 늘었고, core::fmt가 들어오면서 "인증 타깃에서는 패닉 메시지가 정적 문자열뿐"이라는 제약이 사라졌습니다. 둘째, 강제 메커니즘이 표준 라이브러리 포크에서 컴파일러 패스로 승격했습니다. 셋째, 벤더가 자기 증거의 구멍을 공개 저장소에 적어 두고 있습니다.

지켜볼 지점도 명확합니다. Table 9에 분기 커버리지나 MC/DC가 "Applied"로 바뀌는 날이 오는지입니다. 그게 ASIL D core로 가는 관문이고, 오늘 공개된 어떤 문서도 그게 온다고 말하지 않습니다. 그때까지 임베디드 안전 프로젝트에서 Rust를 검토한다면, 마케팅 한 줄이 아니라 sphinx-substitutions.toml 다섯 줄과 method table 세 줄을 먼저 읽으십시오. 거기에 답이 다 있습니다.

참고 자료

Ferrocene's Certified core — The Compiler Is ASIL D, So Why Does the Library Stop at ASIL B?

Introduction — The Trap in "ASIL D-Certified Rust Compiler"

There's a sentence that keeps coming up whenever embedded Rust gets discussed: "Ferrocene has received ISO 26262 ASIL D certification." The sentence itself isn't wrong — Ferrous Systems's public documentation says exactly that.

The problem is the conclusion people draw from it. "So now you can write ASIL D software in Rust." No. Two distinct claims have been mashed into one, and what actually moved in the first half of 2026 wasn't the mashed-together claim — it was the thing underneath it: the core library.

This post is that story. What Ferrocene actually certified between December 2025 and May 2026, why the compiler is ASIL D while the library stops at ASIL B, where that ceiling comes from, and what is still left to you. The short version: the most valuable part of this story isn't something the vendor hid — it's something the vendor wrote down itself.

Tool Qualification and Software Certification Are Different Things

Terminology first. This is the skeleton for the whole post.

The Ferrocene compiler (rustc) was qualified as a tool. The first sentence of the Ferrocene Qualification Report reads: this document is the report of the qualification material developed for certification against the automotive ISO 26262:2018 (ASIL D / TCL 3), industrial IEC 61508:2010 (class T3), and medical IEC 62304:2006 + AMD 1:2015 standards.

The key abbreviation here is TCL — Tool Confidence Level. What ISO 26262 part 8 clause 11 addresses is "confidence in the use of the software tool," not the integrity level of the code the tool produces. Being qualified at TCL 3 for ASIL D means "you may use this compiler for ASIL D development." It does not mean "the compiled output is ASIL D."

The core library subset is a completely different thing. It isn't a tool — it's a software component — and it received certification as software. The same qualification report continues: parts of this document may be referenced from the Core Library Certification developed for certification against the automotive ISO 26262:2018 (ASIL B) and industrial IEC 61508:2010 (SIL 2) software standards.

These two numbers aren't marketing copy — they're baked in machine-readable form into a documentation build config. Open ferrocene/doc/sphinx-substitutions.toml in the Ferrocene repo and you get this:

iso_26262_ferrocene_asil = "ASIL D"
iso_26262_core_asil = "ASIL B"
iso_26262_ferrocene_tcl = "TCL 3"
iso_26262_ferrocene_tql = "class T3"

iec_61508_core_sil = "SIL 2"

Compiler: ASIL D / TCL 3. Core: ASIL B. This file is byte-identical between the 26.02.0 and 26.05.0 branches — the ASIL B ceiling holds in the latest release too.

And the "Qualification scope" chapter of the Safety Manual pins down user responsibility in plain terms: per ISO 26262:2018 part 8 clause 11.4.2, the user must verify the validity of the predetermined TCL before using this software tool for safety-related development. And per clause 11.4.3, the user must ensure that the tool's usage, environment, and functional constraints match the evaluation criteria or qualification.

Read closely, this isn't "we've done it all, just use it" — it's "you verify the valid scope of our qualification."

What Actually Happened, December 2025 to May 2026

In chronological order:

December 3, 2025 — the first core subset, IEC 61508 SIL 2. Ferrous Systems announced it in a press release. TÜV SÜD certified the first subset of the Rust core library to IEC 61508 (SIL 2), and that subset ships in Ferrocene 25.11.0. The certification applies to use on the Ferrocene toolchain and qualified targets (including Armv7E-M and Armv8-A). The work started in 2023, with Cryspen and Thoughtworks contributing tools and time. In the words of Florian Gilcher, Ferrous's managing director — "It's not practical to run Rust without core in embedded or safety-critical contexts, and core can't be certified unless it's rigorously verified with a toolchain like Ferrocene."

The same release names two real-world adopters. Sonair uses it in ADAR, a 3D ultrasonic sensor for autonomous robots (running on quad-core Armv8-A alongside an Armv7E-M subsystem), and Kiteshield uses it in collision-avoidance systems for manned and autonomous underground-mining equipment, where some components ultimately require IEC 61508 SIL 3.

February 15, 2026 — ASIL B added, subset expanded. This is the 26.02.0 release. ISO 26262 (ASIL B) was added to the certified core subset, and the SIL 2 subset itself grew substantially. By the vendor's own published figures, the number of certified functions went from 2,903 to 5,169, modules like core::slice, core::iter, core::ffi, and core::result expanded, and a minimal certified panic hook was added. The repo's ferrocene/version file confirms this release's rustc is 1.92. eeNews Europe covered it independently too — announced at embedded world 2026, and the point was that certification had moved down past the compiler toolchain into the library layer.

May 2026 — core::fmt certified, and the enforcement mechanism replaced. This is where it gets interesting. There's no announcement blog post for 26.05.0. ferrous-systems.com/blog/ferrocene-26-05-0/ is a 404, and the blog index's latest Ferrocene release notice is still 26.02.0. But the release shipped — the repo's release/1.95 branch has ferrocene/version holding 26.05.0, and the :upcoming-release: marker has been removed from the release notes (while 26.08 on release/1.97 still carries that marker). The contents:

  • The core::fmt module was certified to ISO 26262 (ASIL B) and IEC 61508 (SIL 2) — the code that formats Rust data structures into human-readable output.
  • As a result, the "certified panic runtime" targets (aarch64-ferrocene-none, thumbv7em-ferrocene-none-eabi, and others) were retired. They existed to certify panics without certifying the formatting code — no longer necessary.
  • The ferrocene::unvalidated lint was introduced, and the "subset targets" were retired. More on this below.
  • A new qualified target, aarch64-rhivos2-linux-gnu, was added (only when compiling on an aarch64-unknown-linux-gnu host), and the proc_macro crate type was permitted.
  • thumbv7em-m4-none-eabihf and aarch64-a53-none were removed. These were newly added in 26.02.0, but the same effect is now achieved by passing -C target-cpu=cortex-m4 / -C target-cpu=cortex-a53 on the base target.

Traces of the 26.05.0 core::fmt certification show up in the user manual too. The 26.02.0 core/using.rst had a warning: core library behavior differs when using a certified target — in particular, the panic! macro supports only static strings rather than arbitrary format_args!, so panic messages may be less informative. In the same file in 26.05.0, that entire paragraph is gone.

Independent verification. The repository ships an authoritative list of certified symbols as a CSV (ferrocene/doc/symbol-report.csv; the Safety Report chapter of the core-certification docs includes this file directly). Pulling and counting from the two release branches gives:

release/1.92 (26.02.0):  5,235 unique symbols   core::fmt symbols:   0
release/1.95 (26.05.0):  8,790 unique symbols   core::fmt symbols: 535
                         (added 3,597 / removed 42)

This confirms the core::fmt certification landed, independent of the release notes. To be honest, though, the 5,235 in the 26.02.0 CSV doesn't line up exactly with the vendor's announced "5,169 certified functions." As the file name suggests, this is a symbol report while the announcement counted functions, so the counting basis is likely different. Read 5,169 as the vendor's own tally, then — what's solid is the order of magnitude and direction: the subset grew roughly 1.7x in one release.

The 42 removals are interesting too. Most are old certified-panic-runtime parts like core::panicking::PanicArguments::as_str and derive-internal markers (assert_receiver_is_total_eq). The subset doesn't only grow — it shrinks too.

August 2026 (upcoming). 26.08 on release/1.97 still carries the upcoming marker and previews three new qualified targets — aarch64-unknown-qnx, armv7r-none-eabihf, and x86_64-pc-qnx. flip-link is being promoted to quality managed.

Why a Subset, Not All of core

Callgraph analysis (April 1, 2026), written by Ferrous compiler engineer Jynn, spells out the reason. The certification target was IEC 61508 (SIL 2), and one of that standard's requirements that scales with codebase size is Annex A.9, "Software verification." Ferrous uses methods 3 and 4 (static and dynamic analysis). The documented approach is to run tests on every target platform where certified core exists, and collect code coverage that verifies every function has been tested.

So more code means more tests needed. In the post's own words: to avoid spending years of work before shipping a product, they decided to verify only a subset of core. Mark functions as validated, run tests against each of them to collect coverage, and tell customers to use only those validated functions.

The formal certification path is documented too. Per the Certification scope chapter of the core-certification docs, the IEC 61508 side follows Route 3S in section 7.4.2.12 — "Assessment of non-compliant development" — and the ISO 26262 side is SEooC (Safety Element out of Context) software development, tailored across parts 2/6/8.

If Route 3S doesn't mean much on its own, think of it this way: Rust's core was never developed with IEC 61508 in mind. Route 3S is the path for taking something that wasn't developed to a standard from the outset and assessing after the fact whether it's usable. And there's one interesting item in the ISO 26262 list of applicable clauses: "8-12, Qualification of software components" is marked not applicable, with the justification "qualification not applied, treated as new development instead." In other words, they built the evidence as if it were newly developed, rather than going through the existing software-qualification path.

How the Subset Is Enforced — From cfg Hacks to a Callgraph Lint

This is the most engineering-flavored part of the story.

Here's the problem. It's easy to say "only use certified functions," but there's no way for a user to know which parts of core they're actually calling. The Callgraph post nails it: core isn't an ordinary library — it carries deep integration with the compiler and the language itself. Something as innocuous-looking as do_io()? actually emits a call to core::ops::try_trait::Try::branch. Knowing which function calls which requires real compiler integration.

First attempt (25.11, 26.02): cfg forking plus fake subset targets. The approach was to fork the standard library and slap cfg all over the panic machinery. But that affects every user, not just the ones who care about certification, so to avoid breaking changes they created entirely new targets like aarch64-unknown-ferrocene.subset. Ferrous's own assessment is blunt: build scripts couldn't parse the target name, libtest used parts of core that had been cfg'd away so it couldn't compile for that target, and in practice people had to be told "run cargo check --target aarch64-unknown-none.subset, but don't use it for a full build" — a very bad user experience.

The Safety Manual flags the same thing in a warning box: subset targets may only be used to verify subset compliance, and must not be used as a certified target at runtime.

Second attempt (26.05): a lint on top of a custom rustc driver. This is the ferrocene::unvalidated lint introduced in 26.05.0. Per the Safety Manual, the procedure for proving compliance is now this short:

// 1. Turn on the lint at each crate root
#![warn(ferrocene::unvalidated)]

// 2. Compile with -D warnings. If it succeeds, the subset held.
//
// If it fails, pick one of four options:
//   a) if the function is yours, attach #[ferrocene::prevalidated]
//   b) if it's a core function, contact Ferrous to discuss adding it to the subset
//   c) remove the call and rewrite with the same meaning
//   d) keep it, but prove safety yourself and add #[allow(ferrocene::unvalidated)]

The invariant the lint enforces fits in one sentence: the set of validated functions in core must be closed under the function-call operation. If a call appears inside a validated function, the callee must also be validated. The reverse direction doesn't matter — there's nothing wrong with an unvalidated core::async_iter::from_iter calling a validated usize::checked_add.

The implementation splits into two passes.

  • A pre-mono pass (THIR-based). It gives fast feedback in cargo check, running late enough to desugar built-in syntax like ?. It catches unsizing casts from function types to function pointers — blocking the workaround of "pass an unvalidated function pointer into a validated function" — and also catches casts to dyn Trait objects (accounting for supertraits and dyn-to-dyn coercions).
  • A post-mono pass (MIR-based). This is the pass certification actually depends on. Before generics are instantiated, you can't know which clone a call to x.clone() resolves to, so this pass starts from monomorphized roots and walks the call graph, substituting types as it goes. It doesn't run in cargo check, only in cargo build (and it can surface even later for libraries with public generic functions).

The design principle is spelled out explicitly: prefer false positives over false negatives. Rejecting valid code by mistake is better than certifying invalid code. That's the right direction for a safety tool, and in practice it also means "code that's actually fine gets flagged by the lint, and you end up writing a safety argument to attach #[allow]."

The transition itself is a signal. Enforcement moved from "fork the standard library plus a weirdly named fake target" to "a compiler pass." The former is a hack; the latter is engineering.

What the ASIL B Ceiling Actually Is — What the Vendor Wrote Down Itself

Now the central question of this post. The compiler was qualified as an ASIL D tool — so why does the library stop at ASIL B?

You don't have to guess at the answer. Ferrous put a document called ISO 26262 6-Method Tables directly into its MIT/Apache-2.0-licensed public repository. For every method table in ISO 26262 part 6, it records, line by line, "how strongly recommended at ASIL B / how strongly recommended at ASIL D / did we apply it."

Table 9, structural coverage metrics at the software-unit level, reads:

No.  Method            ASIL B  ASIL D  Justification
1a   Statement coverage   ++      +     Applied, 100% line coverage with
                                        explanations for any coverage gaps
1b   Branch coverage      ++      ++    Not applied, 1a applied instead
1c   MC/DC                 +      ++    Not applied, 1a applied instead

It's all right there. The only thing applied is statement coverage; branch coverage and MC/DC are "not applied, 1a applied instead." But as the table shows, branch coverage is strongly recommended (++) at both ASIL B and D, and MC/DC is strongly recommended at ASIL D. Statement coverage, conversely, drops to merely recommended (+) at ASIL D.

In other words, ASIL B isn't a hard ceiling — it's that the evidence gathered so far only supports ASIL B. Claiming ASIL D would require filling in 1b and 1c in Table 9, which means re-establishing branch coverage and MC/DC across the entire core subset. No public document lays out a plan to do that.

The same document has a few more cells that embedded engineers in particular should note.

  • Table 7, 1m, Resource usage evaluation. Strongly recommended at ASIL D. The verdict: "not applied — it's just a library, so it's the integrator's responsibility." Translated into embedded terms, this is stack-depth analysis and WCET. Using certified core doesn't come with answers about how much stack it eats or what the worst-case execution time is. That's your job.
  • Table 6, 1j, No recursion. Strongly recommended at ASIL D. The verdict: "not applied." The exact wording: unconditional recursion is prohibited (except for #[lang_item]s where the compiler substitutes the body), but conditional recursion is allowed. On an MCU with a tight stack budget, that's not a line to skim past.
  • Table 7, 1g, Data flow analysis. Strongly recommended at ASIL D. "Not applied — no internal data flow to analyze, no global state, everything via well-defined interfaces only."
  • Table 1, Modeling and coding guidelines. The verdict here is blunt: the certified core library has no coding standard. The reasoning is that using upstream Rust's own lints and tests as-is keeps drift from upstream low, and more drift means more maintenance burden and more bug surface. That's an unfamiliar answer if you're used to MISRA, but the logic itself is defensible.
  • Tables 2/3/4, software architecture design. All "not applicable, there is no architecture." The core-certification requirements document says the same thing: the core library is small enough that it doesn't need a software architecture.
  • Table 8, 1b/1c, equivalence class generation/analysis and boundary value analysis. Strongly recommended at both ASIL B and D. Verdict: "partially applied." The text is candid — coretests' test cases were built with great care, but Ferrous Systems did not exhaustively review whether boundary and extreme values are always tested. The argument that follows is that achieving 100% line coverage guarantees every code path executed and that no code was left untested for lack of a test on a particular input.

And the requirements-management approach itself is contentious. The Requirements Management chapter of core-certification opens with: requirements are implemented as doc-comments. A function's doc-comment is that function's requirement, a module's doc-comment is the module design, and requirement identifiers are "Ferrocene version + the function's module path." How requirements trace to tests: since a function's requirement is the doc-comment above that function, requirements trace to functions; certification relies on code coverage to guarantee each function is sufficiently tested; therefore, if every function is covered by tests, every requirement is covered too; therefore there's no need to manually trace tests to requirements.

Whether you find this argument convincing is your own call. But it's clear why it's a clever choice — Rust core's doc-comments are unusually well-written by comparison and are enforced as doctests, so they're hard to let drift from the code. It's better to promote documentation that already exists and is already verified into requirements, rather than inventing a requirements spec that doesn't exist yet.

One thing worth stressing. The "not applied" cells above aren't a vendor weakness I dug up. Ferrous wrote them themselves and put them in an open-source repo. A safety-critical tool vendor's norm mapping is usually behind an NDA, and you typically sign a contract to see an assessment report. The fact that these tables are one git clone away might be the best part of this whole project. And these tables don't hide the ceiling — they explain it. If you want to know where ASIL B comes from, Table 9 is all you need.

Your Chip Is Probably Not on the List

Before getting into certification at all, there's something to check: is your target even on the list?

The 26.05.0 Safety Manual's qualification scope is limited to these combinations:

Host                       Target                        Certified  Uncertified          Qualified
aarch64-unknown-linux-gnu  aarch64-rhivos2-linux-gnu     core       alloc
x86_64-unknown-linux-gnu   aarch64-unknown-none          core       alloc
x86_64-unknown-linux-gnu   aarch64-unknown-nto-qnx710    core       alloc, std, test     proc_macro
x86_64-unknown-linux-gnu   thumbv7em-none-eabi           core       alloc
x86_64-unknown-linux-gnu   thumbv7em-none-eabihf         core       alloc
x86_64-unknown-linux-gnu   x86_64-unknown-linux-gnu      core       alloc, std, test     proc_macro
x86_64-unknown-linux-gnu   x86_64-pc-nto-qnx710          core       alloc, std, test     proc_macro

Here's what to read off this.

Only core is certified. alloc, std, and test are all uncertified. In the document's own words: the uncertified libraries provided are evaluated and tested within Ferrocene's qualification scope solely for the purpose of compiler use. End-user code using these libraries is currently outside the scope of Ferrocene's qualification; if you use them, certification is the end user's responsibility. If your design needs heap allocation, alloc is your homework starting today.

On the MCU side, there are only two qualified targets: the thumbv7em pair. That's Cortex-M4/M7. So what's missing? Ferrocene's target support tier document lists these under the Supported tier — riscv64gc-unknown-linux-gnu, thumbv6m-none-eabi (Cortex-M0/M0+), thumbv8m.base-none-eabi, thumbv8m.main-none-eabi, thumbv8m.main-none-eabihf (Cortex-M23/M33), armv7r-none-eabihf, armv8r-none-eabihf, wasm32-unknown-unknown, x86_64-pc-windows-msvc (host), and more. 26.05.0 added s390x and powerpc64le to that list.

Which means neither Cortex-M33 — used in half of today's newer secure MCUs — nor RISC-V is on the qualified list. 26.08 is set to promote armv7r-none-eabihf to qualified, so the direction is right, but as of today, "Rust is certified" does not mean "certified Rust runs on my chip."

The document also tabulates the difference between Supported and Qualified. Qualified runs the full test suite before every merge, tracks and provides known issues, and comes with a two-year support window and LTS. Supported means testing is "best effort," known issues are "documented only," and support patches are "critical only." It notes that a target can be promoted to qualified or quality managed on request — which is really a way of saying it's a contract conversation. Ferrous calls its own development model "contract-driven," and states outright that you can pay to focus the company's attention on the features that matter most to you.

The host is x86-64 Linux, and only that. macOS (aarch64-apple-darwin) is quality managed, and Windows (x86_64-pc-windows-msvc) is supported — neither is qualified. The machine producing a certification-target build has to be x86-64 Linux. Only the RHIVOS row is the exception, using an aarch64-unknown-linux-gnu host.

So What's Still Left to You

The Safety Manual's Constraints list gives each item an identifier. Filtering to the core-related ones:

  • CORE_CSTR_0020_PANIC_ABORT — the user must always pass -C panic=abort to rustc.
  • CORE_CSTR_0030_SUBSET_ONLY_STABLE — experimental functions in the certified subset must not be used. nightly features are out of scope entirely.
  • CORE_CSTR_0060_VERIFY_MACROS — the user must verify that all macro-generated code is correct. That's a demanding line for a Rust codebase that leans on macros.
  • CORE_CSTR_0060_VERIFY_ARCH — architecture-specific code must be reasoned about and tested in the application context. The wording is blunt: we guarantee the compiler emits the instructions you asked for correctly, not that those instructions make sense in context. This applies to the entire core::arch module and core::hint::spin_loop.
  • CORE_CSTR_0070_VERIFY_FLOATS — floating-point code depends on external conditions like which FPU is in use and which operations are implemented in hardware. The user must thoroughly test floating-point computations in their own application and hardware context, and must not rely on compiler and library qualification alone as the argument for correctness.
  • CORE_CSTR_0040_MATCHING_VERSION — the user must verify that the core and rustc versions match.

To that, add the "Handling Unsafety" chapter of the rustc-side Safety Manual. Minimum obligations when using unsafe: localize the use of unsafety as much as possible and never let it cross module boundaries; the module must do exactly one job; use assertions, preconditions, postconditions, and invariants on both the unsafe code and its clients; and comment on safety on both sides. The minimum obligations for verification are heavier still: at least two senior engineers must code-review it, or a third-party review must be used; the entire module containing unsafe code must be reviewed; unit and integration tests must be run on both the unsafe code and its clients. And a mitigation strategy must be developed.

There are operational obligations too. The Known Problems database is accessible only to customers with an active subscription (problems.ferrocene.dev sits behind a login wall). And the Safety Manual is direct about it: it is the customer's responsibility to become aware of newly discovered problems and apply the procedures described in new DB entries — whether by subscribing to notifications or monitoring periodically. Buying a qualified compiler isn't the end of it; you have to build a process inside your organization for watching that compiler's defect notices.

Finally, environment. The Degraded Environment chapter flags RUST_TARGET_PATH and RUSTC_BOOTSTRAP as potential sources of error, and states the user must verify these variables are not set. RUSTC_BOOTSTRAP is, unsurprisingly, the escape hatch that force-opens nightly features on a stable compiler.

When Not to Use This

Laid out honestly:

Don't, if

  • Your application is ASIL D or SIL 3 and you're relying on core to get you there. The library is ASIL B / SIL 2. The compiler being an ASIL D tool doesn't close that gap. Closing it is on you, and Table 9 tells you exactly what's missing.
  • Your target isn't on the list. On RISC-V, Cortex-M0/M23/M33, you get a compiler that runs fine — not a certification argument. It can be promoted by contract, but that's a budget-and-schedule conversation.
  • Your design requires the heap. alloc is outside the certification scope, and the docs say explicitly that it's the end user's responsibility.
  • You need to build certification-target artifacts somewhere other than Linux. Host qualification is x86-64 Linux only.
  • This isn't a safety-critical project to begin with. This is probably the most common case. You gain nothing from certification and still pay the subscription (per the vendor's own notice, €25 per user per month or €240 per year, as of February 2026) and the subset discipline. Use upstream Rust. If you're new to embedded Rust altogether, the no_std hands-on guide will help you a lot more.

When it earns its keep

  • Your product falls within ASIL B / SIL 2 / IEC 62304 Class C, your target is Cortex-M4/M7 or Armv8-A (or QNX 7.1), and you can design around no_std. Sonair and Kiteshield sit exactly here.
  • What you need is the certification material more than the certification itself. Ferrocene's Safety Manual, Qualification Report, and norm mapping being open source means you have something to hand an assessor — and that's worth more than it sounds.
  • Your organization can absorb the subset discipline. Every time the lint fires, a decision has to be made — rewrite it, ask Ferrous, or write your own safety argument and #[allow] it. You need a review process that can absorb that.

Closing

The one-line version: the compiler is an ASIL D tool, and the library is ASIL B software. These are two different statements, both true, and the moment you mash them into one you get a plan that's wrong.

The real 2026 news isn't "Rust got certified" — that's already years old and only half right. The real news is three things. First, the certified subset is genuinely growing — symbols went from 5.2 thousand to 8.8 thousand in one release, and with core::fmt landing, the constraint that "panic messages on certified targets are static strings only" has gone away. Second, the enforcement mechanism was promoted from a standard-library fork to a compiler pass. Third, the vendor is documenting the holes in its own evidence in a public repository.

There's a clear thing to watch for going forward: whether the day comes when Table 9 marks branch coverage or MC/DC as "Applied." That's the gate to an ASIL D core, and no public document today says it's coming. Until then, if you're evaluating Rust for an embedded safety-critical project, read the five lines of sphinx-substitutions.toml and the three lines of the method table before you read the one-line marketing pitch. The answer is all there.

References