summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog36
-rw-r--r--debian/patches/794589-information-disclosure.patch30
-rw-r--r--debian/patches/Disable_JIT_on_sparc64.patch23
-rw-r--r--debian/patches/Fix-bad-compilation-for-patterns-like-1-1-with-forwa.patch145
-rw-r--r--debian/patches/Fix-bad-compile-for-groups-like-2-0-1999.patch209
-rw-r--r--debian/patches/Fix-buffer-overflow-for-named-recursive-back-referen.patch59
-rw-r--r--debian/patches/Fix-compile-time-loop-for-recursive-reference-within.patch86
-rw-r--r--debian/patches/Fix-compiler-crash-misbehaviour-for-zero-repeated-gr.patch175
-rw-r--r--debian/patches/series7
-rw-r--r--pcre_compile.c99
-rw-r--r--pcre_exec.c13
-rw-r--r--sljit/sljitConfigInternal.h6
-rw-r--r--testdata/testinput16
-rw-r--r--testdata/testinput114
-rw-r--r--testdata/testinput28
-rw-r--r--testdata/testoutput110
-rw-r--r--testdata/testoutput11-1639
-rw-r--r--testdata/testoutput11-3239
-rw-r--r--testdata/testoutput11-839
-rw-r--r--testdata/testoutput243
20 files changed, 1032 insertions, 44 deletions
diff --git a/debian/changelog b/debian/changelog
index 190252c..4343549 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,39 @@
+pcre3 (2:8.35-7.4) unstable; urgency=medium
+
+ * Non-maintainer upload.
+ * Fix copy-and-paste error in Disable_JIT_on_sparc64.patch.
+
+ -- John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> Mon, 02 Nov 2015 18:51:13 +0100
+
+pcre3 (2:8.35-7.3) unstable; urgency=medium
+
+ * Non-maintainer upload.
+ * Add Disable_JIT_on_sparc64.patch to disable JIT on sparc64. The patch
+ no_jit_x32_powerpcspe.patch to disable JIT on powerpcspe was already
+ added in 2:8.35-6 (Closes: #765079).
+
+ -- John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> Mon, 02 Nov 2015 15:13:16 +0100
+
+pcre3 (2:8.35-7.2) unstable; urgency=low
+
+ * Non-maintainer upload (with maintainer's permission).
+ * Add Fix-compiler-crash-misbehaviour-for-zero-repeated-gr.patch.
+ Fixes "PCRE Library Stack Overflow Vulnerability" (Upstream bug 1503)
+ * Add Fix-compile-time-loop-for-recursive-reference-within.patch.
+ Fixes "PCRE Call Stack Overflow Vulnerability" (Upstream bug 1515)
+ * Add 794589-information-disclosure.patch.
+ Fixes "pcre_exec does not fill offsets for certain regexps" leading to
+ information disclosure. (Closes: #794589)
+ * Add Fix-bad-compile-for-groups-like-2-0-1999.patch.
+ CVE-2015-2325: heap buffer overflow in compile_branch(). (Closes: #781795)
+ * Add Fix-bad-compilation-for-patterns-like-1-1-with-forwa.patch.
+ CVE-2015-2326: heap buffer overflow in pcre_compile2(). (Closes: #783285)
+ * Add Fix-buffer-overflow-for-named-recursive-back-referen.patch.
+ CVE-2015-3210: heap buffer overflow in pcre_compile2() /
+ compile_regex(). (Closes: #787433)
+
+ -- Salvatore Bonaccorso <carnil@debian.org> Fri, 11 Sep 2015 20:04:19 +0200
+
pcre3 (2:8.35-7.1) unstable; urgency=medium
* Rename libpcrecpp0 to libpcrecpp0v5. Addresses: #791236.
diff --git a/debian/patches/794589-information-disclosure.patch b/debian/patches/794589-information-disclosure.patch
new file mode 100644
index 0000000..b3aba7f
--- /dev/null
+++ b/debian/patches/794589-information-disclosure.patch
@@ -0,0 +1,30 @@
+Description: pcre_exec does not fill offsets for certain regexps
+Origin: upstream, http://vcs.pcre.org/pcre/code/trunk/pcre_exec.c?r1=1502&r2=1510
+Bug: https://bugs.exim.org/show_bug.cgi?id=1537
+Bug-Debian: https://bugs.debian.org/794589
+Forwarded: not-needed
+Last-Update: 2015-09-10
+Applied-Upstream: 8.37
+
+--- a/pcre_exec.c
++++ b/pcre_exec.c
+@@ -1467,7 +1467,18 @@ for (;;)
+ md->offset_vector[offset] =
+ md->offset_vector[md->offset_end - number];
+ md->offset_vector[offset+1] = (int)(eptr - md->start_subject);
+- if (offset_top <= offset) offset_top = offset + 2;
++
++ /* If this group is at or above the current highwater mark, ensure that
++ any groups between the current high water mark and this group are marked
++ unset and then update the high water mark. */
++
++ if (offset >= offset_top)
++ {
++ register int *iptr = md->offset_vector + offset_top;
++ register int *iend = md->offset_vector + offset;
++ while (iptr < iend) *iptr++ = -1;
++ offset_top = offset + 2;
++ }
+ }
+ ecode += 1 + IMM2_SIZE;
+ break;
diff --git a/debian/patches/Disable_JIT_on_sparc64.patch b/debian/patches/Disable_JIT_on_sparc64.patch
new file mode 100644
index 0000000..aacf883
--- /dev/null
+++ b/debian/patches/Disable_JIT_on_sparc64.patch
@@ -0,0 +1,23 @@
+Description: Disable JIT on sparc64 as it needs explicit porting
+ The test suite currently fails on sparc64 when the JIT is enabled
+ as the JIT has not been ported to sparc64 yet. Thus, disable JIT
+ until it has been explicitly ported to sparc64.
+ .
+
+Index: pcre3-8.35/sljit/sljitConfigInternal.h
+===================================================================
+--- pcre3-8.35.orig/sljit/sljitConfigInternal.h
++++ pcre3-8.35/sljit/sljitConfigInternal.h
+@@ -125,7 +125,11 @@
+ #elif defined(__mips64)
+ #define SLJIT_CONFIG_MIPS_64 1
+ #elif defined(__sparc__) || defined(__sparc)
+-#define SLJIT_CONFIG_SPARC_32 1
++# if defined(__arch64__)
++# define SLJIT_CONFIG_UNSUPPORTED 1
++# else
++# define SLJIT_CONFIG_SPARC_32 1
++# endif
+ #elif defined(__tilegx__)
+ #define SLJIT_CONFIG_TILEGX 1
+ #else
diff --git a/debian/patches/Fix-bad-compilation-for-patterns-like-1-1-with-forwa.patch b/debian/patches/Fix-bad-compilation-for-patterns-like-1-1-with-forwa.patch
new file mode 100644
index 0000000..ed5b5c1
--- /dev/null
+++ b/debian/patches/Fix-bad-compilation-for-patterns-like-1-1-with-forwa.patch
@@ -0,0 +1,145 @@
+Description: CVE-2015-2326: heap buffer overflow in pcre_compile2()
+ Fix bad compilation for patterns like /((?+1)(\1))/ with
+ forward reference subroutine and recursive back reference within the same
+ group.
+Origin: upstream, http://vcs.pcre.org/pcre?view=revision&revision=1529
+Bug: http://bugs.exim.org/show_bug.cgi?id=1592
+Bug-Debian: https://bugs.debian.org/783285
+Forwarded: not-needed
+Last-Update: 2015-09-10
+Applied-Upstream: 8.36
+
+--- a/pcre_compile.c
++++ b/pcre_compile.c
+@@ -8027,6 +8027,7 @@ int length;
+ unsigned int orig_bracount;
+ unsigned int max_bracount;
+ branch_chain bc;
++size_t save_hwm_offset;
+
+ /* If set, call the external function that checks for stack availability. */
+
+@@ -8044,6 +8045,8 @@ bc.current_branch = code;
+ firstchar = reqchar = 0;
+ firstcharflags = reqcharflags = REQ_UNSET;
+
++save_hwm_offset = cd->hwm - cd->start_workspace;
++
+ /* Accumulate the length for use in the pre-compile phase. Start with the
+ length of the BRA and KET and any extra bytes that are required at the
+ beginning. We accumulate in a local variable to save frequent testing of
+@@ -8246,7 +8249,7 @@ for (;;)
+ {
+ *code = OP_END;
+ adjust_recurse(start_bracket, 1 + LINK_SIZE,
+- (options & PCRE_UTF8) != 0, cd, cd->hwm - cd->start_workspace);
++ (options & PCRE_UTF8) != 0, cd, save_hwm_offset);
+ memmove(start_bracket + 1 + LINK_SIZE, start_bracket,
+ IN_UCHARS(code - start_bracket));
+ *start_bracket = OP_ONCE;
+--- a/testdata/testinput11
++++ b/testdata/testinput11
+@@ -134,4 +134,6 @@ is required for these tests. --/
+
+ /(((a\2)|(a*)\g<-1>))*a?/B
+
++/((?+1)(\1))/B
++
+ /-- End of testinput11 --/
+--- a/testdata/testinput2
++++ b/testdata/testinput2
+@@ -4066,4 +4066,6 @@ backtracking verbs. --/
+
+ "((?2){0,1999}())?"
+
++/((?+1)(\1))/BZ
++
+ /-- End of testinput2 --/
+--- a/testdata/testoutput11-16
++++ b/testdata/testoutput11-16
+@@ -733,4 +733,19 @@ Memory allocation (code space): 14
+ 41 End
+ ------------------------------------------------------------------
+
++/((?+1)(\1))/B
++------------------------------------------------------------------
++ 0 20 Bra
++ 2 16 Once
++ 4 12 CBra 1
++ 7 9 Recurse
++ 9 5 CBra 2
++ 12 \1
++ 14 5 Ket
++ 16 12 Ket
++ 18 16 Ket
++ 20 20 Ket
++ 22 End
++------------------------------------------------------------------
++
+ /-- End of testinput11 --/
+--- a/testdata/testoutput11-32
++++ b/testdata/testoutput11-32
+@@ -733,4 +733,19 @@ Memory allocation (code space): 28
+ 41 End
+ ------------------------------------------------------------------
+
++/((?+1)(\1))/B
++------------------------------------------------------------------
++ 0 20 Bra
++ 2 16 Once
++ 4 12 CBra 1
++ 7 9 Recurse
++ 9 5 CBra 2
++ 12 \1
++ 14 5 Ket
++ 16 12 Ket
++ 18 16 Ket
++ 20 20 Ket
++ 22 End
++------------------------------------------------------------------
++
+ /-- End of testinput11 --/
+--- a/testdata/testoutput11-8
++++ b/testdata/testoutput11-8
+@@ -733,4 +733,19 @@ Memory allocation (code space): 10
+ 60 End
+ ------------------------------------------------------------------
+
++/((?+1)(\1))/B
++------------------------------------------------------------------
++ 0 31 Bra
++ 3 25 Once
++ 6 19 CBra 1
++ 11 14 Recurse
++ 14 8 CBra 2
++ 19 \1
++ 22 8 Ket
++ 25 19 Ket
++ 28 25 Ket
++ 31 31 Ket
++ 34 End
++------------------------------------------------------------------
++
+ /-- End of testinput11 --/
+--- a/testdata/testoutput2
++++ b/testdata/testoutput2
+@@ -14175,4 +14175,19 @@ Failed: parentheses are too deeply neste
+
+ "((?2){0,1999}())?"
+
++/((?+1)(\1))/BZ
++------------------------------------------------------------------
++ Bra
++ Once
++ CBra 1
++ Recurse
++ CBra 2
++ \1
++ Ket
++ Ket
++ Ket
++ Ket
++ End
++------------------------------------------------------------------
++
+ /-- End of testinput2 --/
diff --git a/debian/patches/Fix-bad-compile-for-groups-like-2-0-1999.patch b/debian/patches/Fix-bad-compile-for-groups-like-2-0-1999.patch
new file mode 100644
index 0000000..f019be6
--- /dev/null
+++ b/debian/patches/Fix-bad-compile-for-groups-like-2-0-1999.patch
@@ -0,0 +1,209 @@
+Description: CVE-2015-2325: heap buffer overflow in compile_branch()
+ Fix bad compile for groups like "((?2){0,1999}())?".
+Origin: backport, http://vcs.pcre.org/pcre?view=revision&revision=1528
+Bug: http://bugs.exim.org/show_bug.cgi?id=1591
+Bug-Debian: https://bugs.debian.org/781795
+Forwarded: not-needed
+Last-Update: 2015-09-10
+Applied-Upstream: 8.37
+
+--- a/pcre_compile.c
++++ b/pcre_compile.c
+@@ -3933,14 +3933,14 @@ Arguments:
+ adjust the amount by which the group is to be moved
+ utf TRUE in UTF-8 / UTF-16 / UTF-32 mode
+ cd contains pointers to tables etc.
+- save_hwm the hwm forward reference pointer at the start of the group
++ save_hwm_offset the hwm forward reference offset at the start of the group
+
+ Returns: nothing
+ */
+
+ static void
+ adjust_recurse(pcre_uchar *group, int adjust, BOOL utf, compile_data *cd,
+- pcre_uchar *save_hwm)
++ size_t save_hwm_offset)
+ {
+ pcre_uchar *ptr = group;
+
+@@ -3952,7 +3952,8 @@ while ((ptr = (pcre_uchar *)find_recurse
+ /* See if this recursion is on the forward reference list. If so, adjust the
+ reference. */
+
+- for (hc = save_hwm; hc < cd->hwm; hc += LINK_SIZE)
++ for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm;
++ hc += LINK_SIZE)
+ {
+ offset = (int)GET(hc, 0);
+ if (cd->start_code + offset == ptr + 1)
+@@ -4397,7 +4398,7 @@ const pcre_uchar *tempptr;
+ const pcre_uchar *nestptr = NULL;
+ pcre_uchar *previous = NULL;
+ pcre_uchar *previous_callout = NULL;
+-pcre_uchar *save_hwm = NULL;
++size_t save_hwm_offset = 0;
+ pcre_uint8 classbits[32];
+
+ /* We can fish out the UTF-8 setting once and for all into a BOOL, but we
+@@ -5909,7 +5910,7 @@ for (;; ptr++)
+ if (repeat_max <= 1) /* Covers 0, 1, and unlimited */
+ {
+ *code = OP_END;
+- adjust_recurse(previous, 1, utf, cd, save_hwm);
++ adjust_recurse(previous, 1, utf, cd, save_hwm_offset);
+ memmove(previous + 1, previous, IN_UCHARS(len));
+ code++;
+ if (repeat_max == 0)
+@@ -5933,7 +5934,7 @@ for (;; ptr++)
+ {
+ int offset;
+ *code = OP_END;
+- adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, save_hwm);
++ adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, save_hwm_offset);
+ memmove(previous + 2 + LINK_SIZE, previous, IN_UCHARS(len));
+ code += 2 + LINK_SIZE;
+ *previous++ = OP_BRAZERO + repeat_type;
+@@ -5996,26 +5997,25 @@ for (;; ptr++)
+ for (i = 1; i < repeat_min; i++)
+ {
+ pcre_uchar *hc;
+- pcre_uchar *this_hwm = cd->hwm;
++ size_t this_hwm_offset = cd->hwm - cd->start_workspace;
+ memcpy(code, previous, IN_UCHARS(len));
+
+ while (cd->hwm > cd->start_workspace + cd->workspace_size -
+- WORK_SIZE_SAFETY_MARGIN - (this_hwm - save_hwm))
++ WORK_SIZE_SAFETY_MARGIN -
++ (this_hwm_offset - save_hwm_offset))
+ {
+- int save_offset = save_hwm - cd->start_workspace;
+- int this_offset = this_hwm - cd->start_workspace;
+ *errorcodeptr = expand_workspace(cd);
+ if (*errorcodeptr != 0) goto FAILED;
+- save_hwm = (pcre_uchar *)cd->start_workspace + save_offset;
+- this_hwm = (pcre_uchar *)cd->start_workspace + this_offset;
+ }
+
+- for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE)
++ for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset;
++ hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset;
++ hc += LINK_SIZE)
+ {
+ PUT(cd->hwm, 0, GET(hc, 0) + len);
+ cd->hwm += LINK_SIZE;
+ }
+- save_hwm = this_hwm;
++ save_hwm_offset = this_hwm_offset;
+ code += len;
+ }
+ }
+@@ -6060,7 +6060,7 @@ for (;; ptr++)
+ else for (i = repeat_max - 1; i >= 0; i--)
+ {
+ pcre_uchar *hc;
+- pcre_uchar *this_hwm = cd->hwm;
++ size_t this_hwm_offset = cd->hwm - cd->start_workspace;
+
+ *code++ = OP_BRAZERO + repeat_type;
+
+@@ -6082,22 +6082,21 @@ for (;; ptr++)
+ copying them. */
+
+ while (cd->hwm > cd->start_workspace + cd->workspace_size -
+- WORK_SIZE_SAFETY_MARGIN - (this_hwm - save_hwm))
++ WORK_SIZE_SAFETY_MARGIN -
++ (this_hwm_offset - save_hwm_offset))
+ {
+- int save_offset = save_hwm - cd->start_workspace;
+- int this_offset = this_hwm - cd->start_workspace;
+ *errorcodeptr = expand_workspace(cd);
+ if (*errorcodeptr != 0) goto FAILED;
+- save_hwm = (pcre_uchar *)cd->start_workspace + save_offset;
+- this_hwm = (pcre_uchar *)cd->start_workspace + this_offset;
+ }
+
+- for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE)
++ for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset;
++ hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset;
++ hc += LINK_SIZE)
+ {
+ PUT(cd->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1));
+ cd->hwm += LINK_SIZE;
+ }
+- save_hwm = this_hwm;
++ save_hwm_offset = this_hwm_offset;
+ code += len;
+ }
+
+@@ -6193,7 +6192,7 @@ for (;; ptr++)
+ {
+ int nlen = (int)(code - bracode);
+ *code = OP_END;
+- adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, save_hwm);
++ adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
+ memmove(bracode + 1 + LINK_SIZE, bracode, IN_UCHARS(nlen));
+ code += 1 + LINK_SIZE;
+ nlen += 1 + LINK_SIZE;
+@@ -6327,7 +6326,7 @@ for (;; ptr++)
+ else
+ {
+ *code = OP_END;
+- adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm);
++ adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
+ memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
+ code += 1 + LINK_SIZE;
+ len += 1 + LINK_SIZE;
+@@ -6376,7 +6375,7 @@ for (;; ptr++)
+
+ default:
+ *code = OP_END;
+- adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm);
++ adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
+ memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
+ code += 1 + LINK_SIZE;
+ len += 1 + LINK_SIZE;
+@@ -6408,7 +6407,7 @@ for (;; ptr++)
+ newoptions = options;
+ skipbytes = 0;
+ bravalue = OP_CBRA;
+- save_hwm = cd->hwm;
++ save_hwm_offset = cd->hwm - cd->start_workspace;
+ reset_bracount = FALSE;
+
+ /* First deal with various "verbs" that can be introduced by '*'. */
+@@ -7701,7 +7700,7 @@ for (;; ptr++)
+ const pcre_uchar *p;
+ pcre_uint32 cf;
+
+- save_hwm = cd->hwm; /* Normally this is set when '(' is read */
++ save_hwm_offset = cd->hwm - cd->start_workspace; /* Normally this is set when '(' is read */
+ terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)?
+ CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
+
+@@ -8247,7 +8246,7 @@ for (;;)
+ {
+ *code = OP_END;
+ adjust_recurse(start_bracket, 1 + LINK_SIZE,
+- (options & PCRE_UTF8) != 0, cd, cd->hwm);
++ (options & PCRE_UTF8) != 0, cd, cd->hwm - cd->start_workspace);
+ memmove(start_bracket + 1 + LINK_SIZE, start_bracket,
+ IN_UCHARS(code - start_bracket));
+ *start_bracket = OP_ONCE;
+--- a/testdata/testinput2
++++ b/testdata/testinput2
+@@ -4064,4 +4064,6 @@ backtracking verbs. --/
+
+ /(((((a)))))/Q
+
++"((?2){0,1999}())?"
++
+ /-- End of testinput2 --/
+--- a/testdata/testoutput2
++++ b/testdata/testoutput2
+@@ -14173,4 +14173,6 @@ Failed: parentheses are too deeply neste
+ /(((((a)))))/Q
+ ** Missing 0 or 1 after /Q
+
++"((?2){0,1999}())?"
++
+ /-- End of testinput2 --/
diff --git a/debian/patches/Fix-buffer-overflow-for-named-recursive-back-referen.patch b/debian/patches/Fix-buffer-overflow-for-named-recursive-back-referen.patch
new file mode 100644
index 0000000..3c4132b
--- /dev/null
+++ b/debian/patches/Fix-buffer-overflow-for-named-recursive-back-referen.patch
@@ -0,0 +1,59 @@
+Description: CVE-2015-3210: heap buffer overflow in pcre_compile2() / compile_regex()
+ Fix buffer overflow for named recursive back reference when
+ the name is duplicated.
+Origin: upstream, http://vcs.pcre.org/pcre?view=revision&revision=1558
+Bug: https://bugs.exim.org/show_bug.cgi?id=1636
+Bug-Debian: https://bugs.debian.org/787433
+Forwarded: not-needed
+Last-Update: 2015-09-10
+Applied-Upstream: not-yet (8.38)
+
+--- a/pcre_compile.c
++++ b/pcre_compile.c
+@@ -7082,14 +7082,26 @@ for (;; ptr++)
+ number. If the name is not found, set the value to 0 for a forward
+ reference. */
+
++ recno = 0;
+ ng = cd->named_groups;
+ for (i = 0; i < cd->names_found; i++, ng++)
+ {
+ if (namelen == ng->length &&
+ STRNCMP_UC_UC(name, ng->name, namelen) == 0)
+- break;
++ {
++ open_capitem *oc;
++ recno = ng->number;
++ if (is_recurse) break;
++ for (oc = cd->open_caps; oc != NULL; oc = oc->next)
++ {
++ if (oc->number == recno)
++ {
++ oc->flag = TRUE;
++ break;
++ }
++ }
++ }
+ }
+- recno = (i < cd->names_found)? ng->number : 0;
+
+ /* Count named back references. */
+
+--- a/testdata/testinput2
++++ b/testdata/testinput2
+@@ -4068,4 +4068,6 @@ backtracking verbs. --/
+
+ /((?+1)(\1))/BZ
+
++"(?J)(?'d'(?'d'\g{d}))"
++
+ /-- End of testinput2 --/
+--- a/testdata/testoutput2
++++ b/testdata/testoutput2
+@@ -14190,4 +14190,6 @@ Failed: parentheses are too deeply neste
+ End
+ ------------------------------------------------------------------
+
++"(?J)(?'d'(?'d'\g{d}))"
++
+ /-- End of testinput2 --/
diff --git a/debian/patches/Fix-compile-time-loop-for-recursive-reference-within.patch b/debian/patches/Fix-compile-time-loop-for-recursive-reference-within.patch
new file mode 100644
index 0000000..a38be27
--- /dev/null
+++ b/debian/patches/Fix-compile-time-loop-for-recursive-reference-within.patch
@@ -0,0 +1,86 @@
+Description: PCRE Call Stack Overflow Vulnerability
+ Fix compile-time loop for recursive reference within a group
+ with an indefinite repeat.
+Origin: backport, http://vcs.pcre.org/pcre?view=revision&revision=1498
+Bug: https://bugs.exim.org/show_bug.cgi?id=1515
+Forwarded: not-needed
+Last-Update: 2015-09-10
+Applied-Upstream: 8.36
+
+--- a/pcre_compile.c
++++ b/pcre_compile.c
+@@ -2367,6 +2367,7 @@ for (code = first_significant_code(code
+ if (c == OP_RECURSE)
+ {
+ const pcre_uchar *scode = cd->start_code + GET(code, 1);
++ const pcre_uchar *endgroup = scode;
+ BOOL empty_branch;
+
+ /* Test for forward reference or uncompleted reference. This is disabled
+@@ -2381,24 +2382,20 @@ for (code = first_significant_code(code
+ if (GET(scode, 1) == 0) return TRUE; /* Unclosed */
+ }
+
+- /* If we are scanning a completed pattern, there are no forward references
+- and all groups are complete. We need to detect whether this is a recursive
+- call, as otherwise there will be an infinite loop. If it is a recursion,
+- just skip over it. Simple recursions are easily detected. For mutual
+- recursions we keep a chain on the stack. */
++ /* If the reference is to a completed group, we need to detect whether this
++ is a recursive call, as otherwise there will be an infinite loop. If it is
++ a recursion, just skip over it. Simple recursions are easily detected. For
++ mutual recursions we keep a chain on the stack. */
+
++ do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
++ if (code >= scode && code <= endgroup) continue; /* Simple recursion */
+ else
+- {
++ {
+ recurse_check *r = recurses;
+- const pcre_uchar *endgroup = scode;
+-
+- do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
+- if (code >= scode && code <= endgroup) continue; /* Simple recursion */
+-
+ for (r = recurses; r != NULL; r = r->prev)
+ if (r->group == scode) break;
+ if (r != NULL) continue; /* Mutual recursion */
+- }
++ }
+
+ /* Completed reference; scan the referenced group, remembering it on the
+ stack chain to detect mutual recursions. */
+--- a/testdata/testinput1
++++ b/testdata/testinput1
+@@ -4937,6 +4937,12 @@ however, we need the complication for Pe
+
+ /((?(R1)a+|(?1)b))/
+ aaaabcde
++
++/((?(R)a|(?1)))*/
++ aaa
++
++/((?(R)a|(?1)))+/
++ aaa
+
+ /a(*:any
+ name)/K
+--- a/testdata/testoutput1
++++ b/testdata/testoutput1
+@@ -8234,6 +8234,16 @@ MK: M
+ aaaabcde
+ 0: aaaab
+ 1: aaaab
++
++/((?(R)a|(?1)))*/
++ aaa
++ 0: aaa
++ 1: a
++
++/((?(R)a|(?1)))+/
++ aaa
++ 0: aaa
++ 1: a
+
+ /a(*:any
+ name)/K
diff --git a/debian/patches/Fix-compiler-crash-misbehaviour-for-zero-repeated-gr.patch b/debian/patches/Fix-compiler-crash-misbehaviour-for-zero-repeated-gr.patch
new file mode 100644
index 0000000..a8c15f3
--- /dev/null
+++ b/debian/patches/Fix-compiler-crash-misbehaviour-for-zero-repeated-gr.patch
@@ -0,0 +1,175 @@
+Description: PCRE Library Stack Overflow Vulnerability
+ Fix compiler crash/misbehaviour for zero-repeated groups that
+ include a recursive back reference.
+Origin: backport, http://vcs.pcre.org/pcre?view=revision&revision=1495
+Bug: https://bugs.exim.org/show_bug.cgi?id=1503
+Forwarded: not-needed
+Last-Update: 2015-09-10
+Applied-Upstream: 8.36
+---
+--- a/pcre_compile.c
++++ b/pcre_compile.c
+@@ -8241,12 +8241,16 @@ for (;;)
+
+ /* If it was a capturing subpattern, check to see if it contained any
+ recursive back references. If so, we must wrap it in atomic brackets.
+- In any event, remove the block from the chain. */
++ Because we are moving code along, we must ensure that any pending recursive
++ references are updated. In any event, remove the block from the chain. */
+
+ if (capnumber > 0)
+ {
+ if (cd->open_caps->flag)
+ {
++ *code = OP_END;
++ adjust_recurse(start_bracket, 1 + LINK_SIZE,
++ (options & PCRE_UTF8) != 0, cd, cd->hwm);
+ memmove(start_bracket + 1 + LINK_SIZE, start_bracket,
+ IN_UCHARS(code - start_bracket));
+ *start_bracket = OP_ONCE;
+--- a/testdata/testinput11
++++ b/testdata/testinput11
+@@ -132,4 +132,6 @@ is required for these tests. --/
+
+ /abc(d|e)(*THEN)x(123(*THEN)4|567(b|q)(*THEN)xx)/B
+
++/(((a\2)|(a*)\g<-1>))*a?/B
++
+ /-- End of testinput11 --/
+--- a/testdata/testinput2
++++ b/testdata/testinput2
+@@ -4035,6 +4035,8 @@ backtracking verbs. --/
+
+ /(?(R&6yh)abc)/
+
++/(((a\2)|(a*)\g<-1>))*a?/BZ
++
+ /-- Test the ugly "start or end of word" compatibility syntax --/
+
+ /[[:<:]]red[[:>:]]/BZ
+--- a/testdata/testoutput11-16
++++ b/testdata/testoutput11-16
+@@ -709,4 +709,28 @@ Memory allocation (code space): 14
+ 62 End
+ ------------------------------------------------------------------
+
++/(((a\2)|(a*)\g<-1>))*a?/B
++------------------------------------------------------------------
++ 0 39 Bra
++ 2 Brazero
++ 3 32 SCBra 1
++ 6 27 Once
++ 8 12 CBra 2
++ 11 7 CBra 3
++ 14 a
++ 16 \2
++ 18 7 Ket
++ 20 11 Alt
++ 22 5 CBra 4
++ 25 a*
++ 27 5 Ket
++ 29 22 Recurse
++ 31 23 Ket
++ 33 27 Ket
++ 35 32 KetRmax
++ 37 a?+
++ 39 39 Ket
++ 41 End
++------------------------------------------------------------------
++
+ /-- End of testinput11 --/
+--- a/testdata/testoutput11-32
++++ b/testdata/testoutput11-32
+@@ -709,4 +709,28 @@ Memory allocation (code space): 28
+ 62 End
+ ------------------------------------------------------------------
+
++/(((a\2)|(a*)\g<-1>))*a?/B
++------------------------------------------------------------------
++ 0 39 Bra
++ 2 Brazero
++ 3 32 SCBra 1
++ 6 27 Once
++ 8 12 CBra 2
++ 11 7 CBra 3
++ 14 a
++ 16 \2
++ 18 7 Ket
++ 20 11 Alt
++ 22 5 CBra 4
++ 25 a*
++ 27 5 Ket
++ 29 22 Recurse
++ 31 23 Ket
++ 33 27 Ket
++ 35 32 KetRmax
++ 37 a?+
++ 39 39 Ket
++ 41 End
++------------------------------------------------------------------
++
+ /-- End of testinput11 --/
+--- a/testdata/testoutput11-8
++++ b/testdata/testoutput11-8
+@@ -709,4 +709,28 @@ Memory allocation (code space): 10
+ 76 End
+ ------------------------------------------------------------------
+
++/(((a\2)|(a*)\g<-1>))*a?/B
++------------------------------------------------------------------
++ 0 57 Bra
++ 3 Brazero
++ 4 48 SCBra 1
++ 9 40 Once
++ 12 18 CBra 2
++ 17 10 CBra 3
++ 22 a
++ 24 \2
++ 27 10 Ket
++ 30 16 Alt
++ 33 7 CBra 4
++ 38 a*
++ 40 7 Ket
++ 43 33 Recurse
++ 46 34 Ket
++ 49 40 Ket
++ 52 48 KetRmax
++ 55 a?+
++ 57 57 Ket
++ 60 End
++------------------------------------------------------------------
++
+ /-- End of testinput11 --/
+--- a/testdata/testoutput2
++++ b/testdata/testoutput2
+@@ -14093,6 +14093,30 @@ Failed: malformed number or name after (
+ /(?(R&6yh)abc)/
+ Failed: group name must start with a non-digit at offset 5
+
++/(((a\2)|(a*)\g<-1>))*a?/BZ
++------------------------------------------------------------------
++ Bra
++ Brazero
++ SCBra 1
++ Once
++ CBra 2
++ CBra 3
++ a
++ \2
++ Ket
++ Alt
++ CBra 4
++ a*
++ Ket
++ Recurse
++ Ket
++ Ket
++ KetRmax
++ a?+
++ Ket
++ End
++------------------------------------------------------------------
++
+ /-- Test the ugly "start or end of word" compatibility syntax --/
+
+ /[[:<:]]red[[:>:]]/BZ
diff --git a/debian/patches/series b/debian/patches/series
index c30b0d0..6bdf005 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -7,3 +7,10 @@ Fix-silly-quantifier-size-check.patch
cve-2014-8964.patch
no_jit_x32_powerpcspe.patch
fix_find_fixedlength.patch
+Fix-compiler-crash-misbehaviour-for-zero-repeated-gr.patch
+Fix-compile-time-loop-for-recursive-reference-within.patch
+794589-information-disclosure.patch
+Fix-bad-compile-for-groups-like-2-0-1999.patch
+Fix-bad-compilation-for-patterns-like-1-1-with-forwa.patch
+Fix-buffer-overflow-for-named-recursive-back-referen.patch
+Disable_JIT_on_sparc64.patch
diff --git a/pcre_compile.c b/pcre_compile.c
index c76ca14..08caf8e 100644
--- a/pcre_compile.c
+++ b/pcre_compile.c
@@ -2367,6 +2367,7 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
if (c == OP_RECURSE)
{
const pcre_uchar *scode = cd->start_code + GET(code, 1);
+ const pcre_uchar *endgroup = scode;
BOOL empty_branch;
/* Test for forward reference or uncompleted reference. This is disabled
@@ -2381,24 +2382,20 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
if (GET(scode, 1) == 0) return TRUE; /* Unclosed */
}
- /* If we are scanning a completed pattern, there are no forward references
- and all groups are complete. We need to detect whether this is a recursive
- call, as otherwise there will be an infinite loop. If it is a recursion,
- just skip over it. Simple recursions are easily detected. For mutual
- recursions we keep a chain on the stack. */
+ /* If the reference is to a completed group, we need to detect whether this
+ is a recursive call, as otherwise there will be an infinite loop. If it is
+ a recursion, just skip over it. Simple recursions are easily detected. For
+ mutual recursions we keep a chain on the stack. */
+ do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
+ if (code >= scode && code <= endgroup) continue; /* Simple recursion */
else
- {
+ {
recurse_check *r = recurses;
- const pcre_uchar *endgroup = scode;
-
- do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
- if (code >= scode && code <= endgroup) continue; /* Simple recursion */
-
for (r = recurses; r != NULL; r = r->prev)
if (r->group == scode) break;
if (r != NULL) continue; /* Mutual recursion */
- }
+ }
/* Completed reference; scan the referenced group, remembering it on the
stack chain to detect mutual recursions. */
@@ -3936,14 +3933,14 @@ Arguments:
adjust the amount by which the group is to be moved
utf TRUE in UTF-8 / UTF-16 / UTF-32 mode
cd contains pointers to tables etc.
- save_hwm the hwm forward reference pointer at the start of the group
+ save_hwm_offset the hwm forward reference offset at the start of the group
Returns: nothing
*/
static void
adjust_recurse(pcre_uchar *group, int adjust, BOOL utf, compile_data *cd,
- pcre_uchar *save_hwm)
+ size_t save_hwm_offset)
{
pcre_uchar *ptr = group;
@@ -3955,7 +3952,8 @@ while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL)
/* See if this recursion is on the forward reference list. If so, adjust the
reference. */
- for (hc = save_hwm; hc < cd->hwm; hc += LINK_SIZE)
+ for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm;
+ hc += LINK_SIZE)
{
offset = (int)GET(hc, 0);
if (cd->start_code + offset == ptr + 1)
@@ -4400,7 +4398,7 @@ const pcre_uchar *tempptr;
const pcre_uchar *nestptr = NULL;
pcre_uchar *previous = NULL;
pcre_uchar *previous_callout = NULL;
-pcre_uchar *save_hwm = NULL;
+size_t save_hwm_offset = 0;
pcre_uint8 classbits[32];
/* We can fish out the UTF-8 setting once and for all into a BOOL, but we
@@ -5912,7 +5910,7 @@ for (;; ptr++)
if (repeat_max <= 1) /* Covers 0, 1, and unlimited */
{
*code = OP_END;
- adjust_recurse(previous, 1, utf, cd, save_hwm);
+ adjust_recurse(previous, 1, utf, cd, save_hwm_offset);
memmove(previous + 1, previous, IN_UCHARS(len));
code++;
if (repeat_max == 0)
@@ -5936,7 +5934,7 @@ for (;; ptr++)
{
int offset;
*code = OP_END;
- adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, save_hwm);
+ adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, save_hwm_offset);
memmove(previous + 2 + LINK_SIZE, previous, IN_UCHARS(len));
code += 2 + LINK_SIZE;
*previous++ = OP_BRAZERO + repeat_type;
@@ -5999,26 +5997,25 @@ for (;; ptr++)
for (i = 1; i < repeat_min; i++)
{
pcre_uchar *hc;
- pcre_uchar *this_hwm = cd->hwm;
+ size_t this_hwm_offset = cd->hwm - cd->start_workspace;
memcpy(code, previous, IN_UCHARS(len));
while (cd->hwm > cd->start_workspace + cd->workspace_size -
- WORK_SIZE_SAFETY_MARGIN - (this_hwm - save_hwm))
+ WORK_SIZE_SAFETY_MARGIN -
+ (this_hwm_offset - save_hwm_offset))
{
- int save_offset = save_hwm - cd->start_workspace;
- int this_offset = this_hwm - cd->start_workspace;
*errorcodeptr = expand_workspace(cd);
if (*errorcodeptr != 0) goto FAILED;
- save_hwm = (pcre_uchar *)cd->start_workspace + save_offset;
- this_hwm = (pcre_uchar *)cd->start_workspace + this_offset;
}
- for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE)
+ for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset;
+ hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset;
+ hc += LINK_SIZE)
{
PUT(cd->hwm, 0, GET(hc, 0) + len);
cd->hwm += LINK_SIZE;
}
- save_hwm = this_hwm;
+ save_hwm_offset = this_hwm_offset;
code += len;
}
}
@@ -6063,7 +6060,7 @@ for (;; ptr++)
else for (i = repeat_max - 1; i >= 0; i--)
{
pcre_uchar *hc;
- pcre_uchar *this_hwm = cd->hwm;
+ size_t this_hwm_offset = cd->hwm - cd->start_workspace;
*code++ = OP_BRAZERO + repeat_type;
@@ -6085,22 +6082,21 @@ for (;; ptr++)
copying them. */
while (cd->hwm > cd->start_workspace + cd->workspace_size -
- WORK_SIZE_SAFETY_MARGIN - (this_hwm - save_hwm))
+ WORK_SIZE_SAFETY_MARGIN -
+ (this_hwm_offset - save_hwm_offset))
{
- int save_offset = save_hwm - cd->start_workspace;
- int this_offset = this_hwm - cd->start_workspace;
*errorcodeptr = expand_workspace(cd);
if (*errorcodeptr != 0) goto FAILED;
- save_hwm = (pcre_uchar *)cd->start_workspace + save_offset;
- this_hwm = (pcre_uchar *)cd->start_workspace + this_offset;
}
- for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE)
+ for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset;
+ hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset;
+ hc += LINK_SIZE)
{
PUT(cd->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1));
cd->hwm += LINK_SIZE;
}
- save_hwm = this_hwm;
+ save_hwm_offset = this_hwm_offset;
code += len;
}
@@ -6196,7 +6192,7 @@ for (;; ptr++)
{
int nlen = (int)(code - bracode);
*code = OP_END;
- adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, save_hwm);
+ adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
memmove(bracode + 1 + LINK_SIZE, bracode, IN_UCHARS(nlen));
code += 1 + LINK_SIZE;
nlen += 1 + LINK_SIZE;
@@ -6330,7 +6326,7 @@ for (;; ptr++)
else
{
*code = OP_END;
- adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm);
+ adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
code += 1 + LINK_SIZE;
len += 1 + LINK_SIZE;
@@ -6379,7 +6375,7 @@ for (;; ptr++)
default:
*code = OP_END;
- adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm);
+ adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
code += 1 + LINK_SIZE;
len += 1 + LINK_SIZE;
@@ -6411,7 +6407,7 @@ for (;; ptr++)
newoptions = options;
skipbytes = 0;
bravalue = OP_CBRA;
- save_hwm = cd->hwm;
+ save_hwm_offset = cd->hwm - cd->start_workspace;
reset_bracount = FALSE;
/* First deal with various "verbs" that can be introduced by '*'. */
@@ -7086,14 +7082,26 @@ for (;; ptr++)
number. If the name is not found, set the value to 0 for a forward
reference. */
+ recno = 0;
ng = cd->named_groups;
for (i = 0; i < cd->names_found; i++, ng++)
{
if (namelen == ng->length &&
STRNCMP_UC_UC(name, ng->name, namelen) == 0)
- break;
+ {
+ open_capitem *oc;
+ recno = ng->number;
+ if (is_recurse) break;
+ for (oc = cd->open_caps; oc != NULL; oc = oc->next)
+ {
+ if (oc->number == recno)
+ {
+ oc->flag = TRUE;
+ break;
+ }
+ }
+ }
}
- recno = (i < cd->names_found)? ng->number : 0;
/* Count named back references. */
@@ -7704,7 +7712,7 @@ for (;; ptr++)
const pcre_uchar *p;
pcre_uint32 cf;
- save_hwm = cd->hwm; /* Normally this is set when '(' is read */
+ save_hwm_offset = cd->hwm - cd->start_workspace; /* Normally this is set when '(' is read */
terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)?
CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
@@ -8031,6 +8039,7 @@ int length;
unsigned int orig_bracount;
unsigned int max_bracount;
branch_chain bc;
+size_t save_hwm_offset;
/* If set, call the external function that checks for stack availability. */
@@ -8048,6 +8057,8 @@ bc.current_branch = code;
firstchar = reqchar = 0;
firstcharflags = reqcharflags = REQ_UNSET;
+save_hwm_offset = cd->hwm - cd->start_workspace;
+
/* Accumulate the length for use in the pre-compile phase. Start with the
length of the BRA and KET and any extra bytes that are required at the
beginning. We accumulate in a local variable to save frequent testing of
@@ -8241,12 +8252,16 @@ for (;;)
/* If it was a capturing subpattern, check to see if it contained any
recursive back references. If so, we must wrap it in atomic brackets.
- In any event, remove the block from the chain. */
+ Because we are moving code along, we must ensure that any pending recursive
+ references are updated. In any event, remove the block from the chain. */
if (capnumber > 0)
{
if (cd->open_caps->flag)
{
+ *code = OP_END;
+ adjust_recurse(start_bracket, 1 + LINK_SIZE,
+ (options & PCRE_UTF8) != 0, cd, save_hwm_offset);
memmove(start_bracket + 1 + LINK_SIZE, start_bracket,
IN_UCHARS(code - start_bracket));
*start_bracket = OP_ONCE;
diff --git a/pcre_exec.c b/pcre_exec.c
index a6ef1c1..0270d60 100644
--- a/pcre_exec.c
+++ b/pcre_exec.c
@@ -1467,7 +1467,18 @@ for (;;)
md->offset_vector[offset] =
md->offset_vector[md->offset_end - number];
md->offset_vector[offset+1] = (int)(eptr - md->start_subject);
- if (offset_top <= offset) offset_top = offset + 2;
+
+ /* If this group is at or above the current highwater mark, ensure that
+ any groups between the current high water mark and this group are marked
+ unset and then update the high water mark. */
+
+ if (offset >= offset_top)
+ {
+ register int *iptr = md->offset_vector + offset_top;
+ register int *iend = md->offset_vector + offset;
+ while (iptr < iend) *iptr++ = -1;
+ offset_top = offset + 2;
+ }
}
ecode += 1 + IMM2_SIZE;
break;
diff --git a/sljit/sljitConfigInternal.h b/sljit/sljitConfigInternal.h
index 8219e73..16175f0 100644
--- a/sljit/sljitConfigInternal.h
+++ b/sljit/sljitConfigInternal.h
@@ -125,7 +125,11 @@
#elif defined(__mips64)
#define SLJIT_CONFIG_MIPS_64 1
#elif defined(__sparc__) || defined(__sparc)
-#define SLJIT_CONFIG_SPARC_32 1
+# if defined(__arch64__)
+# define SLJIT_CONFIG_UNSUPPORTED 1
+# else
+# define SLJIT_CONFIG_SPARC_32 1
+# endif
#elif defined(__tilegx__)
#define SLJIT_CONFIG_TILEGX 1
#else
diff --git a/testdata/testinput1 b/testdata/testinput1
index 7b36360..fbca11e 100644
--- a/testdata/testinput1
+++ b/testdata/testinput1
@@ -4937,6 +4937,12 @@ however, we need the complication for Perl. ---/
/((?(R1)a+|(?1)b))/
aaaabcde
+
+/((?(R)a|(?1)))*/
+ aaa
+
+/((?(R)a|(?1)))+/
+ aaa
/a(*:any
name)/K
diff --git a/testdata/testinput11 b/testdata/testinput11
index 391ada7..65a4b03 100644
--- a/testdata/testinput11
+++ b/testdata/testinput11
@@ -132,4 +132,8 @@ is required for these tests. --/
/abc(d|e)(*THEN)x(123(*THEN)4|567(b|q)(*THEN)xx)/B
+/(((a\2)|(a*)\g<-1>))*a?/B
+
+/((?+1)(\1))/B
+
/-- End of testinput11 --/
diff --git a/testdata/testinput2 b/testdata/testinput2
index da6e614..90f1795 100644
--- a/testdata/testinput2
+++ b/testdata/testinput2
@@ -4035,6 +4035,8 @@ backtracking verbs. --/
/(?(R&6yh)abc)/
+/(((a\2)|(a*)\g<-1>))*a?/BZ
+
/-- Test the ugly "start or end of word" compatibility syntax --/
/[[:<:]]red[[:>:]]/BZ
@@ -4062,4 +4064,10 @@ backtracking verbs. --/
/(((((a)))))/Q
+"((?2){0,1999}())?"
+
+/((?+1)(\1))/BZ
+
+"(?J)(?'d'(?'d'\g{d}))"
+
/-- End of testinput2 --/
diff --git a/testdata/testoutput1 b/testdata/testoutput1
index 4dafc04..09e2a82 100644
--- a/testdata/testoutput1
+++ b/testdata/testoutput1
@@ -8234,6 +8234,16 @@ MK: M
aaaabcde
0: aaaab
1: aaaab
+
+/((?(R)a|(?1)))*/
+ aaa
+ 0: aaa
+ 1: a
+
+/((?(R)a|(?1)))+/
+ aaa
+ 0: aaa
+ 1: a
/a(*:any
name)/K
diff --git a/testdata/testoutput11-16 b/testdata/testoutput11-16
index f1ad888..d4ba39e 100644
--- a/testdata/testoutput11-16
+++ b/testdata/testoutput11-16
@@ -709,4 +709,43 @@ Memory allocation (code space): 14
62 End
------------------------------------------------------------------
+/(((a\2)|(a*)\g<-1>))*a?/B
+------------------------------------------------------------------
+ 0 39 Bra
+ 2 Brazero
+ 3 32 SCBra 1
+ 6 27 Once
+ 8 12 CBra 2
+ 11 7 CBra 3
+ 14 a
+ 16 \2
+ 18 7 Ket
+ 20 11 Alt
+ 22 5 CBra 4
+ 25 a*
+ 27 5 Ket
+ 29 22 Recurse
+ 31 23 Ket
+ 33 27 Ket
+ 35 32 KetRmax
+ 37 a?+
+ 39 39 Ket
+ 41 End
+------------------------------------------------------------------
+
+/((?+1)(\1))/B
+------------------------------------------------------------------
+ 0 20 Bra
+ 2 16 Once
+ 4 12 CBra 1
+ 7 9 Recurse
+ 9 5 CBra 2
+ 12 \1
+ 14 5 Ket
+ 16 12 Ket
+ 18 16 Ket
+ 20 20 Ket
+ 22 End
+------------------------------------------------------------------
+
/-- End of testinput11 --/
diff --git a/testdata/testoutput11-32 b/testdata/testoutput11-32
index 266e55d..85f4e1d 100644
--- a/testdata/testoutput11-32
+++ b/testdata/testoutput11-32
@@ -709,4 +709,43 @@ Memory allocation (code space): 28
62 End
------------------------------------------------------------------
+/(((a\2)|(a*)\g<-1>))*a?/B
+------------------------------------------------------------------
+ 0 39 Bra
+ 2 Brazero
+ 3 32 SCBra 1
+ 6 27 Once
+ 8 12 CBra 2
+ 11 7 CBra 3
+ 14 a
+ 16 \2
+ 18 7 Ket
+ 20 11 Alt
+ 22 5 CBra 4
+ 25 a*
+ 27 5 Ket
+ 29 22 Recurse
+ 31 23 Ket
+ 33 27 Ket
+ 35 32 KetRmax
+ 37 a?+
+ 39 39 Ket
+ 41 End
+------------------------------------------------------------------
+
+/((?+1)(\1))/B
+------------------------------------------------------------------
+ 0 20 Bra
+ 2 16 Once
+ 4 12 CBra 1
+ 7 9 Recurse
+ 9 5 CBra 2
+ 12 \1
+ 14 5 Ket
+ 16 12 Ket
+ 18 16 Ket
+ 20 20 Ket
+ 22 End
+------------------------------------------------------------------
+
/-- End of testinput11 --/
diff --git a/testdata/testoutput11-8 b/testdata/testoutput11-8
index d4a2133..1d60411 100644
--- a/testdata/testoutput11-8
+++ b/testdata/testoutput11-8
@@ -709,4 +709,43 @@ Memory allocation (code space): 10
76 End
------------------------------------------------------------------
+/(((a\2)|(a*)\g<-1>))*a?/B
+------------------------------------------------------------------
+ 0 57 Bra
+ 3 Brazero
+ 4 48 SCBra 1
+ 9 40 Once
+ 12 18 CBra 2
+ 17 10 CBra 3
+ 22 a
+ 24 \2
+ 27 10 Ket
+ 30 16 Alt
+ 33 7 CBra 4
+ 38 a*
+ 40 7 Ket
+ 43 33 Recurse
+ 46 34 Ket
+ 49 40 Ket
+ 52 48 KetRmax
+ 55 a?+
+ 57 57 Ket
+ 60 End
+------------------------------------------------------------------
+
+/((?+1)(\1))/B
+------------------------------------------------------------------
+ 0 31 Bra
+ 3 25 Once
+ 6 19 CBra 1
+ 11 14 Recurse
+ 14 8 CBra 2
+ 19 \1
+ 22 8 Ket
+ 25 19 Ket
+ 28 25 Ket
+ 31 31 Ket
+ 34 End
+------------------------------------------------------------------
+
/-- End of testinput11 --/
diff --git a/testdata/testoutput2 b/testdata/testoutput2
index cfb446e..16e5c68 100644
--- a/testdata/testoutput2
+++ b/testdata/testoutput2
@@ -14093,6 +14093,30 @@ Failed: malformed number or name after (?( at offset 4
/(?(R&6yh)abc)/
Failed: group name must start with a non-digit at offset 5
+/(((a\2)|(a*)\g<-1>))*a?/BZ
+------------------------------------------------------------------
+ Bra
+ Brazero
+ SCBra 1
+ Once
+ CBra 2
+ CBra 3
+ a
+ \2
+ Ket
+ Alt
+ CBra 4
+ a*
+ Ket
+ Recurse
+ Ket
+ Ket
+ KetRmax
+ a?+
+ Ket
+ End
+------------------------------------------------------------------
+
/-- Test the ugly "start or end of word" compatibility syntax --/
/[[:<:]]red[[:>:]]/BZ
@@ -14149,4 +14173,23 @@ Failed: parentheses are too deeply nested (stack check) at offset 0
/(((((a)))))/Q
** Missing 0 or 1 after /Q
+"((?2){0,1999}())?"
+
+/((?+1)(\1))/BZ
+------------------------------------------------------------------
+ Bra
+ Once
+ CBra 1
+ Recurse
+ CBra 2
+ \1
+ Ket
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+
+"(?J)(?'d'(?'d'\g{d}))"
+
/-- End of testinput2 --/