@@ -48,6 +48,10 @@ use std::{
4848} ;
4949use vtable:: JsStringVTable ;
5050
51+ /// Maximum string length allowed (u32::MAX).
52+ /// This prevents OOM crashes from exponential string growth.
53+ pub const MAX_STRING_LENGTH : usize = 4_294_967_295 ;
54+
5155fn alloc_overflow ( ) -> ! {
5256 panic ! ( "detected overflow during string allocation" )
5357}
@@ -628,23 +632,33 @@ impl JsString {
628632 }
629633
630634 /// Creates a new [`JsString`] from the concatenation of `x` and `y`.
635+ ///
636+ /// # Errors
637+ ///
638+ /// Returns an error if the resulting string would exceed [`MAX_STRING_LENGTH`].
631639 #[ inline]
632- #[ must_use]
633- pub fn concat ( x : JsStr < ' _ > , y : JsStr < ' _ > ) -> Self {
640+ pub fn concat ( x : JsStr < ' _ > , y : JsStr < ' _ > ) -> Result < Self , & ' static str > {
634641 Self :: concat_array ( & [ x, y] )
635642 }
636643
637644 /// Creates a new [`JsString`] from the concatenation of every element of
638645 /// `strings`.
646+ ///
647+ /// # Errors
648+ ///
649+ /// Returns an error if the resulting string would exceed [`MAX_STRING_LENGTH`].
639650 #[ inline]
640- #[ must_use]
641- pub fn concat_array ( strings : & [ JsStr < ' _ > ] ) -> Self {
651+ pub fn concat_array ( strings : & [ JsStr < ' _ > ] ) -> Result < Self , & ' static str > {
642652 let mut latin1_encoding = true ;
643653 let mut full_count = 0usize ;
644654 for string in strings {
645655 let Some ( sum) = full_count. checked_add ( string. len ( ) ) else {
646- alloc_overflow ( )
656+ return Err ( "Invalid string length" ) ;
647657 } ;
658+ // Check if the resulting string would exceed the maximum length
659+ if sum > MAX_STRING_LENGTH {
660+ return Err ( "Invalid string length" ) ;
661+ }
648662 if !string. is_latin1 ( ) {
649663 latin1_encoding = false ;
650664 }
@@ -707,7 +721,7 @@ impl JsString {
707721 Self { ptr : ptr. cast ( ) }
708722 } ;
709723
710- StaticJsStrings :: get_string ( & string. as_str ( ) ) . unwrap_or ( string)
724+ Ok ( StaticJsStrings :: get_string ( & string. as_str ( ) ) . unwrap_or ( string) )
711725 }
712726
713727 /// Creates a new [`JsString`] from `data`, without checking if the string is in the interner.
@@ -853,13 +867,15 @@ impl From<&[JsString]> for JsString {
853867 #[ inline]
854868 fn from ( value : & [ JsString ] ) -> Self {
855869 Self :: concat_array ( & value. iter ( ) . map ( Self :: as_str) . collect :: < Vec < _ > > ( ) [ ..] )
870+ . expect ( "string concatenation overflow" )
856871 }
857872}
858873
859874impl < const N : usize > From < & [ JsString ; N ] > for JsString {
860875 #[ inline]
861876 fn from ( value : & [ JsString ; N ] ) -> Self {
862877 Self :: concat_array ( & value. iter ( ) . map ( Self :: as_str) . collect :: < Vec < _ > > ( ) [ ..] )
878+ . expect ( "string concatenation overflow" )
863879 }
864880}
865881
0 commit comments