--- embed.fnc.orig	2007-12-18 10:47:07.000000000 +0000
+++ embed.fnc	2022-08-05 12:07:08.779389095 +0000
@@ -1396,7 +1396,8 @@ Es	|I32	|study_chunk	|NN struct RExC_sta
 				|NN regnode *last|NULLOK struct scan_data_t *data \
 				|I32 stopparen|NULLOK U8* recursed \
 				|NULLOK struct regnode_charclass_class *and_withp \
-				|U32 flags|U32 depth
+				|U32 flags|U32 depth|bool was_mutate_ok
+Es	|void	|rck_elide_nothing|NN regnode *node
 EsRn	|U32	|add_data	|NN struct RExC_state_t* state|U32 n|NN const char *s
 rs	|void	|re_croak2	|NN const char* pat1|NN const char* pat2|...
 Es	|I32	|regpposixcc	|NN struct RExC_state_t* state|I32 value
--- embed.h.orig	2007-12-18 10:47:07.000000000 +0000
+++ embed.h	2022-08-05 12:07:08.783389088 +0000
@@ -3648,6 +3648,7 @@
 #endif
 #if defined(PERL_IN_REGCOMP_C) || defined(PERL_DECL_PROT)
 #if defined(PERL_CORE) || defined(PERL_EXT)
+#define rck_elide_nothing(a)	S_rck_elide_nothing(aTHX_ a)
 #define reg(a,b,c,d)		S_reg(aTHX_ a,b,c,d)
 #define reganode(a,b,c)		S_reganode(aTHX_ a,b,c)
 #define regatom(a,b,c)		S_regatom(aTHX_ a,b,c)
@@ -3673,7 +3674,7 @@
 #define cl_init_zero		S_cl_init_zero
 #define cl_and			S_cl_and
 #define cl_or			S_cl_or
-#define study_chunk(a,b,c,d,e,f,g,h,i,j,k)	S_study_chunk(aTHX_ a,b,c,d,e,f,g,h,i,j,k)
+#define study_chunk(a,b,c,d,e,f,g,h,i,j,k,l)	S_study_chunk(aTHX_ a,b,c,d,e,f,g,h,i,j,k,l)
 #define add_data		S_add_data
 #endif
 #ifdef PERL_CORE
--- proto.h.orig	2007-12-18 10:47:08.000000000 +0000
+++ proto.h	2022-08-05 12:07:08.783389088 +0000
@@ -3746,7 +3746,7 @@ STATIC void	S_cl_or(const struct RExC_st
 			__attribute__nonnull__(2)
 			__attribute__nonnull__(3);
 
-STATIC I32	S_study_chunk(pTHX_ struct RExC_state_t* state, regnode **scanp, I32 *minlenp, I32 *deltap, regnode *last, struct scan_data_t *data, I32 stopparen, U8* recursed, struct regnode_charclass_class *and_withp, U32 flags, U32 depth)
+STATIC I32	S_study_chunk(pTHX_ struct RExC_state_t* state, regnode **scanp, I32 *minlenp, I32 *deltap, regnode *last, struct scan_data_t *data, I32 stopparen, U8* recursed, struct regnode_charclass_class *and_withp, U32 flags, U32 depth, bool was_mutate_ok)
 			__attribute__nonnull__(pTHX_1)
 			__attribute__nonnull__(pTHX_2)
 			__attribute__nonnull__(pTHX_3)
@@ -3758,6 +3758,9 @@ STATIC U32	S_add_data(struct RExC_state_
 			__attribute__nonnull__(1)
 			__attribute__nonnull__(3);
 
+STATIC void	S_rck_elide_nothing(pTHX_ regnode *node)
+			__attribute__nonnull__(pTHX_1);
+
 STATIC void	S_re_croak2(pTHX_ const char* pat1, const char* pat2, ...)
 			__attribute__noreturn__
 			__attribute__nonnull__(pTHX_1)
--- regcomp.c.orig	2022-08-05 12:06:53.827415862 +0000
+++ regcomp.c	2022-08-05 12:31:06.072999376 +0000
@@ -2426,8 +2426,38 @@ typedef struct scan_frame {
     regnode *next;  /* next node to process when last is reached */
     struct scan_frame *prev; /*previous frame*/
     I32 stop; /* what stopparen do we use */
+    bool in_gosub;
 } scan_frame;
 
+/* Follow the next-chain of the current node and optimize away
+   all the NOTHINGs from it.
+ */
+STATIC void
+S_rck_elide_nothing(pTHX_ regnode *node)
+{
+    dVAR;
+
+    if (OP(node) != CURLYX) {
+        const int max = (reg_off_by_arg[OP(node)]
+                   ? I32_MAX
+                   /* I32 may be smaller than U16 on CRAYs! */
+                   : (I32_MAX < U16_MAX ? I32_MAX : U16_MAX));
+        int off = (reg_off_by_arg[OP(node)] ? ARG(node) : NEXT_OFF(node));
+        int noff;
+        regnode *n = node;
+
+        /* Skip NOTHING and LONGJMP. */
+        while ((n = regnext(n))
+               && ((PL_regkind[OP(n)] == NOTHING && (noff = NEXT_OFF(n)))
+                   || ((OP(n) == LONGJMP) && (noff = ARG(n))))
+               && off + noff < max)
+            off += noff;
+        if (reg_off_by_arg[OP(node)])
+            ARG(node) = off;
+        else
+            NEXT_OFF(node) = off;
+    }
+}
 
 #define SCAN_COMMIT(s, data, m) scan_commit(s, data, m, is_inf)
 
@@ -2467,7 +2497,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_
 			I32 stopparen,
 			U8* recursed,
 			struct regnode_charclass_class *and_withp,
-			U32 flags, U32 depth)
+			U32 flags, U32 depth, bool was_mutate_ok)
 			/* scanp: Start here (read-write). */
 			/* deltap: Write maxlen-minlen here. */
 			/* last: Stop before this one. */
@@ -2503,33 +2533,16 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_
 
   fake_study_recurse:
     while ( scan && OP(scan) != END && scan < last ){
+        bool mutate_ok = was_mutate_ok && !(frame && frame->in_gosub);
 	/* Peephole optimizer: */
 	DEBUG_STUDYDATA("Peep:", data,depth);
 	DEBUG_PEEP("Peep",scan,depth);
-        JOIN_EXACT(scan,&min,0);
+	if (mutate_ok)
+	    JOIN_EXACT(scan,&min,0);
 
 	/* Follow the next-chain of the current node and optimize
 	   away all the NOTHINGs from it.  */
-	if (OP(scan) != CURLYX) {
-	    const int max = (reg_off_by_arg[OP(scan)]
-		       ? I32_MAX
-		       /* I32 may be smaller than U16 on CRAYs! */
-		       : (I32_MAX < U16_MAX ? I32_MAX : U16_MAX));
-	    int off = (reg_off_by_arg[OP(scan)] ? ARG(scan) : NEXT_OFF(scan));
-	    int noff;
-	    regnode *n = scan;
-	
-	    /* Skip NOTHING and LONGJMP. */
-	    while ((n = regnext(n))
-		   && ((PL_regkind[OP(n)] == NOTHING && (noff = NEXT_OFF(n)))
-		       || ((OP(n) == LONGJMP) && (noff = ARG(n))))
-		   && off + noff < max)
-		off += noff;
-	    if (reg_off_by_arg[OP(scan)])
-		ARG(scan) = off;
-	    else
-		NEXT_OFF(scan) = off;
-	}
+	rck_elide_nothing(scan);
 
 
 
@@ -2583,7 +2596,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_
 		    /* we suppose the run is continuous, last=next...*/
 		    minnext = study_chunk(pRExC_state, &scan, minlenp, &deltanext,
 					  next, &data_fake,
-					  stopparen, recursed, NULL, f,depth+1);
+					  stopparen, recursed, NULL, f,depth+1, mutate_ok);
 		    if (min1 > minnext)
 			min1 = minnext;
 		    if (max1 < minnext + deltanext)
@@ -2644,7 +2657,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_
 		    }
 		}
 
-                if (PERL_ENABLE_TRIE_OPTIMISATION && OP( startbranch ) == BRANCH ) {
+                if (PERL_ENABLE_TRIE_OPTIMISATION && OP( startbranch ) == BRANCH && mutate_ok) {
 		/* demq.
 
 		   Assuming this was/is a branch we are dealing with: 'scan' now
@@ -2903,6 +2916,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_
 	        newframe->last = last;
 	        newframe->stop = stopparen;
 	        newframe->prev = frame;
+                newframe->in_gosub = ((frame && frame->in_gosub) || OP(scan) == GOSUB || OP(scan) == GOSTART);
 
 	        frame = newframe;
 	        scan =  start;
@@ -3114,7 +3128,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_
 		minnext = study_chunk(pRExC_state, &scan, minlenp, &deltanext, 
 		                      last, data, stopparen, recursed, NULL,
 				      (mincount == 0
-					? (f & ~SCF_DO_SUBSTR) : f),depth+1);
+					? (f & ~SCF_DO_SUBSTR) : f),depth+1, mutate_ok);
 
 		if (flags & SCF_DO_STCLASS)
 		    data->start_class = oclass;
@@ -3156,6 +3170,12 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_
 			  "Quantifier unexpected on zero-length expression");
 		}
 
+                if ( ( minnext > 0 && mincount >= I32_MAX / minnext )
+                    || min >= I32_MAX - minnext * mincount )
+                {
+                    FAIL("Regexp out of space");
+                }
+
 		min += minnext * mincount;
 		is_inf_internal |= ((maxcount == REG_INFTY
 				     && (minnext + deltanext) > 0)
@@ -3262,7 +3282,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_
 #endif
 			/* Optimize again: */
 			study_chunk(pRExC_state, &nxt1, minlenp, &deltanext, nxt,
-				    NULL, stopparen, recursed, NULL, 0,depth+1);
+				    NULL, stopparen, recursed, NULL, 0,depth+1, mutate_ok);
 		    }
 		    else
 			oscan->flags = 0;
@@ -3380,11 +3400,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_
 		if (data && (fl & SF_HAS_EVAL))
 		    data->flags |= SF_HAS_EVAL;
 	      optimize_curly_tail:
-		if (OP(oscan) != CURLYX) {
-		    while (PL_regkind[OP(next = regnext(oscan))] == NOTHING
-			   && NEXT_OFF(next))
-			NEXT_OFF(oscan) += NEXT_OFF(next);
-		}
+                rck_elide_nothing(oscan);
 		continue;
 	    default:			/* REF and CLUMP only? */
 		if (flags & SCF_DO_SUBSTR) {
@@ -3681,7 +3697,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_
                 next = regnext(scan);
                 nscan = NEXTOPER(NEXTOPER(scan));
                 minnext = study_chunk(pRExC_state, &nscan, minlenp, &deltanext, 
-                    last, &data_fake, stopparen, recursed, NULL, f, depth+1);
+                    last, &data_fake, stopparen, recursed, NULL, f, depth+1, mutate_ok);
                 if (scan->flags) {
                     if (deltanext) {
 			FAIL("Variable length lookbehind not implemented");
@@ -3756,7 +3772,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_
                 nscan = NEXTOPER(NEXTOPER(scan));
 
                 *minnextp = study_chunk(pRExC_state, &nscan, minnextp, &deltanext, 
-                    last, &data_fake, stopparen, recursed, NULL, f,depth+1);
+                    last, &data_fake, stopparen, recursed, NULL, f,depth+1, mutate_ok);
                 if (scan->flags) {
                     if (deltanext) {
 			FAIL("Variable length lookbehind not implemented");
@@ -3919,7 +3935,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_
                          */
                         minnext = study_chunk(pRExC_state, &scan, minlenp, 
                             &deltanext, (regnode *)nextbranch, &data_fake, 
-                            stopparen, recursed, NULL, f,depth+1);
+                            stopparen, recursed, NULL, f,depth+1, mutate_ok);
                     }
                     if (nextbranch && PL_regkind[OP(nextbranch)]==BRANCH)
                         nextbranch= regnext((regnode*)nextbranch);
@@ -4573,7 +4589,7 @@ reStudy:
         
 	minlen = study_chunk(pRExC_state, &first, &minlen, &fake, scan + RExC_size, /* Up to end */
             &data, -1, NULL, NULL,
-            SCF_DO_SUBSTR | SCF_WHILEM_VISITED_POS | stclass_flag,0);
+            SCF_DO_SUBSTR | SCF_WHILEM_VISITED_POS | stclass_flag,0,TRUE);
 
 	
         CHECK_RESTUDY_GOTO;
@@ -4751,7 +4767,7 @@ reStudy:
 
         
 	minlen = study_chunk(pRExC_state, &scan, &minlen, &fake, scan + RExC_size,
-	    &data, -1, NULL, NULL, SCF_DO_STCLASS_AND|SCF_WHILEM_VISITED_POS,0);
+	    &data, -1, NULL, NULL, SCF_DO_STCLASS_AND|SCF_WHILEM_VISITED_POS,0,TRUE);
         
         CHECK_RESTUDY_GOTO;
 
