Hacktoberfest 2026:維護者為十月標記出來的 issue,仍然開放、適合新手。 瀏覽 Hacktoberfest issue

test_runner: backport #64706 to v22.x — non-ASCII test stdout can silently drop a whole test file

未關閉
#65,934 2 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

維護者通常 1 天內回覆

還沒有人認領這個 Issue。

評估

難度
4/5
預估耗時
3-5 天
新手友好度
58/100
Issue 類型
缺陷
描述清晰度
描述清楚
活躍度
活躍
技術堆疊
javascript, node.js
領域
testing-qa

研究方向

從修正 #64706 開始,並比較 v22.x-staging 上的 lib/internal/test_runner/runner.js,然後在 v22.x 線上使用 node --test 執行 repro.mjs 範例。修正已回移植,且非 ASCII stdout 的重現不再損壞或遺失測試檔案,即表示完成。

由索引模型根據 Issue 內容生成。

描述

Request

Please consider backporting #64706 (fix for #64061) to the v22.x release line.

State as of 2026-09-09, checked with the GitHub contents API against lib/internal/test_runner/runner.js, looking for ) >>> 0) + kSerializedSizeHeader:

ref has the fix
main yes
v26.x yes
v24.x, v24.x-staging yes
v22.x, v22.x-staging no

#64706 carries no dont-land-on-v22.x label, and I could not find an existing backport request or backport PR for v22.x.

The line is actively released — the most recent v22 release is v22.23.2 (2026-07-29), three days after #64706 landed on main (2026-07-26).

Why this may deserve more weight than the original report suggested

#64061 was reported as an intermittent CI flake. On v22.19.0 I traced the trigger, and it turns out not to be exotic: it is ordinary non-ASCII text written to stdout by a test.

FileTest.#processRawBuffer advances bufferHead past a consumed message and then reads the next four bytes as a length without re-checking for the FF 0F header:

bufferHead = TypedArrayPrototypeSubarray(concatenatedBuffer, fullMessageSize);
this.#rawBufferSize = TypedArrayPrototypeGetLength(bufferHead);
...
while (bufferHead?.length >= kSerializedSizeHeader) {
  const fullMessageSize = (
    bufferHead[kV8HeaderLength] << 24 |
    bufferHead[kV8HeaderLength + 1] << 16 |
    bufferHead[kV8HeaderLength + 2] << 8 |
    bufferHead[kV8HeaderLength + 3]
  ) + kSerializedSizeHeader;          // signed 32-bit

  if (this.#rawBufferSize < fullMessageSize) break;

When a test's own stdout follows a report message inside the same read, those bytes are interpreted as a length. Every UTF-8 lead/continuation byte is >= 0x80, so any non-ASCII output — CJK, emoji, accented Latin — can make fullMessageSize negative, which defeats the break guard and hands garbage to DefaultDeserializer.

In our repository the emitter was a server start-up banner containing an emoji, printed by the code under test. Three sightings over two days, always the same test file.

Minimal deterministic reproduction

No load, no concurrency, no flakiness. One write():

// repro.mjs   —   node --test repro.mjs
import { writeSync } from 'node:fs';
import test from 'node:test';
import { DefaultSerializer } from 'node:v8';

test('a passing test', () => {});

const s = new DefaultSerializer();
s.writeHeader();
s.writeValue({ __proto__: null, type: 'test:diagnostic',
               data: { __proto__: null, nesting: 0, message: 'hi', file: 'repro.mjs' } });
const payload = s.releaseBuffer();
const size = Buffer.alloc(4);
size.writeUInt32BE(payload.length);
const message = Buffer.concat([Buffer.from([0xff, 0x0f]), size, payload]);

// a report message, immediately followed by ordinary test stdout, in ONE write
const tail = process.env.ASCII ? '\nserver listening -> http://localhost:3456\n'
                               : '\n\u{1F7E1} 서버 실행 중 -> http://localhost:3456\n';
writeSync(1, Buffer.concat([message, Buffer.from(tail, 'utf8')]));

On v22.19.0, Windows 11 x64:

$ node --test repro.mjs
not ok 1 - repro.mjs
  error: 'Unable to deserialize cloned data due to invalid or unsupported version.'
# fail 1

$ ASCII=1 node --test repro.mjs
ok 1 - a passing test
# fail 0

The only difference between the two runs is whether the trailing stdout is ASCII.

I only have v22.19.0 on this machine, so I have not run this against a fixed release line — the report above is strictly about v22.19.0.

Three symptoms, and one of them is silent

Also observed on v22.19.0, depending on where in the stream the corruption lands:

  1. a file-level failure carrying the message above (the symptom in #64061);
  2. the file's results vanish with no failure and no summary. Running a poisoned file together with a healthy one printed only the healthy file's ok 1 / ok 2 — no 1..N, no # tests, no # fail, no error text. The exit code was 1, but the TAP body reads as a clean pass;
  3. with a length byte below 0x80 but large, the runner waits for a message that never arrives and hangs.

Symptom 2 is the reason I am filing this: on a line that is still in service, a whole test file can drop out of a run while the output looks green, and only the exit code disagrees.

Offer

If the missing step is just a backport-requested-v22.x label or an approval, I am happy to open the [v22.x backport] PR against v22.x-staging — please say so.

主要語言
JavaScript
星號
122k
分支
38.4k
平均合併
4 天 10 小時
30 天內合併 PR
276

環境準備

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

nodejs/node 的其他 Issue

查看 nodejs/node 的全部 Issue

相似的 Issue

更多 JavaScript Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。