From 9d2aa9c3bd79aaed7646676050073f9308484a1b Mon Sep 17 00:00:00 2001 From: Durvesh Pilankar Date: Mon, 29 Jun 2026 21:31:41 -0700 Subject: [PATCH] Fix Blob.slice() for negative start and inverted ranges Blob.slice() handled a negative `end` (relative to the end of the blob) but not a negative `start`, so `blob.slice(-100)` produced a negative offset and an oversized blob instead of slicing the last 100 bytes. It also computed `size = end - start` without clamping, so calling `slice(start, end)` with `end` before `start` produced a negative size. Normalize a negative start relative to the blob size (matching the existing end handling) and clamp the resulting size to a minimum of 0, per the W3C Blob.slice() semantics. Add tests for negative start, negative end, and end-precedes-start. --- packages/react-native/Libraries/Blob/Blob.js | 8 ++++- .../Libraries/Blob/__tests__/Blob-test.js | 32 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/react-native/Libraries/Blob/Blob.js b/packages/react-native/Libraries/Blob/Blob.js index dc6939860f72..90a4e5800813 100644 --- a/packages/react-native/Libraries/Blob/Blob.js +++ b/packages/react-native/Libraries/Blob/Blob.js @@ -86,6 +86,11 @@ class Blob { let {offset, size} = this.data; if (typeof start === 'number') { + if (start < 0) { + // A negative start is relative to the end of the blob. + // $FlowFixMe[reassign-const] + start = Math.max(this.size + start, 0); + } if (start > size) { // $FlowFixMe[reassign-const] start = size; @@ -102,7 +107,8 @@ class Blob { // $FlowFixMe[reassign-const] end = this.size; } - size = end - start; + // Clamp to 0 so an end that precedes start yields an empty blob. + size = Math.max(end - start, 0); } } return BlobManager.createFromOptions({ diff --git a/packages/react-native/Libraries/Blob/__tests__/Blob-test.js b/packages/react-native/Libraries/Blob/__tests__/Blob-test.js index 36aee4969c74..3375467b4831 100644 --- a/packages/react-native/Libraries/Blob/__tests__/Blob-test.js +++ b/packages/react-native/Libraries/Blob/__tests__/Blob-test.js @@ -81,6 +81,38 @@ describe('Blob', function () { expect(sliceC.size).toBe(Math.min(blob.data.size, 34569) - 34543); }); + it('should slice a blob with a negative start', () => { + const blob = new Blob(); + blob.data.size = 34546; + + // A negative start is relative to the end of the blob. + const slice = blob.slice(-100); + + expect(slice.data.offset).toBe(34446); + expect(slice.size).toBe(100); + }); + + it('should slice a blob with a negative end', () => { + const blob = new Blob(); + blob.data.size = 34546; + + // A negative end is relative to the end of the blob. + const slice = blob.slice(0, -100); + + expect(slice.data.offset).toBe(0); + expect(slice.size).toBe(34446); + }); + + it('should return an empty slice when end precedes start', () => { + const blob = new Blob(); + blob.data.size = 34546; + + const slice = blob.slice(200, 100); + + expect(slice.data.offset).toBe(200); + expect(slice.size).toBe(0); + }); + it('should slice a blob and sets a contentType', () => { const blob = new Blob();