Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions data/contributions/8536386.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
---
title: "[textdecoder] Clear JIS0212 state on EUC-JP errors"
date: 2026-10-08
resolvedDate: 2026-10-13
author: Yelihi
contribution_url: https://crrev.com/c/8536386
module: blink
kind: fix
keywords: ["TextDecoder", "TextCodecCJK", "EUC-JP", "JIS0212", "encoding", "wpt"]
status: merged
crbug: 467624168
related: [8503856]
externalLinks:
- title: "WPT PR #63590 · EUC-JP 오류 이후 JIS0212 상태 회귀 테스트"
url: https://github.com/web-platform-tests/wpt/pull/63590
---

EUC-JP 디코딩 중 잘못된 JIS0212 바이트열을 만난 뒤에도 문자표 선택 상태가 남아,
같은 세션의 후속 문자를 잘못 해석하던 문제를 수정했습니다. 오류 경로에서 상태를
초기화하는 한 줄을 추가하고, 일반 입력·스트리밍·fatal 오류 이후 재개를 확인하는
WPT 회귀 테스트를 추가했습니다.

## 문제 설명

EUC-JP 디코더는 `0x8F`로 시작하는 JIS0212 시퀀스를 읽을 때 `jis0212_`로
문자표 선택 상태를 관리합니다. 세 번째 바이트가 유효하지 않으면 오류를 반환하지만,
기존 오류 경로에서는 이 상태를 지우지 않았습니다.

그 결과 같은 디코딩 세션에서 뒤이어 정상적인 JIS0208 바이트 쌍이 들어와도
JIS0212 문자표로 해석해 잘못된 결과를 만들 수 있었습니다. 예를 들어
`0x8F 0xA2 0x20` 뒤에 `0xA1 0xA1`을 전달하면, 마지막 바이트 쌍은
전각 공백 `U+3000`으로 해석되어야 합니다.

선행 [CL 8503856](https://crrev.com/c/8503856)은 입력 종료 시 상태를 초기화해
다음 세션으로 넘어가는 문제를 해결했습니다. 이번 사례는 입력이 끝나기 전,
같은 세션 안에서 오류 이후의 디코딩을 계속하는 경로에 남아 있었습니다.

## 해결 내용

`third_party/blink/renderer/platform/wtf/text/text_codec_cjk.cc`의
`EucJpDecoder::ParseByte()` 오류 경로에 `jis0212_ = false;`를 추가했습니다.
다음 바이트를 처리하기 전에 문자표 선택을 해제하도록 한 변경입니다.

아래는 변경 위치를 발췌한 코드입니다. 첫 줄이 이번 CL에서 추가한 부분입니다.

```cpp
jis0212_ = false;
if (IsAscii(byte)) {
prepended_byte_ = byte;
}
```

오류를 일으킨 바이트가 ASCII이면 재처리할 수 있도록 보관하는 기존 동작은
유지합니다. 따라서 문자표 상태는 지우면서도 해당 ASCII 문자를 잃지 않습니다.
기존 코덱 재사용과 입력 종료 시의 초기화 역시 유지했습니다.

## 테스트 방법

`encoding/textdecoder-mistakes.any.js`에 네 종류의 입력 벡터와 fatal 스트리밍
오류 이후 재개 테스트를 추가했습니다.

### 일반 입력과 스트리밍 경계

다음 입력을 한 번에 디코딩한 결과와, 가능한 모든 두 청크 분할 위치에서
디코딩한 결과가 같은지 검사합니다. 첫 청크는 `{stream: true}`로 처리합니다.

| 입력 바이트 | 기대 결과 | 검증 내용 |
| --- | --- | --- |
| `8F A2 20 A1 A1` | `U+FFFD`, ASCII 공백, `U+3000` | 오류 뒤 ASCII 재처리와 JIS0208 복구 |
| `8F A2 A0 A1 A1` | `U+FFFD`, `U+3000` | 유효 범위 아래의 세 번째 바이트 |
| `8F A2 FF B0 A1` | `U+FFFD`, `U+4E9C` | 유효 범위 위의 세 번째 바이트 |
| `8F A2 AF A1 A1` | `U+02D8`, `U+3000` | 정상 JIS0212 처리 뒤 JIS0208 해석 유지 |

각 벡터는 바이트 다섯 개로 구성되어, 단일 입력 한 경우와 분할 위치 네 경우를
검사합니다. 여기에 fatal 오류 테스트를 더해 총 21개의 테스트 케이스를 추가했습니다.

### fatal 스트리밍 오류 이후 재개

`fatal: true`에서는 잘못된 시퀀스가 `TypeError`를 발생시켜야 합니다.
이후 같은 디코더로 입력을 이어 가면, 재처리 대기 중인 ASCII 공백과 정상적인
JIS0208 문자가 함께 출력되는지 확인합니다.

아래는 추가한 테스트의 핵심 부분입니다. `u()`는 해당 테스트 파일의 바이트 배열
생성 헬퍼입니다.

```js
const d = new TextDecoder('euc-jp', {fatal: true});
assert_throws_js(TypeError,
() => d.decode(u(0x8f, 0xa2, 0x20), {stream: true}));
assert_equals(d.decode(u(0xa1, 0xa1)), ' \u3000');
```

### 리뷰와 CQ 결과

Gerrit 리뷰 요청에서 Adam Rice가 CL 8503856에서 지적한 EUC-JP 문제의
후속 수정임을 명시했습니다. 2026년 10월 8일 Patch Set 1의 CQ dry run이
통과했고, Adam Rice와 Kent Tamura의 승인을 거쳐 10월 13일 리베이스된
Patch Set 2가 머지됐습니다.

추가한 회귀 테스트는 같은 날 WPT PR #63590으로 upstream에 머지됐습니다.
Gerrit export 댓글과 upstream의 `encoding/textdecoder-mistakes.any.js` 변경을
대조했습니다. 이 문서 작성 과정에서 Chromium 테스트를 별도로 실행하지는 않았습니다.

## 연관 CL과 외부 PR

- [CL 8503856 — 입력 종료 후 CJK 디코더 상태 초기화](https://crrev.com/c/8503856):
ISO-2022-JP와 EUC-JP의 상태가 다음 디코딩 세션으로 넘어가는 문제를 해결한
선행 변경입니다. 해당 리뷰에서 이번 오류 처리 경로의 문제가 제기됐습니다.
- [WPT PR #63590 — EUC-JP 상태 회귀 테스트](https://github.com/web-platform-tests/wpt/pull/63590):
현재 CL에서 자동 export된 테스트 PR입니다. 별도 기여로 중복 집계하지 않고
`externalLinks`로 연결했습니다.
- [Chromium 이슈 467624168](https://crbug.com/467624168):
선행 CL과 현재 CL이 참조하는 디코더 상태 관련 이슈입니다.

## 배운 점

- 상태를 가진 파서는 입력 종료뿐 아니라 오류 이후에도 다음 입력을 해석할 수 있는
상태로 복구해야 합니다.
- 오류 상태를 지우는 것과 재처리할 입력을 보존하는 것은 별개의 책임입니다.
ASCII 재처리 동작을 유지하면서 문자표 선택만 초기화해야 합니다.
- 바이트열을 한 번에 전달하는 테스트 외에 청크 경계를 바꾼 스트리밍 테스트와
예외 이후 재개 테스트를 함께 두면 상태 잔류를 더 정확하게 검증할 수 있습니다.

## 참고 자료

- [현재 CL 8536386 — 설명·변경 코드·리뷰 기록](https://chromium-review.googlesource.com/c/chromium/src/+/8536386)
- [Patch Set 2 — EUC-JP 오류 경로 수정](https://chromium-review.googlesource.com/c/chromium/src/+/8536386/2/third_party/blink/renderer/platform/wtf/text/text_codec_cjk.cc)
- [Patch Set 2 — WPT 회귀 테스트](https://chromium-review.googlesource.com/c/chromium/src/+/8536386/2/third_party/blink/web_tests/external/wpt/encoding/textdecoder-mistakes.any.js)
- [병합된 커밋 951c29c2ac34](https://chromium.googlesource.com/chromium/src/+/951c29c2ac34c231b6e038c296d131104df8391f)
Loading