@@ -443,6 +443,12 @@ private void compileRangeRepeatNode(QuantifierNode qn, int targetLen, int emptyI
443443
444444 private static final int QUANTIFIER_EXPAND_LIMIT_SIZE = 50 ; // was 50
445445
446+ // MRI: regcomp.c IS_EXPAND_LIMIT_OK (since Ruby 4.0.8; 3.4.12 and 3.3.13)
447+ // prevent nested repeats from bypassing the limit and exhausting heap
448+ private static boolean isExpandLimitOK (int tlen , int n ) {
449+ return n <= 0 || tlen <= QUANTIFIER_EXPAND_LIMIT_SIZE / n ;
450+ }
451+
446452 private static boolean cknOn (int ckn ) {
447453 return ckn > 0 ;
448454 }
@@ -660,7 +666,7 @@ private int compileNonCECLengthQuantifierNode(QuantifierNode qn) {
660666 }
661667
662668 int len ;
663- if (infinite && (qn .lower <= 1 || tlen * qn .lower <= QUANTIFIER_EXPAND_LIMIT_SIZE )) {
669+ if (infinite && (qn .lower <= 1 || isExpandLimitOK ( tlen , qn .lower ) )) {
664670 if (qn .lower == 1 && tlen > QUANTIFIER_EXPAND_LIMIT_SIZE ) {
665671 len = OPSize .JUMP ;
666672 } else {
@@ -682,7 +688,7 @@ private int compileNonCECLengthQuantifierNode(QuantifierNode qn) {
682688 } else if (qn .upper == 0 && qn .isRefered ) { /* /(?<n>..){0}/ */
683689 len = OPSize .JUMP + tlen ;
684690 } else if (!infinite && qn .greedy &&
685- (qn .upper == 1 || (tlen + OPSize .PUSH ) * qn .upper <= QUANTIFIER_EXPAND_LIMIT_SIZE )) {
691+ (qn .upper == 1 || isExpandLimitOK (tlen + OPSize .PUSH , qn .upper ) )) {
686692 len = tlen * qn .lower ;
687693 len += (OPSize .PUSH + tlen ) * (qn .upper - qn .lower );
688694 } else if (!qn .greedy && qn .upper == 1 && qn .lower == 0 ) { /* '??' */
@@ -728,7 +734,7 @@ protected void compileNonCECQuantifierNode(QuantifierNode qn) {
728734 } else {
729735 modTLen = tlen ;
730736 }
731- if (infinite && (qn .lower <= 1 || tlen * qn .lower <= QUANTIFIER_EXPAND_LIMIT_SIZE )) {
737+ if (infinite && (qn .lower <= 1 || isExpandLimitOK ( tlen , qn .lower ) )) {
732738 if (qn .lower == 1 && tlen > QUANTIFIER_EXPAND_LIMIT_SIZE ) {
733739 if (qn .greedy ) {
734740 if (qn .headExact != null ) {
@@ -772,7 +778,7 @@ protected void compileNonCECQuantifierNode(QuantifierNode qn) {
772778 addOpcodeRelAddr (OPCode .JUMP , tlen );
773779 compileTree (qn .target );
774780 } else if (!infinite && qn .greedy &&
775- (qn .upper == 1 || (tlen + OPSize .PUSH ) * qn .upper <= QUANTIFIER_EXPAND_LIMIT_SIZE )) {
781+ (qn .upper == 1 || isExpandLimitOK (tlen + OPSize .PUSH , qn .upper ) )) {
776782 int n = qn .upper - qn .lower ;
777783 compileTreeNTimes (qn .target , qn .lower );
778784
0 commit comments