|
| 1 | +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Ben Noordhuis <info@bnoordhuis.nl> |
| 3 | +Date: Sat, 18 Jan 2020 10:55:31 +0100 |
| 4 | +Subject: lib,src: switch Buffer::kMaxLength to size_t |
| 5 | +MIME-Version: 1.0 |
| 6 | +Content-Type: text/plain; charset=UTF-8 |
| 7 | +Content-Transfer-Encoding: 8bit |
| 8 | + |
| 9 | +Change the type of `Buffer::kMaxLength` to size_t because upcoming |
| 10 | +changes in V8 will allow typed arrays > 2 GB on 64 bits platforms. |
| 11 | + |
| 12 | +Not all platforms handle file reads and writes > 2 GB though so keep |
| 13 | +enforcing the 2 GB typed array limit for I/O operations. |
| 14 | + |
| 15 | +Fixes: https://github.com/nodejs/node/issues/31399 |
| 16 | +Refs: https://github.com/libuv/libuv/pull/1501 |
| 17 | + |
| 18 | +PR-URL: https://github.com/nodejs/node/pull/31406 |
| 19 | +Reviewed-By: Richard Lau <riclau@uk.ibm.com> |
| 20 | +Reviewed-By: David Carlier <devnexen@gmail.com> |
| 21 | +Reviewed-By: Colin Ihrig <cjihrig@gmail.com> |
| 22 | +Reviewed-By: Luigi Pinca <luigipinca@gmail.com> |
| 23 | +Reviewed-By: Anna Henningsen <anna@addaleax.net> |
| 24 | +Reviewed-By: Rich Trott <rtrott@gmail.com> |
| 25 | +Reviewed-By: Tobias Nießen <tniessen@tnie.de> |
| 26 | +Reviewed-By: Shelley Vohr <codebytere@gmail.com> |
| 27 | + |
| 28 | +diff --git a/lib/fs.js b/lib/fs.js |
| 29 | +index 4a19e3b6033711d8c77d1ac9ea7e0f2cd9742ce9..59a41fe62c68c05ab09ad280e4e9ecdb2ca23349 100644 |
| 30 | +--- a/lib/fs.js |
| 31 | ++++ b/lib/fs.js |
| 32 | +@@ -24,6 +24,10 @@ |
| 33 | + |
| 34 | + 'use strict'; |
| 35 | + |
| 36 | ++// Most platforms don't allow reads or writes >= 2 GB. |
| 37 | ++// See https://github.com/libuv/libuv/pull/1501. |
| 38 | ++const kIoMaxLength = 2 ** 31 - 1; |
| 39 | ++ |
| 40 | + const { |
| 41 | + Map, |
| 42 | + MathMax, |
| 43 | +@@ -52,7 +56,7 @@ const { |
| 44 | + const pathModule = require('path'); |
| 45 | + const { isArrayBufferView } = require('internal/util/types'); |
| 46 | + const binding = internalBinding('fs'); |
| 47 | +-const { Buffer, kMaxLength } = require('buffer'); |
| 48 | ++const { Buffer } = require('buffer'); |
| 49 | + const { |
| 50 | + codes: { |
| 51 | + ERR_FS_FILE_TOO_LARGE, |
| 52 | +@@ -274,7 +278,7 @@ function readFileAfterStat(err, stats) { |
| 53 | + |
| 54 | + const size = context.size = isFileType(stats, S_IFREG) ? stats[8] : 0; |
| 55 | + |
| 56 | +- if (size > kMaxLength) { |
| 57 | ++ if (size > kIoMaxLength) { |
| 58 | + err = new ERR_FS_FILE_TOO_LARGE(size); |
| 59 | + return context.close(err); |
| 60 | + } |
| 61 | +@@ -331,7 +335,7 @@ function tryCreateBuffer(size, fd, isUserFd) { |
| 62 | + let threw = true; |
| 63 | + let buffer; |
| 64 | + try { |
| 65 | +- if (size > kMaxLength) { |
| 66 | ++ if (size > kIoMaxLength) { |
| 67 | + throw new ERR_FS_FILE_TOO_LARGE(size); |
| 68 | + } |
| 69 | + buffer = Buffer.allocUnsafe(size); |
| 70 | +diff --git a/lib/internal/errors.js b/lib/internal/errors.js |
| 71 | +index 1e987cefb156df8e7a494bcb80547ae8e0ea649f..567d82c7bd12a7233481d80042d331afd7471674 100644 |
| 72 | +--- a/lib/internal/errors.js |
| 73 | ++++ b/lib/internal/errors.js |
| 74 | +@@ -822,9 +822,7 @@ E('ERR_FALSY_VALUE_REJECTION', function(reason) { |
| 75 | + this.reason = reason; |
| 76 | + return 'Promise was rejected with falsy value'; |
| 77 | + }, Error); |
| 78 | +-E('ERR_FS_FILE_TOO_LARGE', 'File size (%s) is greater than possible Buffer: ' + |
| 79 | +- `${kMaxLength} bytes`, |
| 80 | +- RangeError); |
| 81 | ++E('ERR_FS_FILE_TOO_LARGE', 'File size (%s) is greater than 2 GB', RangeError); |
| 82 | + E('ERR_FS_INVALID_SYMLINK_TYPE', |
| 83 | + 'Symlink type must be one of "dir", "file", or "junction". Received "%s"', |
| 84 | + Error); // Switch to TypeError. The current implementation does not seem right |
| 85 | +diff --git a/lib/internal/fs/promises.js b/lib/internal/fs/promises.js |
| 86 | +index d653724474f314cd1c6bebe0a2d9285439d54928..98335fdc1027409a2f17ae50fba378f5d78b2cab 100644 |
| 87 | +--- a/lib/internal/fs/promises.js |
| 88 | ++++ b/lib/internal/fs/promises.js |
| 89 | +@@ -1,5 +1,9 @@ |
| 90 | + 'use strict'; |
| 91 | + |
| 92 | ++// Most platforms don't allow reads or writes >= 2 GB. |
| 93 | ++// See https://github.com/libuv/libuv/pull/1501. |
| 94 | ++const kIoMaxLength = 2 ** 31 - 1; |
| 95 | ++ |
| 96 | + const { |
| 97 | + MathMax, |
| 98 | + MathMin, |
| 99 | +@@ -15,7 +19,7 @@ const { |
| 100 | + S_IFREG |
| 101 | + } = internalBinding('constants').fs; |
| 102 | + const binding = internalBinding('fs'); |
| 103 | +-const { Buffer, kMaxLength } = require('buffer'); |
| 104 | ++const { Buffer } = require('buffer'); |
| 105 | + const { |
| 106 | + ERR_FS_FILE_TOO_LARGE, |
| 107 | + ERR_INVALID_ARG_TYPE, |
| 108 | +@@ -166,7 +170,7 @@ async function readFileHandle(filehandle, options) { |
| 109 | + size = 0; |
| 110 | + } |
| 111 | + |
| 112 | +- if (size > kMaxLength) |
| 113 | ++ if (size > kIoMaxLength) |
| 114 | + throw new ERR_FS_FILE_TOO_LARGE(size); |
| 115 | + |
| 116 | + const chunks = []; |
| 117 | +diff --git a/src/node_buffer.cc b/src/node_buffer.cc |
| 118 | +index 59baa45413d500272d0e293ab06bfe4d24e5e0cb..4d1951b740240bff231b7f4c855beb5b73d076af 100644 |
| 119 | +--- a/src/node_buffer.cc |
| 120 | ++++ b/src/node_buffer.cc |
| 121 | +@@ -62,6 +62,7 @@ using v8::Local; |
| 122 | + using v8::Maybe; |
| 123 | + using v8::MaybeLocal; |
| 124 | + using v8::Nothing; |
| 125 | ++using v8::Number; |
| 126 | + using v8::Object; |
| 127 | + using v8::String; |
| 128 | + using v8::Uint32; |
| 129 | +@@ -1161,7 +1162,7 @@ void Initialize(Local<Object> target, |
| 130 | + |
| 131 | + target->Set(env->context(), |
| 132 | + FIXED_ONE_BYTE_STRING(env->isolate(), "kMaxLength"), |
| 133 | +- Integer::NewFromUnsigned(env->isolate(), kMaxLength)).Check(); |
| 134 | ++ Number::New(env->isolate(), kMaxLength)).Check(); |
| 135 | + |
| 136 | + target->Set(env->context(), |
| 137 | + FIXED_ONE_BYTE_STRING(env->isolate(), "kStringMaxLength"), |
| 138 | +diff --git a/src/node_buffer.h b/src/node_buffer.h |
| 139 | +index 11010017ce0df8367b1992bd9df57117ff50454d..606a6f5caa3b11b6d2a9068ed2fd65800530a5eb 100644 |
| 140 | +--- a/src/node_buffer.h |
| 141 | ++++ b/src/node_buffer.h |
| 142 | +@@ -29,7 +29,7 @@ namespace node { |
| 143 | + |
| 144 | + namespace Buffer { |
| 145 | + |
| 146 | +-static const unsigned int kMaxLength = v8::TypedArray::kMaxLength; |
| 147 | ++static const size_t kMaxLength = v8::TypedArray::kMaxLength; |
| 148 | + |
| 149 | + typedef void (*FreeCallback)(char* data, void* hint); |
| 150 | + |
| 151 | +diff --git a/test/parallel/test-fs-util-validateoffsetlengthwrite.js b/test/parallel/test-fs-util-validateoffsetlengthwrite.js |
| 152 | +index be6d8acea77efa5adc82a6bcaaa192167b510fb0..e2c583749d041d76da630bbbf6b46ac490076c56 100644 |
| 153 | +--- a/test/parallel/test-fs-util-validateoffsetlengthwrite.js |
| 154 | ++++ b/test/parallel/test-fs-util-validateoffsetlengthwrite.js |
| 155 | +@@ -4,7 +4,10 @@ |
| 156 | + require('../common'); |
| 157 | + const assert = require('assert'); |
| 158 | + const { validateOffsetLengthWrite } = require('internal/fs/utils'); |
| 159 | +-const { kMaxLength } = require('buffer'); |
| 160 | ++ |
| 161 | ++// Most platforms don't allow reads or writes >= 2 GB. |
| 162 | ++// See https://github.com/libuv/libuv/pull/1501. |
| 163 | ++const kIoMaxLength = 2 ** 31 - 1; |
| 164 | + |
| 165 | + // RangeError when offset > byteLength |
| 166 | + { |
| 167 | +@@ -22,27 +25,27 @@ const { kMaxLength } = require('buffer'); |
| 168 | + ); |
| 169 | + } |
| 170 | + |
| 171 | +-// RangeError when byteLength > kMaxLength, and length > kMaxLength - offset . |
| 172 | ++// RangeError when byteLength > kIoMaxLength, and length > kIoMaxLength - offset . |
| 173 | + { |
| 174 | +- const offset = kMaxLength; |
| 175 | ++ const offset = kIoMaxLength; |
| 176 | + const length = 100; |
| 177 | +- const byteLength = kMaxLength + 1; |
| 178 | ++ const byteLength = kIoMaxLength + 1; |
| 179 | + assert.throws( |
| 180 | + () => validateOffsetLengthWrite(offset, length, byteLength), |
| 181 | + { |
| 182 | + code: 'ERR_OUT_OF_RANGE', |
| 183 | + name: 'RangeError', |
| 184 | + message: 'The value of "length" is out of range. ' + |
| 185 | +- `It must be <= ${kMaxLength - offset}. Received ${length}` |
| 186 | ++ `It must be <= ${kIoMaxLength - offset}. Received ${length}` |
| 187 | + } |
| 188 | + ); |
| 189 | + } |
| 190 | + |
| 191 | +-// RangeError when byteLength < kMaxLength, and length > byteLength - offset . |
| 192 | ++// RangeError when byteLength < kIoMaxLength, and length > byteLength - offset. |
| 193 | + { |
| 194 | +- const offset = kMaxLength - 150; |
| 195 | ++ const offset = kIoMaxLength - 150; |
| 196 | + const length = 200; |
| 197 | +- const byteLength = kMaxLength - 100; |
| 198 | ++ const byteLength = kIoMaxLength - 100; |
| 199 | + assert.throws( |
| 200 | + () => validateOffsetLengthWrite(offset, length, byteLength), |
| 201 | + { |
0 commit comments