fix(std/io): BufReader should not share the internal buffer across reads (#4543)

This commit is contained in:
uki00a 2020-05-20 23:34:20 +09:00 committed by GitHub
parent ef14d62462
commit 9b4da88a96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 1 deletions

View file

@ -338,7 +338,11 @@ export class BufReader implements Reader {
// Buffer full?
if (this.buffered() >= this.buf.byteLength) {
this.r = this.w;
throw new BufferFullError(this.buf);
// #4521 The internal buffer should not be reused across reads because it causes corruption of data.
const oldbuf = this.buf;
const newbuf = this.buf.slice(0);
this.buf = newbuf;
throw new BufferFullError(oldbuf);
}
s = this.w - this.r; // do not rescan area we scanned before

View file

@ -12,6 +12,7 @@ import {
BufWriterSync,
BufferFullError,
PartialReadError,
ReadLineResult,
readStringDelim,
readLines,
} from "./bufio.ts";
@ -445,3 +446,22 @@ Deno.test("readStringDelimAndLines", async function (): Promise<void> {
assertEquals(lines_.length, 10);
assertEquals(lines_, ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
});
Deno.test(async function bufReaderShouldNotShareArrayBufferAcrossReads() {
const decoder = new TextDecoder();
const data = "abcdefghijklmnopqrstuvwxyz";
const bufSize = 25;
const b = new BufReader(stringsReader(data), bufSize);
const r1 = (await b.readLine()) as ReadLineResult;
assertNotEOF(r1);
assertEquals(decoder.decode(r1.line), "abcdefghijklmnopqrstuvwxy");
const r2 = (await b.readLine()) as ReadLineResult;
assertNotEOF(r2);
assertEquals(decoder.decode(r2.line), "z");
assert(
r1.line.buffer !== r2.line.buffer,
"array buffer should not be shared across reads"
);
});

View file

@ -180,3 +180,16 @@ test({
assertEquals(m.get("Content-Disposition"), 'form-data; name="test"');
},
});
test({
name: "[textproto] #4521 issue",
async fn() {
const input = "abcdefghijklmnopqrstuvwxyz";
const bufSize = 25;
const tp = new TextProtoReader(
new BufReader(stringsReader(input), bufSize)
);
const line = await tp.readLine();
assertEquals(line, input);
},
});