Repository: denoland/deno
Pull request: fix(ext/node): Buffer write OOB checks

Enables `parallel/test-buffer-write.js` test

Changed files:
filename: ext/node/polyfills/internal/buffer.mjs
patch: @@ -794,6 +794,15 @@ Buffer.prototype.asciiSlice = function asciiSlice(offset, length) {
 };
 
 Buffer.prototype.asciiWrite = function asciiWrite(string, offset, length) {
+  // deno-lint-ignore prefer-primordials
+  if (offset < 0 || offset > this.byteLength) {
+    throw new codes.ERR_BUFFER_OUT_OF_BOUNDS("offset");
+  }
+  // deno-lint-ignore prefer-primordials
+  if (length < 0 || length > this.byteLength - offset) {
+    throw new codes.ERR_BUFFER_OUT_OF_BOUNDS("length");
+  }
+
   return blitBuffer(asciiToBytes(string), this, offset, length);
 };
 
@@ -865,6 +874,15 @@ Buffer.prototype.latin1Write = function latin1Write(
   offset,
   length,
 ) {
+  // deno-lint-ignore prefer-primordials
+  if (offset < 0 || offset > this.byteLength) {
+    throw new codes.ERR_BUFFER_OUT_OF_BOUNDS("offset");
+  }
+  // deno-lint-ignore prefer-primordials
+  if (length < 0 || length > this.byteLength - offset) {
+    throw new codes.ERR_BUFFER_OUT_OF_BOUNDS("length");
+  }
+
   return blitBuffer(asciiToBytes(string), this, offset, length);
 };
 
@@ -890,6 +908,15 @@ Buffer.prototype.utf8Slice = function utf8Slice(string, offset, length) {
 };
 
 Buffer.prototype.utf8Write = function utf8Write(string, offset, length) {
+  // deno-lint-ignore prefer-primordials
+  if (offset < 0 || offset > this.byteLength) {
+    throw new codes.ERR_BUFFER_OUT_OF_BOUNDS("offset");
+  }
+  // deno-lint-ignore prefer-primordials
+  if (length < 0 || length > this.byteLength - offset) {
+    throw new codes.ERR_BUFFER_OUT_OF_BOUNDS("length");
+  }
+
   offset = offset || 0;
   const maxLength = MathMin(length || Infinity, this.length - offset);
   const buf = offset || maxLength < this.length
@@ -993,7 +1020,6 @@ function _base64Slice(buf, start, end) {
     return forgivingBase64Encode(buf.slice(start, end));
   }
 }
-
 const decoder = new TextDecoder();
 
 function _utf8Slice(buf, start, end) {

filename: tests/node_compat/config.jsonc
patch: @@ -27,7 +27,6 @@
       "test-buffer-includes.js",
       "test-buffer-indexof.js",
       "test-buffer-tostring-range.js",
-      "test-buffer-write.js",
       "test-child-process-exec-abortcontroller-promisified.js",
       "test-child-process-exec-encoding.js",
       "test-child-process-exec-maxbuf.js",

filename: tests/node_compat/test/parallel/test-buffer-write.js
patch: @@ -2,7 +2,7 @@
 // deno-lint-ignore-file
 
 // Copyright Joyent and Node contributors. All rights reserved. MIT license.
-// Taken from Node 20.11.1
+// Taken from Node 23.9.0
 // This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
 
 'use strict';
@@ -113,3 +113,31 @@ assert.strictEqual(Buffer.alloc(4)
   assert.strictEqual(buf.write('ыы', 1, 'utf16le'), 4);
   assert.deepStrictEqual([...buf], [0, 0x4b, 0x04, 0x4b, 0x04, 0, 0, 0]);
 }
+
+{
+  const buf = Buffer.alloc(1);
+  assert.strictEqual(buf.write('ww'), 1);
+  assert.strictEqual(buf.toString(), 'w');
+}
+
+assert.throws(() => {
+  const buf = Buffer.alloc(1);
+  assert.strictEqual(buf.asciiWrite('ww', 0, -1));
+  assert.strictEqual(buf.latin1Write('ww', 0, -1));
+  assert.strictEqual(buf.utf8Write('ww', 0, -1));
+}, common.expectsError({
+  code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+}));
+
+
+assert.throws(() => {
+  Buffer.alloc(1).asciiWrite('ww', 0, 2);
+}, common.expectsError({
+  code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+}));
+
+assert.throws(() => {
+  Buffer.alloc(1).asciiWrite('ww', 1, 1);
+}, common.expectsError({
+  code: 'ERR_BUFFER_OUT_OF_BOUNDS',
+}));