Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/ffi/data.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ Maybe<size_t> GetValidatedSize(Environment* env,
return Nothing<size_t>();
}

if (length > static_cast<double>(std::numeric_limits<size_t>::max())) {
// Values beyond Number.MAX_SAFE_INTEGER may already have been rounded
// by the caller. On 32-bit platforms SIZE_MAX is the tighter bound.
if (length > kMaxSafeJsInteger ||
length > static_cast<double>(std::numeric_limits<size_t>::max())) {
THROW_ERR_OUT_OF_RANGE(env, "The %s is too large", label);
return Nothing<size_t>();
}
Expand Down
24 changes: 22 additions & 2 deletions test/ffi/test-ffi-memory.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,15 +322,35 @@ test('ffi validates memory access arguments', () => {

assert.throws(() => ffi.toBuffer(maxPointer, 8), /pointer and length exceed the platform address range/);
assert.throws(() => ffi.toArrayBuffer(maxPointer, 8), /pointer and length exceed the platform address range/);
assert.throws(() => ffi.toBuffer(1n, bufferConstants.MAX_LENGTH + 1), { code: 'ERR_BUFFER_TOO_LARGE' });
assert.throws(() => ffi.toArrayBuffer(1n, bufferConstants.MAX_LENGTH + 1), { code: 'ERR_BUFFER_TOO_LARGE' });

// If MAX_LENGTH is Number.MAX_SAFE_INTEGER, MAX_LENGTH + 1 is an unsafe
// integer and is rejected before the buffer length is checked.
if (bufferConstants.MAX_LENGTH < Number.MAX_SAFE_INTEGER) {
assert.throws(() => ffi.toBuffer(1n, bufferConstants.MAX_LENGTH + 1), { code: 'ERR_BUFFER_TOO_LARGE' });
assert.throws(() => ffi.toArrayBuffer(1n, bufferConstants.MAX_LENGTH + 1), { code: 'ERR_BUFFER_TOO_LARGE' });
}

if (process.arch === 'ia32' || process.arch === 'arm') {
assert.throws(() => ffi.toBuffer(2n ** 32n, 0), /platform pointer range/);
}
}));
});

test('ffi rejects unsafe integers as an offset or length', () => {
withAllocations(common.mustCall((alloc) => {
const ptr = alloc(8);
const range = { code: 'ERR_OUT_OF_RANGE' };

// On 64-bit platforms SIZE_MAX rounds up to 2 ** 64 as a double.
for (const value of [Number.MAX_SAFE_INTEGER + 1, 2 ** 64]) {
assert.throws(() => ffi.getUint8(ptr, value), range);
assert.throws(() => ffi.setUint8(ptr, value, 42), range);
assert.throws(() => ffi.toBuffer(ptr, value), range);
assert.throws(() => ffi.toArrayBuffer(ptr, value), range);
}
}));
});

test('ffi memory helpers reject missing required arguments', () => {
const widths = ['Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32',
'Int64', 'Uint64', 'Float32', 'Float64'];
Expand Down
Loading