Ripgrep musl 바이너리가 초대형 검색 중 간헐적으로 세그멘테이션 오류를 일으킴
요약
Ripgrep의 musl 바이너리가 대규모 검색 시 발생하는 세그멘테이션 오류의 원인이 커널 버그임을 분석합니다. musl의 mallocng 할당자와 커널의 페이지 관리 방식 간의 상호작용 문제를 다루며, AI 에이전트가 버그 분석을 수행하는 미래의 변화를 전망합니다.
핵심 포인트
- Ripgrep의 musl 바이너리에서 발생하는 세그멘테이션 오류는 커널 버그로 식별됨
- musl의 mallocng 할당자가 커널 버그를 발견하는 데 기여함
- HPC 환경에서 대규모 파일 시스템 대상의 ripgrep 실행 시 주의 필요
- AI 에이전트가 버그 분석 및 검증을 주도하는 개발 환경의 변화 예고
읽기 고역이었고, 그 장황한 글 어디에서도 lore.kernel의 실제 사람이 찾아낸 것과 같은 코드나 영역을 짚은 부분을 못 찾겠음. Claude를 더 잘 이해하는 사람에게 묻고 싶은데, 실제 원인을 식별한 대목이 있기는 한가?
2000년 무렵까지 공공장소에서 휴대전화를 쓰는 사람은 잘난 체하는 재수 없는 사람처럼 취급됐고, 지금 AI도 그와 비슷한 불쾌한 거부 단계를 지나고 있음
2년 전이었다면 이런 분석은 공동체에 시간을 후하게 기부한 결과로 여겨졌겠지만, 이제는 출처와 토큰 비용이 고작 0.06달러라는 걸 아니 읽으려 하지 않음. 앞으로 벌어질 일을 예고한다는 점도 한몫함
몇 년 뒤에는 사람이 직접 버그를 파헤치는 일이 최후의 수단이 되고, 다른 AI 에이전트가 보고서를 읽어 수정 사항을 검증할 것임. 컴파일러가 생성한 어셈블리와 공공장소의 휴대전화 사용자를 무시하듯, 비웃는 단계에서 무관심한 단계로 넘어갈 듯함
musl의 기본 할당자를 편리하다는 이유로 그대로 쓰는 건 이해하지만, 속도 자체가 목적인 애플리케이션에서 더 빠른 할당자로 바꾸지 않은 건 이상함
mallocng는 다중 스레드 경합에 취약함. 평소 입출력 병목이던 애플리케이션도 musl로 빌드하면 스레드 8개만으로 malloc 병목이 생겼고, mimalloc으로 바꾸자 성능이 20배 향상되어 glibc 기본 구성에 매우 가까워졌으며 glibc+mimalloc보다는 조금 느렸음
실제로 흥미로운 문제가 있는 건 맞지만 애초에 이런 식으로 드러나서는 안 됐음
세그멘테이션 오류 스택을 보면 할당은 musl libc의 opendir에서 발생함. Rust가 사용하는 할당자 교체 방식은 프로세스 전체의 할당자를 바꾸는 게 아니라 Rust 코드가 호출하는 할당자만 교체함
다만 전역 잠금을 사용하는 할당자를 거쳐야 한다면 ripgrep이 libc의 opendir 사용을 피하는 편이 나아 보임
이건 커널 버그임. libc 할당자들이 별 이유 없이 형편없다는 데는 동의하지만, 이 문제는 mimalloc이나 glibc를 비롯한 다른 애플리케이션 코드에서도 비슷한 확률로 발생할 수 있어 보임
대부분의 프로그램은 할당을 재사용해 속도를 높임. 아예 할당하지 않는다면 빠른 할당자도 필요 없고, ripgrep의 작업 자체가 빈번한 할당을 본질적으로 요구하지도 않음
오히려 musl의 mallocng가 제공하는 강화 기능 덕분에 커널 버그를 발견할 수 있었음. 그렇지 않았다면 수개월 동안 조용히 메모리를 손상시키며 눈에 띄지 않았을 수도 있음
HPC 클러스터에서 대규모 클러스터 파일 시스템을 상대로 ripgrep을 실행한다면 즉시 멈추고 작업 흐름을 다시 설계해야 함. 이런 작업은 대량의 작은 입출력을 발생시키는데, 이는 대규모 클러스터 파일 시스템의 아킬레스건임
클러스터의 고대역폭 메모리 계층에서 처리할 일을 파일 시스템의 메타데이터 계층으로 떠넘기게 되며, 사용자 몇 명만 동시에 실행해도 고대역폭 파일 시스템 전체가 마비될 수 있음
이건 HPC 클러스터가 아니라 내 워크스테이션에서 사용하는 btrfs일 뿐임
최근 GitHub가 불안정해진 근본 원인도 비슷한 게 아닌지 궁금했음. AI 사용으로 증폭된 수십억 개의 작은 파일 작업이 갑자기 발생하고 있으며, 객체 그래프는 본질적으로 파편화돼 있어 페이지 하나를 미리 가져온 뒤 일반적인 Git 작업이 그 페이지 안의 객체만 건드리도록 만들기도 어려움 https://isolveproblems.substack.com/p/how-microsoft-vaporize...의 내용이 조금이라도 맞는다면, Azure의 파일 시스템 추상화에서 최적화되지 않은 경로 하나만 있어도 사용량 급증이 막대한 장애 반경으로 번질 수 있음
읽어보려 했지만 첫 번째 Headline 문단에서 포기했음
“새로 페이지 폴트가 난 익명 페이지에 스레드가 저장한 값이 약 10개 명령어 뒤 같은 스레드의 재읽기에서 사라지고, 함수 실행 도중 페이지의 backing이 교체된다”, “폴트 순간 pagemap을 읽으면 backing이 커널의 zero page다”, “메커니즘이 VMA별 잠금의 익명 폴트 빠른 경로와 동시 munmap의 TLB shootdown 사이 상호작용으로 localize된다” 같은 문장이 이어짐
페이지의 backing이 무엇인지, freshly-faulted나 “약 10개 명령어 뒤”가 어떤 의미인지, 메커니즘이 어떻게 “localize”된다는 건지 이해하기 어려움. 기술 설명이라기보다 단어를 이어 붙인 글처럼 보임
제대로 된 기술 문서의 예시는 다음과 같음: https://yifan.lu/2019/01/11/the-first-f00d-exploit/
“오버플로는 여전히 오버플로하고, 해제 후 사용은 여전히 해제 후 사용하며, musl 마스크 경쟁은 여전히 경쟁한다”는 대목은 컴퓨터 시 같아 웃김
결론은 대략 Linux 7.0과 musl 1.2.5의 조합에 문제가 있다는 듯하지만, 재현은 여전히 같은 물리적 Threadripper CPU에서 강한 부하를 줄 때 간헐적으로만 성공하므로 하드웨어 문제를 배제하지 못했음
AI 생성 버그 보고서를 읽는 건 끔찍함
추적 자체는 훌륭하지만 설명은 말이 안 됨. 추가적인 TLB 플러시는 오류가 될 수 없으며 CPU는 원할 때 언제든 플러시할 수 있음. 실제 오류는 있어서는 안 될 때 zero-page PTE가 존재한 데 있는 듯함
어색한 순간에 CPU가 마이그레이션되며 발생한 복잡한 경쟁 상태이거나, 페이지 테이블 제거 경로가 잘못된 PTE를 일시적으로 노출한 버그로 보임. zero page의 PFN이 0이라고도 생각하지 않음
추측하자면 직접적인 페이지 테이블 제거 과정에서 CPU가 상위 페이징 구조의 캐시된 항목을 통해 이미 해제되고 재사용된 테이블을 읽도록 허용했을 가능성이 있음. 예전에 이런 문제를 디버깅한 적이 있는데 정말 끔찍했음
전형적으로 장황한 LLM 찌꺼기 분석임. 맞는 분석일 수도 있지만 자세히 읽기 힘들고, 사람이 같은 분석을 했다면 분량을 5분의 1로 줄였을 것임
왜 다른 libc가 아니라 musl libc에서만 버그가 발생하는가?
우연일 뿐이며 한 대의 머신에서만 발생하기도 함
musl 할당자는 새로 페이지 폴트가 발생한 단일 페이지를 애플리케이션에 바로 노출하기 때문일 가능성이 큼. 다른 할당자는 보통 여러 페이지를 한꺼번에 미리 할당하므로 경쟁 조건의 시간 창이 더 좁아짐
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기