본문으로 건너뛰기

© 2026 Molayo

GN헤드라인2026. 05. 17. 03:32

Bun Rust 재작성: "코드베이스가 기본적인 miri 검사에 실패하고 safe Rust에서 UB를 허용"

요약

이 글은 Bun 런타임을 Rust로 재작성하는 과정에서 발생한 기술적인 문제와 아키텍처적 논쟁을 다루고 있습니다. 특히 `PathString::init` 함수가 안전(safe) 함수임에도 불구하고, 내부적으로 라이프타임을 제거하여 dangling reference를 생성할 수 있는 취약점이 지적되었습니다. 또한, Bun의 개발 방향성 및 Anthropic의 관리 주체에 대한 비판적인 시각과, Zig에서 Rust로의 코드베이스 포팅 방식 전반에 대한 기술적 회의론이 함께 제시되고 있습니다.

핵심 포인트

  • Bun의 `PathString::init` 함수는 안전한(safe) API임에도 불구하고 라이프타임을 제거하여 dangling reference를 생성할 위험성이 있음 (Miri 검사 실패).
  • Rust로의 재작성 과정에서 발생하는 메모리 안전성 문제와 unsafe 사용 전반에 대한 심도 있는 검토가 필요함.
  • Bun의 개발 방향성과 Anthropic의 관리 주체 변화에 대해 신뢰하기 어렵다는 비판적 시각이 제기됨.
  • Zig를 Rust로 포팅하는 방식(예: `zig translate-c` 연결)은 기술적으로 복잡하고, 메모리 안전성 측면에서 근본적인 문제점을 가질 수 있음.
  • Bun은 Deno와 유사하게 다양한 기능을 제공하며, 현재 여러 환경에 배포되는 중요한 TypeScript 런타임으로 자리매김하고 있음.

이 이슈는 현재 Open 상태이며, 대화는 off topic으로 잠기고 collaborator로 제한됐고, 관련 수정으로 #30728과 #30876이 연결돼 있음

제보자는 PathString::init으로 만든 값이 원본 Box가 drop된 뒤에도 slice()를 호출할 수 있어, Miri가 dangling reference 기반 Undefined Behavior를 보고한다고 제시함

재현 코드는 Box::new(*b"Hello World")로 만든 버퍼를 PathString::init(&*test)에 넘긴 뒤 drop(test) 후 init.slice()를 호출하는 형태였고, Miri는 core::slice::from_raw_parts 지점에서 오류를 냄

robobun은 문제가 재현됐다고 확인하며, PathString::init이 safe 함수인데도 slice lifetime을 지워서 dangling &[u8]를 만들 수 있다고 정리함

연결된 #30728은 PathString::init과 dir_iterator::next()의 병렬 구멍을 unsafe fn으로 바꾸고, 호출부 약 70곳에 backing allocation을 명시한 SAFETY 주석을 추가하는 방향임

같은 수정에는 세 시그니처에서 unsafe 키워드가 필요함을 강제하는 compile_fail doctest와 resolver의 readdir-error fd leak 수정도 포함됐다고 설명됨

AwesomeQubic은 추가로 PathString::init이 provenance를 지우며 MIRIFLAGS=-Zmiri-strict-provenance에서도 실패한다고 덧붙임

JavaDerg는 init이 &[u8]의 암묵적 lifetime을 받아 unsafe 작업으로 이를 지운 뒤 'static처럼 보이는 Self를 반환해 use-after-free와 invalid aliasing을 허용한다고 설명함

JavaDerg는 Rust의 안전 모델 위에서 UB가 예상 밖의 위치에서 문제를 일으킬 수 있다며, unsafe 사용 전반에 대한 검토가 필요하고 다른 언어의 메모리 관리 방식을 Rust로 1:1 번역하는 것은 적합하지 않다고 경고함

처음 Bun에 관심을 가진 건 Zig로 작성됐기 때문이고, Zig에 끌린 건 Andrew Kelley의 의사결정과 취향을 신뢰했기 때문임
이후 Bun에 더 흥미를 느낀 이유들도 결국 내가 존중할 만한 선택들이었기 때문인데, Anthropic 인수 후에도 조심스럽게 낙관하려 했음
하지만 이번 행보는 신뢰하기 어려운 의사결정으로 보이며, Rust 자체가 문제가 아니라 Anthropic이 Bun을 이런 식으로 관리한다면 도구함의 신뢰할 만한 구성요소로 더는 베팅하기 어렵다는 느낌임
코드만이 아니라 그 뒤의 사고방식까지 신뢰해야 하는데, 지금은 Anthropic 내부 전용 도구처럼 보임

Bun은 정말 흥미로운 프로젝트지만 이슈에 올라오는 세그멘테이션 폴트 수가 진지한 운영 환경에 쓰기엔 너무 걱정스러웠음
이번 방향이 그걸 고치는 한 방법일 수는 있으니 지켜볼 일임

이해는 되지만, 내 출발점은 꽤 다름
오래된 Deno 팬으로서 Bun은 덜 야심 찬 Deno처럼 보였고, Zig를 배우고 싶지 않아 취미로라도 Bun 자체를 건드릴 가능성이 낮았음
그런데 지난 몇 년간 런타임에 덜 묶인 방식으로 꽤 큰 TypeScript 코드베이스를 유지하려다 보니 Bun에 점점 마음이 열렸고, 특정 TypeScript 런타임을 요구사항으로 만들고 싶지 않았지만 Bun은 Deno처럼 Postgres, SQLite, S3, 웹소켓, 로컬 비밀 저장소, 번들링, 컴파일, 빠른 속도 같은 이유를 계속 제공했음
지금은 여러 API 서버와 프런트엔드 앱 서버를 bun build --compile --bytecode 단일 실행 파일로 만들어 거의 어디서나 실행·배포하고 있음
다만 이런 방식이 흔하다고 보진 않고, 이번 LLM 기반 포팅이 실패하면 Bun 관련 결정들을 모두 후회하기 딱 좋은 위치에 있음
그래도 실패하지 않는다면 흥미로움. LLM으로 무엇이 가능한지 보여주는 사례가 되고, 앞으로 Bun이 Rust로 개발되는 건 내 기준에선 장점임
반대로 실패해도 정보로서 중요함. Bun은 주요 TS/JS 런타임 중 하나이고, Anthropic에는 엄청난 자원과 최신 모델 접근권, 사실상 무제한 예산이 있으니 이들이 못 한다면 아직은 정말 불가능하다는 뜻에 가까움

Bun이 Deno보다 끌렸던 이유가 궁금함

Zig를 안전하지 않은 Rust로 옮길 거였다면 왜 번역 도구를 만들지 않았는지 이해가 안 됨
언어 구조를 일대일로 매핑하고 코드베이스의 패턴을 하드코딩하면 결정적인 변환을 얻을 수 있었을 텐데, 친구 말처럼 “zig translate-c를 c2rust에 연결”하는 식도 가능했을 것임
지금 결과물은 입력보다도 덜 신뢰됨. 입력은 메모리 안전하진 않았지만 사람이 직접 쓴 코드였고, 출력은 메모리 안전하지 않은 데다 바이브 코딩됐고 사람이 제대로 본 적도 없어 보임
이런 용도에 에이전트형 AI를 남용하는 의미가 뭔지 모르겠음

c2rust 결과물을 본 적이 있다면 그렇게 말하기 어려움
C의 안전하지 않은 포인터 의미론을 Rust의 안전하지 않은 함수 라이브러리로 흉내 내는 식이라 결과가 끔찍함
몇 년 전 OpenJPEG 버그를 보던 중 누군가 c2rust로 변환해 봤는데, 변환된 안전하지 않은 Rust도 C 코드와 같은 지점에서 세그멘테이션 폴트를 냈음
호환은 되지만 안전하진 않음
핵심은 문자열 조작을 C나 안전하지 않은 Rust로 하지 말라는 것임. 작업에 전혀 맞지 않는 도구임

그들은 만들었음. 아주 동적인 번역 도구를

“zig translate-c를 c2rust에 연결하면 된다”는 건 생각처럼 작동하지 않음
이런 도구들은 오류가 많고 코드를 매우 장황하고 추론하기 어렵게 만듦
작은 앱에는 통할 수 있지만 전체 재작성에는 맞지 않음

나도 다른 스레드에서 거의 같은 얘기를 했지만, 소프트웨어 작성 방식에 대해서는 조금 다른 관점임
Zig를 Rust로 번역하는 것보다, 정적 Python으로 JPEG 파서를 작성한 뒤 각 언어에 맞는 관용적 구조로 Zig와 Rust로 낮추는 편이 더 낫다고 봄
이를 위해 이런 목적에 맞는 Python 방언 파서를 만들었고, 대부분의 Python 코드와 호환성을 유지하면서 번역을 쉽게 해 주는 Rust/Zig 기능 일부를 받아들이려 함
JPEG 파서도 예시 자산에 포함돼 있음 https://github.com/py2many/static-python-skill https://github.com/py2many/spy-ast

코드베이스를 다른 언어로 포팅하는 올바른 방식은 구문 트리를 파싱하고 결정적이며 검증된 변환을 적용하는 것임

이 이슈는 오해를 부름
문제는 miri가 잡을 수 있는 정의되지 않은 동작의 존재 자체가 아니라, 안전한 코드에서 정의되지 않은 동작을 일으킬 수 있는 API를 노출한 것임. miri도 그걸 증명하는 테스트를 작성해야만 잡음
안전하지 않은 언어에서 초기 포팅을 하는 동안 이런 일이 생기는 건 완전히 비합리적이진 않음
Bun 팀도 이후 안전하지 않은 코드를 감싼 함수들이 올바른지 점검해 나가는 듯함
포팅 단계에서 일부 안전하지 않은 함수를 임시로 안전하다고 잘못 표시하는 건 그 자체로 큰 문제는 아니지만, 그런 상태로 메인 저장소에 병합한 건 좀 이상함
실제 문제는 이 상태의 코드를 릴리스했을 때임
아쉬운 점은 테스트를 즉시 miri로 돌리도록 설정하지 않았다는 것임. LLM은 좋은 테스트에 잘 반응하기 때문임
이 GitHub 이슈 때문이 아니라, 다른 테스트 [1]가 miri가 잡을 정의되지 않은 동작을 실제로 호출하기 때문에 그렇게 판단함. 다만 그 테스트 대상 코드는 어디에도 쓰이지 않는 듯해 현실적 영향은 크지 않아 보임
포팅 초반이니 나중에 고칠 수도 있고, 실제로 필요 없는 안전하지 않은 코드를 없앨 수도 있음
[1] https://github.com/oven-sh/bun/blob/4d443e54022ceeadc79adf54... - 첫 번째 가변 참조에서 파생된 포인터들이 같은 객체에 새 가변 참조를 만들면서 무효화됨. C식으로는 “가변 참조”를 “사소한 변경이 수행되는 restrict 참조”로 생각하면 됨
올바르게 하려면 모든 포인터를 같은 가변 참조에서 파생하면 되는데, 그렇게 하지 않았을 뿐임
GitHub에 몰려가 도배하면 공개적으로 일할 가능성만 줄어듦. 그러지 않았으면 함
그리고 게시 가능한 상태가 될 때까지 판단을 유보하는 게 좋겠음. 중간 작업 상태를 평가하는 건 공정하지도, 별로 흥미롭지도 않음

프로젝트가 처음 1.0에 도달하면 많은 사람이 main 브랜치가 항상 동작한다고 기대함
CI/CD가 결국 모든 커밋이 동작해야 한다는 전제에 가깝기 때문임
전체 재작성처럼 동작하지 않는 진행 중 코드는 브랜치에서 해야 함
그래야 보안 수정 같은 일이 필요할 때도 동작하는 main을 유지할 수 있음

이런 결과는 요청한 방식이 거의 직역 포팅이었으니 놀랍지 않음
먼저 더 강한 타입 시스템을 가진 언어로 Bun을 옮긴 뒤, 그 타입 시스템을 발판 삼아 후속 개선을 하는 편이 낫다고 볼 수도 있지 않나 싶음
첫 단계부터 완벽을 요구하는 것보다는 나아 보임

실제로 그들이 하고 있는 일이 그거임
들어오는 이슈를 처리해 나가고 있음

프롬프트에 “정의되지 않은 동작이 없게 해라”만 추가하면 괜찮아질 것임

이제 miri 같은 도구로 재작성을 압박하면서 Claude Code가 자동으로 개선하게 만들 수 있어 보임

대부분 직역된, 일부 안전하지 않은 Rust 코드에서 정의되지 않은 동작이 나오는 건 놀랍지 않음
다만 Rust 코드의 API가 unsafe로 표시되지 않았는데도 정의되지 않은 동작을 일으킬 수 있다는 점은 실망스러움
이런 번역을 한다면 보수적으로 접근해 처음에는 전부 또는 대부분을 unsafe로 표시했을 것임
그다음 개별 조각의 안전성을 단계적으로 검증하면 됨

솔직히 일주일 만에 완전히 동작하게 만들었다는 말에 좀 놀랐음
내 사이드 프로젝트도 비슷한 야심을 가진 https://tsz.dev인데, 성공했다고 주장할 수는 없음
계속 테스트를 추가해 동작을 확인하고 있고, TypeScript 자체 테스트를 모두 통과한 뒤에도 예상대로 버그를 찾고 있음 tsc 동작과 일치시키는 기준은 정말 매우 높음 https://github.com/type-challenges/type-challenges
LLM으로 많은 코드를 작성하는 데 반대하진 않지만, 이 속도로 코드를 뽑아낼 수 있게 된 지금은 검증이 100배는 더 탄탄해야 함

“실험”에서 일주일 만에 리뷰가 거의 안 됐을 가능성이 큰 백만 줄 규모 코드를 병합한 게 충격적임
에이전트를 쓰는 것 자체엔 반대하지 않지만, 이런 일을 서두르고 커뮤니티를 갑자기 놀라게 만드는 건 매우 아마추어처럼 보임
의욕 넘치는 신입 엔지니어에게서나 기대할 법한 행동임

https://tsz.dev/sound-mode/
이건 훌륭함. TypeScript에는 이런 게 더 필요하고, 더 알려져서 Microsoft가 채택할 수도 있길 바람
다만 이름을 sound mode라고 부르는 건 조심해야 할 것 같음
“수학적 의미의 건전성 증명이 아니며, 서드파티 .d.ts 파일을 참으로 만들지 않는다”는 문장에는 서로 완전히 다른 두 가지가 섞여 있음
첫째, 건전성은 수학적인 개념임. 무언가가 건전하면 정말로 건전한 것이고, 세부사항을 수동으로 확인하지 않아도 컴파일러를 믿을 수 있다는 뜻임
구현 버그가 있으면 잘못 동작할 수 있지만 고칠 수 있고, 건전성은 명세나 타입 시스템 자체에 이론적으로 잘못될 버그가 없다는 뜻임
둘째, 현실의 언어에 사람이 올바르게 사용한다고 믿는 미검사 기능이 필요한 건 완전히 괜찮고 예상 가능한 일임. Haskell의 unsafeCoerce나 Java의 sun.misc.unsafe 같은 것임
진짜 문제는 그런 기능을 쓰지 않았는데도 타입 시스템이 깨지는 경우임

동작한다고 부르는 건 좀 과장임
코드를 몇 분 봤을 뿐이지만, 최적화를 켜는 순간 크게 망가질 것 같음

아마 수개월 동안 이걸 계획하고 실험해 왔을 것임
큰 기존 테스트 스위트에 더해 에이전트를 병렬화하는 도구와 사실상 무제한 토큰 예산도 있었을 테니 너무 낙담할 필요는 없음

주의와 미디어에 대한 내 생각을 많이 바꾼 책이 있음 [0]
책 자체가 아주 좋진 않지만 여기와 관련 있는 지점을 짚음
크고 화려한 발표의 도달 범위, 예컨대 “Bun이 몇 주 만에 메모리 안전한 Rust로 재작성됐다”는 메시지와, 정정의 도달 범위, 예컨대 오래된 기사 각주나 GitHub 이슈 사이에는 엄청난 비대칭이 있음
이 비대칭은 마케팅과 PR 업계가 잘 이해하고 적극적으로 활용함
[0] https://en.wikipedia.org/wiki/Trust_Me,_I%27m_Lying

이번 분위기를 보면 코드에 대한 어떤 비판이든 찾아내서 최대한 증폭하려는 사람이 많아 보임
지금으로서는 대부분 꽤 얕아 보임
큰 LLM 보조 포팅을 병합한 건 분명 매우 대담한 결정이지만, 실제 결과물에 대해 사람들이 지적하는 내용 중 다른 진행 중 포팅보다 더 나쁘다고 느껴지는 건 많지 않음
발견되는 이슈마다 과하게 부풀려지고 있음

그들이 정말 메모리 안전하다고 주장했는지부터 의문임
이 주제의 모든 논의에는 바이브 코딩된 코드베이스가 감사되지 않은 unsafe 블록으로 터질 듯하고, Rust를 이해하지 못하는 듯한 사람들이 가볍게 리뷰했다는 댓글이 수십 개씩 달렸음
심지어 어떤 프로그래밍 언어든 이해해야 한다는 생각 자체에 화내는 것처럼 보이기도 함

“거짓말은 진실이 신발을 신기도 전에 지구 반 바퀴를 돈다”는 인용구가 말하는 개념이 이건가 싶음

마케팅과 PR뿐 아니라 주류 매체도 헛소리를 먼저 내보낸 뒤 나중에 철회해도 지속 효과가 있다는 걸 알고 있음
사람들은 원래 기사나 헤드라인은 기억하지만 정정은 보지 못하는 경우가 많음

오히려 반대 방향의 문제를 말할 줄 알았음
포팅은 아직 진행 중이라 크고 화려한 발표가 없었고, 아직 완료되거나 릴리스되지 않았음
내가 보는 화려한 발표는 진행 중 코드에 대한 치고 빠지기식 조롱과, 마치 팀이 완료됐거나 완벽하다고 말한 것처럼 암시하는 시도들임
재작성은 출발점으로 삼기 위한 코드 번역이었음
Bun 팀은 코드가 이제 메모리 안전하다고 크게 발표한 적이 없고, 출발점이라고 분명히 말해 왔음
즉시 완벽하고 원래 Zig 코드의 모든 메모리 문제를 해결했어야 한다고 기대하는 건 Bun 팀의 실제 발표가 아니라 상상한 발표와 싸우는 것임
이 메모리 문제가 원래 코드베이스에도 존재하는지 매핑해 본 사람이 있는지도 궁금함

이런 종류의 오류는 예상 가능했음
안정성이 필요한 사람들을 위해 안정 버전은 Zig로 남겨뒀고, 결국 오류들은 고쳐질 것이라 봄

이런 오류는 충분히 피할 수 있었음
Rust 생태계에는 이런 오류를 잡는 잘 알려진 도구들이 있고, unsafe 블록 실수로 생기는 정의되지 않은 동작을 전부 잡진 못하더라도 실행하는 것이 좋은 관행으로 여겨짐

가장 걱정되는 건 메타 대화임
처음에는 이 GitHub 이슈를 주제에서 벗어났다고 닫은 유지보수자들을 비판적으로 봤음
그런데 GitHub UI가 정보 가치가 전혀 없는 메시지들을 한꺼번에 자동 접기하고 있었고, 그 메시지들은 포럼이나 커뮤니티 Discord에서 몰려온 듯했음
이건 모두를 지는 상황에 몰아넣음
관련 커뮤니티 다수가 걱정할 만한 중대한 문제를 발견한 사람은 가능한 한 널리 알릴 충분한 이유가 있음
최근 변경에 대한 실질적인 요청이고, 말투를 문제 삼는다고 사실성이 사라지진 않음
문제는 추가 관심이 말 그대로 논의를 죽인다는 점임
유지보수자 쪽에서 더 감정적이거나 AI 정신증에 가까운 결정을 내리는 사람에게도 방패막이가 될 수 있음
비판을 차단하고 무시하는 포위 심리의 프로젝트는 매우 빠르게 탈선하기 쉬움
반대로 유지보수자를 AI에 대한 불안과 병리에서 보호하지 못하는 프로젝트에서는 유지보수자 번아웃이 필연적임

이번 Bun 재작성은 Mythos 마케팅을 위한 잠재적 이벤트처럼 느껴짐

지금까지 Bun 팀이나 Anthropic 누구도 이걸 더 나은 컴파일러 보장을 가진 더 메모리 안전한 언어로 바꾸는 것 이상으로 과장해 마케팅한 적은 없음
현재까지의 화제와 홍보는 대부분 AI에 반대하는 사람들의 부정적 반응에서 나왔음
내 생각엔 최근 Anthropic의 몇몇 결정으로 인해 Anthropic 자체에 대한 부정적 인식이 커진 것도 많이 얽혀 있음

그냥 기업식 러그풀로 보임
Anthropic의 필요만이 유일한 우선순위이고, 나머지는 신경 쓰지 않는다는 느낌임

무제한 토큰에 얼마나 많은 돈을 썼는지 모를 정도로 재작성을 돌림
“Claude Code가 Bun 팀이 Zig 100만 줄 이상을 Rust로 재작성하게 해 줬다”고 크게 떠들고 블로그 글을 쓰면 VC들이 군침을 흘림
기본 검사에서 실패함
Mythos가 코드베이스를 갈기갈기 찢게 두고 또 얼마나 많은 돈을 쓰는지 모름
별도 블로그 글을 씀
사기꾼들과 단순한 사람들이 박수치며 “망상적인 반AI 군중”에 맞서 옹호함
VC들은 더 흥분함
이게 돈 버는 법임
그리고 이제 소프트웨어 엔지니어도 없애야 한다는 식으로 흘러감

안전하지 않은 언어의 코드베이스에 또 다른 안전하지 않은 언어 바인딩까지 들어 있는데, 곧바로 완벽하게 구현돼 보일 거라고 왜 가정하는지 모르겠음

AI 자동 생성 콘텐츠

본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0