@@ -100,6 +100,8 @@ const {
100
100
inspect : utilInspect ,
101
101
} = require ( 'internal/util/inspect' ) ;
102
102
103
+ const assert = require ( 'internal/assert' ) ;
104
+
103
105
const {
104
106
codes : {
105
107
ERR_BUFFER_OUT_OF_BOUNDS ,
@@ -205,12 +207,12 @@ function toInteger(n, defaultVal) {
205
207
return defaultVal ;
206
208
}
207
209
210
+
208
211
function copyImpl ( source , target , targetStart , sourceStart , sourceEnd ) {
209
212
if ( ! ArrayBufferIsView ( source ) )
210
213
throw new ERR_INVALID_ARG_TYPE ( 'source' , [ 'Buffer' , 'Uint8Array' ] , source ) ;
211
214
if ( ! ArrayBufferIsView ( target ) )
212
215
throw new ERR_INVALID_ARG_TYPE ( 'target' , [ 'Buffer' , 'Uint8Array' ] , target ) ;
213
- // Guaranteed real buffers
214
216
215
217
if ( targetStart === undefined ) {
216
218
targetStart = 0 ;
@@ -219,7 +221,7 @@ function copyImpl(source, target, targetStart, sourceStart, sourceEnd) {
219
221
if ( targetStart < 0 )
220
222
throw new ERR_OUT_OF_RANGE ( 'targetStart' , '>= 0' , targetStart ) ;
221
223
}
222
- // Guaranteed targetStart >= 0
224
+ // Guaranteed 0 <= targetStart
223
225
224
226
if ( sourceStart === undefined ) {
225
227
sourceStart = 0 ;
@@ -239,26 +241,43 @@ function copyImpl(source, target, targetStart, sourceStart, sourceEnd) {
239
241
}
240
242
// Guaranteed 0 <= sourceEnd
241
243
244
+ // Clamp sourceEnd to be inbounds of source buffer.
245
+ // This is expected behavior and not to throw.
246
+ sourceEnd = MathMin ( sourceEnd , source . byteLength ) ;
247
+
242
248
if ( targetStart >= target . byteLength || sourceStart >= sourceEnd )
243
249
return 0 ;
244
250
245
- // Guaranteed 0 <= sourceStart < sourceEnd (NO GUARANTEE <= source.byteLnegth)
246
- // Guaranteed 0 <= targetStart < target.byteLength here
251
+ // Assert source slice in bounds of source buffer.
252
+ // 0 <= sourceStart < sourceEnd <= source.byteLength
253
+ assert ( 0 <= sourceStart && sourceStart < sourceEnd && sourceEnd <= source . byteLength ) ;
254
+
255
+ // Assert target slice in bounds of target buffer.
256
+ // 0 <= targetStart < target.byteLength
257
+ assert ( 0 <= targetStart && targetStart < target . byteLength ) ;
258
+
259
+ // Truncate source so that its length doesn't exceed targets.
260
+ // This is the expected behavior, not to throw.
261
+ const copyLength = MathMin ( sourceEnd - sourceStart , target . byteLength - targetStart ) ;
262
+ sourceEnd = sourceStart + copyLength ;
247
263
248
- return _copyActual ( source , target , targetStart , sourceStart , sourceEnd ) ;
264
+ return _copyActual ( source , target , targetStart , sourceStart , sourceStart + copyLength ) ;
249
265
}
250
266
251
- // Assumes `source`, `target` are real buffers.
252
- // Assumes 0 <= sourceStart <= sourceEnd
253
- // Assumes 0 <= targetStart <= target.byteLength
254
- //
255
- // This function clamps sourceEnd such that the source subarray will not exceed the length
256
- // of the target subarray.
267
+ // Safely performs native copy from valid source slice to valid target slice.
268
+ // - The source slice is not clamped to fit into the target slice. If it won't fit, this throws.
269
+ // - If either the source or target slice are out of bounds, this throws.
257
270
function _copyActual ( source , target , targetStart , sourceStart , sourceEnd ) {
258
- sourceEnd = MathMin ( sourceEnd , source . byteLength ) ;
259
- const sourceLength = sourceEnd - sourceStart ;
260
- const targetLength = target . byteLength - targetStart ;
261
- const copyLength = MathMin ( sourceLength , targetLength ) ;
271
+ assert ( isUint8Array ( source ) && isUint8Array ( target ) ) ;
272
+ // Enforce: 0 <= sourceStart <= sourceEnd <= source.byteLength
273
+ assert ( 0 <= sourceStart && sourceStart <= sourceEnd && sourceEnd <= source . byteLength ) ;
274
+ // Enforce: 0 <= targetStart<= target.byteLength
275
+ assert ( 0 <= targetStart && targetStart <= target . byteLength ) ;
276
+
277
+ const copyLength = sourceEnd - sourceStart ;
278
+ const targetCapacity = target . byteLength - targetStart ;
279
+ assert ( copyLength <= targetCapacity ) ;
280
+
262
281
_copy ( source , target , targetStart , sourceStart , copyLength ) ;
263
282
return copyLength ;
264
283
}
@@ -607,8 +626,9 @@ Buffer.concat = function concat(list, length) {
607
626
throw new ERR_INVALID_ARG_TYPE (
608
627
`list[${ i } ]` , [ 'Buffer' , 'Uint8Array' ] , list [ i ] ) ;
609
628
}
610
- // (src, target, t_beg, s_beg, s_end)
611
- pos += _copyActual ( buf , buffer , pos , 0 , buf . length ) ;
629
+
630
+ const copyLength = MathMin ( buf . length , buffer . length - pos ) ;
631
+ pos += _copyActual ( buf , buffer , pos , 0 , copyLength ) ;
612
632
}
613
633
614
634
// Note: `length` is always equal to `buffer.length` at this point
0 commit comments