FROM THE WORKSHOP / 노하우
macOS iconv는 1KB를 넘으면 멀쩡한 UTF-8에도 실패를 돌려준다 — 유효성 판정기로 쓰지 마라
BSD iconv 는 입력이 약 1024바이트를 넘으면 유효한 UTF-8 에도 rc=1 을 낼 수 있어, 작은 픽스처로는 영원히 안 보이다가 실전 입력에서 터진다. iconv 종료코드를 유효성 정본으로 쓰지 말고 iconv -c 출력 대조나 python3 디코더를 쓰며, 픽스처에 경계보다 큰 케이스를 포함한다.
macOS iconv는 1KB를 넘으면 멀쩡한 UTF-8에도 실패를 돌려준다 — 유효성 판정기로 쓰지 마라
“입력이 올바른 UTF-8인지”를 iconv -f utf-8 -t utf-8의 종료코드로 판정하는 셸 테스트가 있었다. 리눅스에서는 늘 초록. macOS에서만 빨강이 났다. 입력을 아무리 들여다봐도 인코딩은 완벽했다.
범인은 크기였다. macOS(BSD) iconv는 입력이 약 1024바이트를 넘으면 완전히 유효한 UTF-8에도 rc=1을 돌려주는 경우가 있다. 1KB 미만의 픽스처에서는 절대 재현되지 않기 때문에, 작은 샘플로 테스트를 만들면 이 함정은 배포 후에야 큰 실전 입력에서 터진다. GNU iconv(리눅스)와 BSD iconv(macOS)는 이름만 같은 다른 프로그램이라는 것을 잊기 쉽다.
왜 위험한가
- 증상이 입력 내용이 아니라 입력 크기에 달려 있어, “어느 글자가 깨졌나”를 찾는 디버깅이 전부 헛수고가 된다.
- macOS에서만 나므로 “macOS 인코딩 문제”라는 뭉뚱그린 오진으로 흐르기 쉽다.
- 유효성 판정기가 거짓 빨강을 내면, 멀쩡한 데이터가 파이프라인에서 반려된다.
룰
- iconv 종료코드를 UTF-8 유효성의 정본으로 쓰지 않는다. 대안:
iconv -c로 불량 바이트를 걷어낸 출력과 원본을 비교하거나(같으면 유효),python3 -c 'open(p,"rb").read().decode("utf-8")'같은 명시적 디코더를 쓴다. - macOS에서 인코딩 관련 빨강이 나면 코드보다 입력 크기부터 잰다. 1KB 경계 위인지 아래인지가 첫 분기다.
- 크로스 플랫폼 픽스처에는 경계보다 큰 입력 케이스를 반드시 포함한다. 작은 샘플만으로는 이 계열 결함이 영원히 안 보인다.
덤으로, 같은 스윕에서 잡힌 이웃 함정 하나: macOS 기본 bash 3.2에서는 set -u 상태에서 빈 배열을 "${arr[@]}"로 펼치면 그 자리에서 죽는다(신형 bash는 통과). macOS 셸 스크립트의 하한선은 언제나 bash 3.2다.
체크리스트
- 인코딩 유효성 판정에 iconv 종료코드를 쓰고 있는가?
- 그 판정이 통과하는 픽스처의 크기는 실전 입력과 같은 자릿수인가?
- “macOS에서만 실패”에 결함 항목 이름(BSD iconv 1KB 거짓 빨강)이 붙어 있는가?
한 문장으로. 판정기의 결함은 데이터의 결함처럼 보인다 — 계기부터 검증해야 입력을 의심할 자격이 생긴다.