@@ -100,6 +100,8 @@ const {
100100 inspect : utilInspect ,
101101} = require ( 'internal/util/inspect' ) ;
102102
103+ const assert = require ( 'internal/assert' ) ;
104+
103105const {
104106 codes : {
105107 ERR_BUFFER_OUT_OF_BOUNDS ,
@@ -205,6 +207,7 @@ function toInteger(n, defaultVal) {
205207 return defaultVal ;
206208}
207209
210+
208211function copyImpl ( source , target , targetStart , sourceStart , sourceEnd ) {
209212 if ( ! ArrayBufferIsView ( source ) )
210213 throw new ERR_INVALID_ARG_TYPE ( 'source' , [ 'Buffer' , 'Uint8Array' ] , source ) ;
@@ -235,27 +238,45 @@ function copyImpl(source, target, targetStart, sourceStart, sourceEnd) {
235238 throw new ERR_OUT_OF_RANGE ( 'sourceEnd' , '>= 0' , sourceEnd ) ;
236239 }
237240
241+ // Clamp sourceEnd to be inbounds of source buffer.
242+ // This is expected behavior and not to throw.
243+ sourceEnd = MathMin ( sourceEnd , source . byteLength ) ;
244+
238245 if ( targetStart >= target . byteLength || sourceStart >= sourceEnd )
239246 return 0 ;
240247
241- return _copyActual ( source , target , targetStart , sourceStart , sourceEnd ) ;
242- }
243-
244- function _copyActual ( source , target , targetStart , sourceStart , sourceEnd ) {
245- if ( sourceEnd - sourceStart > target . byteLength - targetStart )
246- sourceEnd = sourceStart + target . byteLength - targetStart ;
248+ // Assert source slice in bounds of source buffer.
249+ // 0 <= sourceStart < sourceEnd <= source.byteLength
250+ assert ( 0 <= sourceStart && sourceStart < sourceEnd && sourceEnd <= source . byteLength ) ;
247251
248- let nb = sourceEnd - sourceStart ;
249- const sourceLen = source . byteLength - sourceStart ;
250- if ( nb > sourceLen )
251- nb = sourceLen ;
252+ // Assert target slice in bounds of target buffer.
253+ // 0 <= targetStart < target.byteLength
254+ assert ( 0 <= targetStart && targetStart < target . byteLength ) ;
252255
253- if ( nb <= 0 )
254- return 0 ;
256+ // Truncate source so that its length doesn't exceed targets.
257+ // This is the expected behavior, not to throw.
258+ const copyLength = MathMin ( sourceEnd - sourceStart , target . byteLength - targetStart ) ;
259+ sourceEnd = sourceStart + copyLength ;
255260
256- _copy ( source , target , targetStart , sourceStart , nb ) ;
261+ return _copyActual ( source , target , targetStart , sourceStart , sourceStart + copyLength ) ;
262+ }
257263
258- return nb ;
264+ // Safely performs native copy from valid source slice to valid target slice.
265+ // - The source slice is not clamped to fit into the target slice. If it won't fit, this throws.
266+ // - If either the source or target slice are out of bounds, this throws.
267+ function _copyActual ( source , target , targetStart , sourceStart , sourceEnd ) {
268+ assert ( isUint8Array ( source ) && isUint8Array ( target ) ) ;
269+ // Enforce: 0 <= sourceStart <= sourceEnd <= source.byteLength
270+ assert ( 0 <= sourceStart && sourceStart <= sourceEnd && sourceEnd <= source . byteLength ) ;
271+ // Enforce: 0 <= targetStart<= target.byteLength
272+ assert ( 0 <= targetStart && targetStart <= target . byteLength ) ;
273+
274+ const copyLength = sourceEnd - sourceStart ;
275+ const targetCapacity = target . byteLength - targetStart ;
276+ assert ( copyLength <= targetCapacity ) ;
277+
278+ _copy ( source , target , targetStart , sourceStart , copyLength ) ;
279+ return copyLength ;
259280}
260281
261282/**
@@ -602,7 +623,9 @@ Buffer.concat = function concat(list, length) {
602623 throw new ERR_INVALID_ARG_TYPE (
603624 `list[${ i } ]` , [ 'Buffer' , 'Uint8Array' ] , list [ i ] ) ;
604625 }
605- pos += _copyActual ( buf , buffer , pos , 0 , buf . length ) ;
626+
627+ const copyLength = MathMin ( buf . length , buffer . length - pos ) ;
628+ pos += _copyActual ( buf , buffer , pos , 0 , copyLength ) ;
606629 }
607630
608631 // Note: `length` is always equal to `buffer.length` at this point
0 commit comments