diff --git a/contributions/65301.md b/contributions/65301.md new file mode 100644 index 0000000..253b381 --- /dev/null +++ b/contributions/65301.md @@ -0,0 +1,22 @@ +--- +pr-url: https://github.com/nodejs/node/pull/65301 +--- + +## 문제 내용 + +- `lib/internal/streams/fast-utf8-stream.js`의 `Utf8Stream#write()`는 `contentMode`가 `'buffer'`일 때 `Buffer` 인스턴스만 받도록 되어 있었습니다. 정작 내부 구현(`#writeBuffer`, `mergeBuf()`, `Buffer.concat()` 등)이 필요로 하는 건 바이트 단위로 접근 가능한 데이터일 뿐이라, `TypedArray`나 `DataView` 같은 다른 `ArrayBufferView`를 넘기려면 호출부에서 매번 `Buffer.from()`으로 감싸야 했습니다. +- 해당 위치에는 이미 `TODO(@jasnell): Support any ArrayBufferView type here, not just Buffer.`라는 주석이 남아 있어서, 실제로 필요한 확장이 무엇인지 코드 상에 명시되어 있었습니다. 이 TODO를 구현했습니다. +- 코드에 남아 있는 TODO 주석을 찾아 해결하는 접근 방식 자체는 [PR #60161](https://github.com/nodejs/node/pull/60161)(`buffer: remove unreachable overflow check in atob`)을 참고했습니다. 해당 PR도 `lib/buffer.js`의 TODO 주석을 근거로 죽은 코드를 제거한 사례라, "TODO 검색 → 필요성 확인 → 최소 범위로 구현/정리"라는 흐름을 그대로 따랐습니다. + +## 해결 과정과 검증 + +- 상태: `Review 중` (리뷰 요청: `@nodejs/streams`, 아직 리뷰 없음 — GitHub Actions/Linter/Test/Coverage 등 CI 전부 통과) +- `data`가 `ArrayBufferView`인지 먼저 확인(`isArrayBufferView`)하고, `Buffer`가 아닌 뷰라면 단일 진입점에서만 `Buffer.from(data.buffer, data.byteOffset, data.byteLength)`로 변환해 이후 로직은 항상 `Buffer`를 다루도록 했습니다. +- 이때 `byteOffset`/`byteLength`를 기준으로 변환한 것이 핵심입니다. `data.length`(요소 개수)를 그대로 쓰면 `Float64Array`처럼 요소당 8바이트인 타입에서 실제 바이트 수보다 훨씬 작은 값이 되어, `mergeBuf()`/`Buffer.concat()`이나 write-release 로직에서 쓰는 길이 계산이 틀어질 수 있습니다. `lib/zlib.js`의 `zlibBuffer()`가 쓰는 패턴을 그대로 참고했습니다. +- 검증을 위해 `test/parallel/test-fastutf8stream-write-arraybufferview.js`를 새로 추가했습니다. `Uint8Array`/`DataView`/`Float64Array`가 정상적으로 받아들여지는지, `byteOffset`이 0이 아닌 부분 뷰(공유 버퍼의 일부)가 해당 범위만 기록하는지, `ArrayBufferView`가 아닌 값(문자열, 일반 배열)은 여전히 `ERR_INVALID_ARG_TYPE`으로 거부되는지를 `sync: true/false` 두 경우 모두에서 확인했습니다. +- 문서(`doc/api/fs.md`)의 `data` 타입 설명도 `{Buffer}` → `{Buffer|TypedArray|DataView}`로 함께 갱신했습니다. + +## 기여 회고 + +- 새 기능을 스스로 구상하기보다, 코드베이스에 이미 남아 있는 `TODO` 주석을 찾아 그 필요성과 범위가 명확한 작업부터 구현하는 방식으로 접근했습니다. +- zero-copy로 뷰를 재해석할 때 "요소 개수"와 "바이트 길이"를 혼동하지 않는 것, 그리고 그 차이가 실제로 드러나는 타입(`Float64Array` 등)으로 테스트를 짜는 것이 검증의 핵심이라는 걸 확인할 수 있었습니다.