diff options
-rw-r--r-- | std/io/bufio.ts | 6 | ||||
-rw-r--r-- | std/io/bufio_test.ts | 20 | ||||
-rw-r--r-- | std/textproto/test.ts | 13 |
3 files changed, 38 insertions, 1 deletions
diff --git a/std/io/bufio.ts b/std/io/bufio.ts index aa74809fe..5c005672a 100644 --- a/std/io/bufio.ts +++ b/std/io/bufio.ts @@ -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 diff --git a/std/io/bufio_test.ts b/std/io/bufio_test.ts index c49023814..d3e39bff6 100644 --- a/std/io/bufio_test.ts +++ b/std/io/bufio_test.ts @@ -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" + ); +}); diff --git a/std/textproto/test.ts b/std/textproto/test.ts index 3b71bc08c..ec66bfd8c 100644 --- a/std/textproto/test.ts +++ b/std/textproto/test.ts @@ -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); + }, +}); |