OSSCA Chromium

기여 목록 / 8503856

[textdecoder] Reset CJK state after flushing

BlinkfixMerged

TextDecoder에서 ISO-2022-JP와 EUC-JP 디코딩을 끝낸 뒤에도 내부 상태가 남아, 같은 디코더의 다음 세션에 영향을 주는 문제를 수정했습니다. 입력 종료 시 상태를 초기화하되, 스트리밍 중의 상태와 기존 코덱 재사용 최적화는 유지했습니다.

문제 설명

Blink는 디코딩 세션마다 TextCodec 객체를 새로 만들지 않고, 이전 세션에서 flush한 코덱을 재사용합니다. 따라서 flush가 끝나면 다음 세션이 초기 상태에서 시작할 수 있어야 합니다.

그러나 ISO-2022-JP는 문자 집합과 입력 처리 상태를, EUC-JP는 JIS0212 문자표의 선택 상태를 입력 종료 후에도 보관했습니다. 이 때문에 앞선 입력에서 설정한 상태가 다음 세션의 바이트 해석에 영향을 줬습니다.

반면 {stream: true}로 입력을 나누어 전달하는 동안에는 기존 상태를 유지해야 합니다. 스트리밍 청크 사이와 하나의 디코딩 세션이 끝나는 시점을 구분하는 것이 이번 수정의 핵심입니다.

해결 내용

  1. ISO-2022-JP: 입력 종료 시 남은 입력을 처리한 다음, 선행 바이트와 재처리용 바이트를 비우고 디코더 상태·출력 상태를 ASCII로 되돌렸습니다.
  2. EUC-JP: 기존 Finalize 훅을 재정의해 flush일 때만 jis0212_를 false로 초기화했습니다.
  3. 코덱 재사용: TextDecoder의 할당 로직은 유지하고, 완전한 flush 후 코덱을 재사용하며 flush 중 fatal 오류가 나면 코덱을 버린다는 설명으로 주석을 정리했습니다.

다음은 text_codec_cjk.cc의 EucJpDecoder에 추가한 코드입니다.

void Finalize(bool flush, StringBuilder&) override {
  if (flush) {
    // Do not carry the JIS0212 selection into the next decoding session.
    jis0212_ = false;
  }
}

ISO-2022-JP 역시 EOF 처리를 먼저 마친 뒤 초기화합니다. 남은 입력을 처리하기 전에 상태를 지우면 불완전한 입력에 대한 기존 오류 처리까지 달라질 수 있으므로, 초기화 순서를 유지했습니다.

테스트 방법

encoding/iso-2022-jp-decoder.any.js에 다음 회귀 테스트를 추가했습니다. 각 경우를 fatal: false와 fatal: true로 검사합니다.

  • 이스케이프 시퀀스를 청크 사이에 나누어 전달해도 올바르게 해석하고, 마지막 청크 처리 후 다음 세션은 ASCII 상태에서 시작하는지 확인합니다.
  • 스트리밍으로 문자 집합을 바꾼 뒤 인자 없는 decode()로 flush하면, 다음 세션에 이전 문자 집합이 남지 않는지 확인합니다.

아래는 첫 번째 테스트의 핵심 부분을 발췌한 코드입니다. fatal은 테스트 반복문에서 설정하는 옵션입니다.

const decoder = new TextDecoder('iso-2022-jp', {fatal});
assert_equals(decoder.decode(Uint8Array.of(0x1b, 0x28), {stream: true}), '');
assert_equals(decoder.decode(Uint8Array.of(0x49, 0x21)), '\uFF61');
assert_equals(decoder.decode(Uint8Array.of(0x21)), '!');

기존 textdecoder-mistakes의 일반·worker 기대 결과에서도 ISO-2022-JP 출력 연결과 ISO-2022-JP·EUC-JP의 상태 잔류에 관한 실패 세 개를 제거했습니다. 각각의 기대 실패는 4개에서 1개로 줄었으며, Replacement, push back ASCII characters: iso-2022-jp 실패는 이 CL에 남아 있습니다.

Gerrit 기록상 2026년 10월 2일 Patch Set 1의 CQ dry run이 통과했습니다. Adam Rice와 Kent Tamura의 리뷰를 거쳐 10월 6일 CQ 실행 후 Patch Set 2가 머지됐습니다. 추가한 WPT는 같은 날 upstream PR #63304로 머지됐습니다. 이 문서 작성 과정에서 Chromium 테스트를 별도로 실행하지는 않았습니다.

연관 CL과 외부 PR

배운 점

  • 상태를 가진 객체를 재사용할 때는 이전 작업을 마치는 처리와 다음 작업을 위한 초기화가 모두 필요합니다.
  • 스트리밍에서는 청크가 끝나는 시점과 전체 입력이 끝나는 시점을 구분해야 합니다. 상태를 너무 일찍 지우면 청크 사이에 걸친 문자나 이스케이프 시퀀스를 해석할 수 없습니다.
  • 세션 종료 시 초기화와 세션 도중 오류 복구는 별도의 경로이므로, 각각의 상태 잔류를 나누어 검증해야 합니다.

참고 자료