@@ -414,10 +414,17 @@ export class Reader {
414414 readonly #data: Uint8Array ;
415415 #offset: number ;
416416
417- constructor ( data : BytesLike , allowLoose ?: boolean ) {
417+ #bytesRead: number ;
418+ #parent: null | Reader ;
419+ #maxInflation: number ;
420+
421+ constructor ( data : BytesLike , allowLoose ?: boolean , maxInflation ?: number ) {
418422 defineProperties < Reader > ( this , { allowLoose : ! ! allowLoose } ) ;
419423
420424 this . #data = getBytesCopy ( data ) ;
425+ this . #bytesRead = 0 ;
426+ this . #parent = null ;
427+ this . #maxInflation = ( maxInflation != null ) ? maxInflation : 1024 ;
421428
422429 this . #offset = 0 ;
423430 }
@@ -427,6 +434,21 @@ export class Reader {
427434 get consumed ( ) : number { return this . #offset; }
428435 get bytes ( ) : Uint8Array { return new Uint8Array ( this . #data) ; }
429436
437+ #incrementBytesRead( count : number ) : void {
438+ if ( this . #parent) { return this . #parent. #incrementBytesRead( count ) ; }
439+
440+ this . #bytesRead += count ;
441+
442+ // Check for excessive inflation (see: #4537)
443+ assert ( this . #maxInflation < 1 || this . #bytesRead <= this . #maxInflation * this . dataLength , `compressed ABI data exceeds inflation ratio of ${ this . #maxInflation } ( see: https:/\/github.com/ethers-io/ethers.js/issues/4537 )` , "BUFFER_OVERRUN" , {
444+ buffer : getBytesCopy ( this . #data) , offset : this . #offset,
445+ length : count , info : {
446+ bytesRead : this . #bytesRead,
447+ dataLength : this . dataLength
448+ }
449+ } ) ;
450+ }
451+
430452 #peekBytes( offset : number , length : number , loose ?: boolean ) : Uint8Array {
431453 let alignedLength = Math . ceil ( length / WordSize ) * WordSize ;
432454 if ( this . #offset + alignedLength > this . #data. length ) {
@@ -445,12 +467,15 @@ export class Reader {
445467
446468 // Create a sub-reader with the same underlying data, but offset
447469 subReader ( offset : number ) : Reader {
448- return new Reader ( this . #data. slice ( this . #offset + offset ) , this . allowLoose ) ;
470+ const reader = new Reader ( this . #data. slice ( this . #offset + offset ) , this . allowLoose , this . #maxInflation) ;
471+ reader . #parent = this ;
472+ return reader ;
449473 }
450474
451475 // Read bytes
452476 readBytes ( length : number , loose ?: boolean ) : Uint8Array {
453477 let bytes = this . #peekBytes( 0 , length , ! ! loose ) ;
478+ this . #incrementBytesRead( length ) ;
454479 this . #offset += bytes . length ;
455480 // @TODO : Make sure the length..end bytes are all 0?
456481 return bytes . slice ( 0 , length ) ;
0 commit comments