@@ -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,12 +207,12 @@ 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 ) ;
211214 if ( ! ArrayBufferIsView ( target ) )
212215 throw new ERR_INVALID_ARG_TYPE ( 'target' , [ 'Buffer' , 'Uint8Array' ] , target ) ;
213- // Guaranteed real buffers
214216
215217 if ( targetStart === undefined ) {
216218 targetStart = 0 ;
@@ -219,7 +221,7 @@ function copyImpl(source, target, targetStart, sourceStart, sourceEnd) {
219221 if ( targetStart < 0 )
220222 throw new ERR_OUT_OF_RANGE ( 'targetStart' , '>= 0' , targetStart ) ;
221223 }
222- // Guaranteed targetStart >= 0
224+ // Guaranteed 0 <= targetStart
223225
224226 if ( sourceStart === undefined ) {
225227 sourceStart = 0 ;
@@ -239,26 +241,43 @@ function copyImpl(source, target, targetStart, sourceStart, sourceEnd) {
239241 }
240242 // Guaranteed 0 <= sourceEnd
241243
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+
242248 if ( targetStart >= target . byteLength || sourceStart >= sourceEnd )
243249 return 0 ;
244250
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 ;
247263
248- return _copyActual ( source , target , targetStart , sourceStart , sourceEnd ) ;
264+ return _copyActual ( source , target , targetStart , sourceStart , sourceStart + copyLength ) ;
249265}
250266
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.
257270function _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+
262281 _copy ( source , target , targetStart , sourceStart , copyLength ) ;
263282 return copyLength ;
264283}
@@ -607,8 +626,9 @@ Buffer.concat = function concat(list, length) {
607626 throw new ERR_INVALID_ARG_TYPE (
608627 `list[${ i } ]` , [ 'Buffer' , 'Uint8Array' ] , list [ i ] ) ;
609628 }
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 ) ;
612632 }
613633
614634 // Note: `length` is always equal to `buffer.length` at this point
0 commit comments