From 9d9fc08368d6224a37a698d2a453f8ec2db74f7d Mon Sep 17 00:00:00 2001 From: Divyanshu singh Date: Thu, 5 Feb 2026 20:40:07 +0530 Subject: [PATCH 1/2] fix: prevent tableFromIPC from hanging on corrupted files --- src/ipc/message.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/ipc/message.ts b/src/ipc/message.ts index 3dc86252..6bd3b644 100644 --- a/src/ipc/message.ts +++ b/src/ipc/message.ts @@ -29,6 +29,20 @@ import { ArrowJSON, ArrowJSONLike, ITERATOR_DONE, FileHandle } from '../io/inter /** @ignore */ const invalidMessageMetadata = (expected: number, actual: number) => `Expected to read ${expected} metadata bytes, but only read ${actual}.`; /** @ignore */ const invalidMessageBodyLength = (expected: number, actual: number) => `Expected to read ${expected} bytes for message body, but only read ${actual}.`; +/** + * Maximum allowed metadata length (256 MB). This is a safeguard against corrupted + * files that could cause the reader to hang or consume excessive memory. + * @ignore + */ +const MAX_METADATA_LENGTH = 256 * 1024 * 1024; + +/** + * Maximum allowed message body length (2 GB). This is a safeguard against corrupted + * files that could cause the reader to hang or consume excessive memory. + * @ignore + */ +const MAX_BODY_LENGTH = 2 * 1024 * 1024 * 1024; + /** @ignore */ export class MessageReader implements IterableIterator { protected source: ByteStream; @@ -59,6 +73,9 @@ export class MessageReader implements IterableIterator { } public readMessageBody(bodyLength: number): Uint8Array { if (bodyLength <= 0) { return new Uint8Array(0); } + if (bodyLength > MAX_BODY_LENGTH) { + throw new Error(`Message body length ${bodyLength} exceeds maximum allowed size of ${MAX_BODY_LENGTH} bytes. The file may be corrupted.`); + } const buf = toUint8Array(this.source.read(bodyLength)); if (buf.byteLength < bodyLength) { throw new Error(invalidMessageBodyLength(bodyLength, buf.byteLength)); @@ -81,6 +98,10 @@ export class MessageReader implements IterableIterator { const buf = this.source.read(PADDING); const bb = buf && new ByteBuffer(buf); const len = bb?.readInt32(0) || 0; + // Guard against corrupted files with unreasonable metadata lengths + if (len < 0 || len > MAX_METADATA_LENGTH) { + throw new Error(`Invalid metadata length ${len}. The file may be corrupted.`); + } return { done: len === 0, value: len }; } protected readMetadata(metadataLength: number): IteratorResult { @@ -128,6 +149,9 @@ export class AsyncMessageReader implements AsyncIterableIterator { } public async readMessageBody(bodyLength: number): Promise { if (bodyLength <= 0) { return new Uint8Array(0); } + if (bodyLength > MAX_BODY_LENGTH) { + throw new Error(`Message body length ${bodyLength} exceeds maximum allowed size of ${MAX_BODY_LENGTH} bytes. The file may be corrupted.`); + } const buf = toUint8Array(await this.source.read(bodyLength)); if (buf.byteLength < bodyLength) { throw new Error(invalidMessageBodyLength(bodyLength, buf.byteLength)); @@ -150,6 +174,10 @@ export class AsyncMessageReader implements AsyncIterableIterator { const buf = await this.source.read(PADDING); const bb = buf && new ByteBuffer(buf); const len = bb?.readInt32(0) || 0; + // Guard against corrupted files with unreasonable metadata lengths + if (len < 0 || len > MAX_METADATA_LENGTH) { + throw new Error(`Invalid metadata length ${len}. The file may be corrupted.`); + } return { done: len === 0, value: len }; } protected async readMetadata(metadataLength: number): Promise> { From 9606995e59bd633fb9be71a4d14c957744ea00f3 Mon Sep 17 00:00:00 2001 From: Divyanshu singh Date: Fri, 6 Feb 2026 20:56:54 +0530 Subject: [PATCH 2/2] fix: revert size limits that broke IPC reading --- src/ipc/message.ts | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/ipc/message.ts b/src/ipc/message.ts index 6bd3b644..3dc86252 100644 --- a/src/ipc/message.ts +++ b/src/ipc/message.ts @@ -29,20 +29,6 @@ import { ArrowJSON, ArrowJSONLike, ITERATOR_DONE, FileHandle } from '../io/inter /** @ignore */ const invalidMessageMetadata = (expected: number, actual: number) => `Expected to read ${expected} metadata bytes, but only read ${actual}.`; /** @ignore */ const invalidMessageBodyLength = (expected: number, actual: number) => `Expected to read ${expected} bytes for message body, but only read ${actual}.`; -/** - * Maximum allowed metadata length (256 MB). This is a safeguard against corrupted - * files that could cause the reader to hang or consume excessive memory. - * @ignore - */ -const MAX_METADATA_LENGTH = 256 * 1024 * 1024; - -/** - * Maximum allowed message body length (2 GB). This is a safeguard against corrupted - * files that could cause the reader to hang or consume excessive memory. - * @ignore - */ -const MAX_BODY_LENGTH = 2 * 1024 * 1024 * 1024; - /** @ignore */ export class MessageReader implements IterableIterator { protected source: ByteStream; @@ -73,9 +59,6 @@ export class MessageReader implements IterableIterator { } public readMessageBody(bodyLength: number): Uint8Array { if (bodyLength <= 0) { return new Uint8Array(0); } - if (bodyLength > MAX_BODY_LENGTH) { - throw new Error(`Message body length ${bodyLength} exceeds maximum allowed size of ${MAX_BODY_LENGTH} bytes. The file may be corrupted.`); - } const buf = toUint8Array(this.source.read(bodyLength)); if (buf.byteLength < bodyLength) { throw new Error(invalidMessageBodyLength(bodyLength, buf.byteLength)); @@ -98,10 +81,6 @@ export class MessageReader implements IterableIterator { const buf = this.source.read(PADDING); const bb = buf && new ByteBuffer(buf); const len = bb?.readInt32(0) || 0; - // Guard against corrupted files with unreasonable metadata lengths - if (len < 0 || len > MAX_METADATA_LENGTH) { - throw new Error(`Invalid metadata length ${len}. The file may be corrupted.`); - } return { done: len === 0, value: len }; } protected readMetadata(metadataLength: number): IteratorResult { @@ -149,9 +128,6 @@ export class AsyncMessageReader implements AsyncIterableIterator { } public async readMessageBody(bodyLength: number): Promise { if (bodyLength <= 0) { return new Uint8Array(0); } - if (bodyLength > MAX_BODY_LENGTH) { - throw new Error(`Message body length ${bodyLength} exceeds maximum allowed size of ${MAX_BODY_LENGTH} bytes. The file may be corrupted.`); - } const buf = toUint8Array(await this.source.read(bodyLength)); if (buf.byteLength < bodyLength) { throw new Error(invalidMessageBodyLength(bodyLength, buf.byteLength)); @@ -174,10 +150,6 @@ export class AsyncMessageReader implements AsyncIterableIterator { const buf = await this.source.read(PADDING); const bb = buf && new ByteBuffer(buf); const len = bb?.readInt32(0) || 0; - // Guard against corrupted files with unreasonable metadata lengths - if (len < 0 || len > MAX_METADATA_LENGTH) { - throw new Error(`Invalid metadata length ${len}. The file may be corrupted.`); - } return { done: len === 0, value: len }; } protected async readMetadata(metadataLength: number): Promise> {