Skip to content

Commit f8111ad

Browse files
committed
feat: fromBase64 never returns pooled Uint8Arrays
1 parent 6034e9c commit f8111ad

2 files changed

Lines changed: 23 additions & 4 deletions

File tree

base64.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { assertEmptyRest } from './assert.js'
2-
import { typedView } from './array.js'
3-
import { assertU8, fromUint8, E_STRING } from './fallback/_utils.js'
2+
import { assertU8, fromUint8, fromBuffer, E_STRING } from './fallback/_utils.js'
43
import { isHermes } from './fallback/platform.js'
54
import { decodeLatin1, encodeLatin1 } from './fallback/latin1.js'
65
import * as js from './fallback/base64.js'
@@ -140,12 +139,14 @@ if (Uint8Array.fromBase64) {
140139
}
141140
} else if (haveNativeBuffer) {
142141
fromBase64impl = (str, isBase64url, padding, format) => {
143-
const arr = Buffer.from(str, 'base64')
142+
const size = Buffer.byteLength(str, 'base64')
143+
const arr = Buffer.allocUnsafeSlow(size) // non-pooled
144+
if (arr.base64Write(str) !== size) throw new SyntaxError(E_PADDING)
144145
// Rechecking by re-encoding is cheaper than regexes on Node.js
145146
const got = isBase64url ? maybeUnpad(str, padding === false) : maybePad(str, padding !== true)
146147
const valid = isBase64url ? arr.base64urlSlice(0, arr.length) : arr.base64Slice(0, arr.length)
147148
if (got !== valid) throw new SyntaxError(E_PADDING)
148-
return typedView(arr, format) // fully checked
149+
return fromBuffer(arr, format) // fully checked
149150
}
150151
} else if (shouldUseAtob) {
151152
// atob is faster than manual parsing on Hermes

tests/base64.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,21 @@ describe('fromBase64', () => {
171171
}
172172
})
173173
})
174+
175+
test('fromBase64 returns non-pooled Uint8Array instances', (t) => {
176+
for (let i = 0; i < 256; i++) {
177+
t.assert.strictEqual(fromBase64('A'.repeat(128 * 4)).buffer.byteLength, 128 * 3)
178+
}
179+
180+
for (let i = 0; i < 256; i++) {
181+
t.assert.strictEqual(fromBase64('A'.repeat(64 * 4)).buffer.byteLength, 64 * 3)
182+
}
183+
184+
for (let i = 0; i < 512; i++) {
185+
t.assert.strictEqual(fromBase64('A'.repeat(32 * 4)).buffer.byteLength, 32 * 3)
186+
}
187+
188+
for (let i = 0; i < 512; i++) {
189+
t.assert.strictEqual(fromBase64('').buffer.byteLength, 0)
190+
}
191+
})

0 commit comments

Comments
 (0)