diff --git a/src/pcre2_compile.c b/src/pcre2_compile.c index 0b76a957f..50bb7abc9 100644 --- a/src/pcre2_compile.c +++ b/src/pcre2_compile.c @@ -10254,6 +10254,7 @@ get_branchlength(uint32_t **pptrptr, int *minptr, int *errcodeptr, int *lcptr, uint32_t group = 0; uint32_t itemlength = 0; uint32_t itemminlength = 0; + BOOL cond_no_else = FALSE; if (*pptr < META_END) { @@ -10542,14 +10543,20 @@ get_branchlength(uint32_t **pptrptr, int *minptr, int *errcodeptr, int *lcptr, case META_COND_RNAME: case META_COND_RNUMBER: pptr += 2 + SIZEOFFSET; - goto CHECK_GROUP; + goto CHECK_COND; case META_COND_ASSERT: pptr += 1; - goto CHECK_GROUP; + goto CHECK_COND; case META_COND_VERSION: pptr += 4; + + CHECK_COND: + gptr = parsed_skip(pptr, PSKIP_ALT); + if (gptr == NULL) + return -1; + cond_no_else = *gptr == META_KET; goto CHECK_GROUP; case META_CAPTURE: @@ -10566,7 +10573,7 @@ get_branchlength(uint32_t **pptrptr, int *minptr, int *errcodeptr, int *lcptr, if (grouplength < 0) return -1; itemlength = grouplength; - itemminlength = groupminlength; + itemminlength = cond_no_else ? 0 : groupminlength; break; case META_QUERY: diff --git a/src/pcre2_jit_char_inc.h b/src/pcre2_jit_char_inc.h index c8dd49b92..a9e6ec94d 100644 --- a/src/pcre2_jit_char_inc.h +++ b/src/pcre2_jit_char_inc.h @@ -2036,12 +2036,8 @@ compile_char1_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR detect_partial_match(common, backtracks); read_char(common, common->bsr_nlmin, common->bsr_nlmax, NULL, 0); jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR); - /* We don't need to handle soft partial matching case. */ end_list = NULL; - if (common->mode != PCRE2_JIT_PARTIAL_HARD) - add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); - else - check_str_end(common, &end_list); + check_str_end(common, &end_list); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, CHAR_NL); OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); diff --git a/src/pcre2_jit_compile.c b/src/pcre2_jit_compile.c index 47854258b..ec6d7fa80 100644 --- a/src/pcre2_jit_compile.c +++ b/src/pcre2_jit_compile.c @@ -4215,17 +4215,20 @@ check_str_end(compiler_common *common, jump_list **end_reached) } jump = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); - if (common->mode == PCRE2_JIT_PARTIAL_SOFT) - { + if (!common->allow_empty_partial) add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0)); + else if (common->mode == PCRE2_JIT_PARTIAL_SOFT) + add_jump(compiler, end_reached, + CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1)); + + if (common->mode == PCRE2_JIT_PARTIAL_SOFT) + { OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0); add_jump(compiler, end_reached, JUMP(SLJIT_JUMP)); } else { - add_jump(compiler, end_reached, - CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0)); if (common->partialmatchlabel != NULL) JUMPTO(SLJIT_JUMP, common->partialmatchlabel); else @@ -5875,7 +5878,7 @@ do_getucdtype(compiler_common *common) #endif /* SUPPORT_UNICODE */ static SLJIT_INLINE struct sljit_label * -mainloop_entry(compiler_common *common) +mainloop_entry(compiler_common *common, jump_list **limit_reached) { DEFINE_COMPILER; struct sljit_label *mainloop; @@ -6061,6 +6064,11 @@ mainloop_entry(compiler_common *common) JUMPHERE(end2); } + if ((readuchar || newlinecheck) && + (overall_options & (PCRE2_FIRSTLINE | PCRE2_USE_OFFSET_LIMIT)) == PCRE2_USE_OFFSET_LIMIT) + add_jump(compiler, limit_reached, + CMP(SLJIT_GREATER, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr)); + return mainloop; } @@ -6181,6 +6189,7 @@ scan_prefix(compiler_common *common, PCRE2_SPTR cc, fast_forward_char_data *char --stack_ptr; cc = cc_stack[stack_ptr]; chars = chars_stack[stack_ptr]; + repeat = 1; if (chars >= chars_end) continue; @@ -9761,10 +9770,7 @@ compile_assert_matchingpath(compiler_common *common, PCRE2_SPTR cc, assert_backt } if (end_block_size > 0) - { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), STR_END, 0); - OP1(SLJIT_MOV, STR_END, 0, STR_PTR, 0); - } memset(&altbacktrack, 0, sizeof(backtrack_common)); if (conditional || (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT)) @@ -9777,7 +9783,8 @@ compile_assert_matchingpath(compiler_common *common, PCRE2_SPTR cc, assert_backt common->quit = NULL; } - common->in_positive_assertion = (opcode == OP_ASSERT || opcode == OP_ASSERTBACK); + common->in_positive_assertion = + (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) && !local_quit_available; common->positive_assertion_quit = NULL; while (1) @@ -9818,9 +9825,17 @@ compile_assert_matchingpath(compiler_common *common, PCRE2_SPTR cc, assert_backt if (has_vreverse) { - SLJIT_ASSERT(altbacktrack.top != NULL); - add_jump(compiler, &altbacktrack.top->simple_backtracks, - CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0)); + SLJIT_ASSERT(altbacktrack.top != NULL && extrasize > 0); + if (framesize == no_stack) + add_jump(compiler, &altbacktrack.top->simple_backtracks, + CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0))); + else + { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); + add_jump(compiler, &altbacktrack.top->simple_backtracks, + CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), + STACK(-(framesize < 0 ? 0 : framesize) - extrasize))); + } } common->accept_label = LABEL(); @@ -10632,7 +10647,6 @@ compile_bracket_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_c OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr + sizeof(sljit_sw), STR_END, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); - OP1(SLJIT_MOV, STR_END, 0, STR_PTR, 0); has_vreverse = (*matchingpath == OP_VREVERSE); if (*matchingpath == OP_REVERSE || has_vreverse) @@ -10874,7 +10888,7 @@ compile_bracket_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_c { SLJIT_ASSERT(backtrack->top != NULL && PRIVATE_DATA(ccbegin + 1)); add_jump(compiler, &backtrack->top->simple_backtracks, - CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0)); + CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr)); } if (PRIVATE_DATA(ccbegin + 1)) @@ -13344,8 +13358,6 @@ compile_bracket_backtrackingpath(compiler_common *common, struct backtrack_commo if (common->restore_end_ptr == 0) common->restore_end_ptr = private_data_ptr + sizeof(sljit_sw); } - else if (SLJIT_UNLIKELY(opcode == OP_ASSERTBACK_NA) && PRIVATE_DATA(ccbegin + 1)) - OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); if (SLJIT_UNLIKELY(opcode == OP_ONCE)) { @@ -13485,7 +13497,7 @@ compile_bracket_backtrackingpath(compiler_common *common, struct backtrack_commo { SLJIT_ASSERT(current->top != NULL && PRIVATE_DATA(ccbegin + 1)); add_jump(compiler, ¤t->top->simple_backtracks, - CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0)); + CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr)); } if (PRIVATE_DATA(ccbegin + 1)) @@ -13858,7 +13870,7 @@ compile_control_verb_backtrackingpath(compiler_common *common, struct backtrack_ add_jump(compiler, &common->then_trap->quit, JUMP(SLJIT_JUMP)); return; } - else if (!common->local_quit_available && common->in_positive_assertion) + else if (common->in_positive_assertion) { add_jump(compiler, &common->positive_assertion_quit, JUMP(SLJIT_JUMP)); return; @@ -13962,6 +13974,12 @@ compile_then_trap_backtrackingpath(compiler_common *common, struct backtrack_com OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 3); + if (current->prev != NULL && *current->prev->cc == OP_VREVERSE) + { + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP1, 0); + add_jump(compiler, ¤t->prev->own_backtracks, JUMP(SLJIT_JUMP)); + } + JUMPHERE(jump); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP1, 0); } @@ -14424,6 +14442,7 @@ jit_compile(pcre2_code *code, sljit_u32 mode) struct sljit_jump *empty_match = NULL; struct sljit_jump *end_anchor_failed = NULL; jump_list *reqcu_not_found = NULL; + jump_list *limit_reached = NULL; SLJIT_ASSERT(tables); @@ -14719,7 +14738,7 @@ jit_compile(pcre2_code *code, sljit_u32 mode) /* Main part of the matching */ if ((re->overall_options & PCRE2_ANCHORED) == 0) { - mainloop_label = mainloop_entry(common); + mainloop_label = mainloop_entry(common, &limit_reached); continue_match_label = LABEL(); /* Forward search if possible. */ if ((re->optimization_flags & PCRE2_OPTIM_START_OPTIMIZE) != 0) @@ -14922,6 +14941,8 @@ jit_compile(pcre2_code *code, sljit_u32 mode) /* No more remaining characters. */ if (reqcu_not_found != NULL) set_jumps(reqcu_not_found, LABEL()); + if (limit_reached != NULL) + set_jumps(limit_reached, LABEL()); if (mode == PCRE2_JIT_PARTIAL_SOFT) CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1, diff --git a/src/pcre2_jit_test.c b/src/pcre2_jit_test.c index 652844301..3cddd11ca 100644 --- a/src/pcre2_jit_test.c +++ b/src/pcre2_jit_test.c @@ -660,6 +660,19 @@ static struct regression_test_case regression_test_cases[] = { { MU, A, 0, 0, "(?(?..)(?P..)\\k{2,4}", "AaAAAaAaAaA" }, { M | PCRE2_DUPNAMES, A, PCRE2_PARTIAL_HARD, 0, "^(?P..)(?P..)\\k{2,4}", "AaAAAaAaAaa" }, + { MU, A, PCRE2_PARTIAL_SOFT, 0, "\\R(*F)", "\r" }, + { MU, A, PCRE2_PARTIAL_SOFT, 0, "(?:\\R|z)(*F)", "\r" }, + { MU, A, PCRE2_PARTIAL_SOFT, 0, "(?=(?!\\R)?})", "\r" }, + { MU, A, PCRE2_PARTIAL_SOFT, 0 | F_NOMATCH, "(?end_subject && *Feptr == CHAR_LF) + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + } + else if (*Feptr == CHAR_LF) + { Feptr++; + } break; case CHAR_LF: @@ -3937,8 +3943,14 @@ match(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, uint16_t top_bracket, PCRE2 RRETURN(MATCH_NOMATCH); case CHAR_CR: - if (Feptr < mb->end_subject && *Feptr == CHAR_LF) + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + } + else if (*Feptr == CHAR_LF) + { Feptr++; + } break; case CHAR_LF: @@ -4568,8 +4580,14 @@ match(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, uint16_t top_bracket, PCRE2 RRETURN(MATCH_NOMATCH); case CHAR_CR: - if (Feptr < mb->end_subject && *Feptr == CHAR_LF) + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + } + else if (*Feptr == CHAR_LF) + { Feptr++; + } break; case CHAR_LF: @@ -4717,8 +4735,14 @@ match(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, uint16_t top_bracket, PCRE2 RRETURN(MATCH_NOMATCH); case CHAR_CR: - if (Feptr < mb->end_subject && *Feptr == CHAR_LF) + if (Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); + } + else if (*Feptr == CHAR_LF) + { Feptr++; + } break; case CHAR_LF: @@ -5332,7 +5356,10 @@ match(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, uint16_t top_bracket, PCRE2 if (fc == CHAR_CR) { if (++Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); break; + } if (*Feptr == CHAR_LF) Feptr++; } @@ -5607,7 +5634,10 @@ match(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, uint16_t top_bracket, PCRE2 if (fc == CHAR_CR) { if (++Feptr >= mb->end_subject) + { + SCHECK_PARTIAL(); break; + } if (*Feptr == CHAR_LF) Feptr++; } @@ -5938,8 +5968,10 @@ match(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, uint16_t top_bracket, PCRE2 if (rrc != 0) { if (rrc > 0) + { Feptr = mb->end_subject; // Partial match - CHECK_PARTIAL(); + CHECK_PARTIAL(); + } RRETURN(MATCH_NOMATCH); } } @@ -5975,8 +6007,10 @@ match(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, uint16_t top_bracket, PCRE2 if (rrc != 0) { if (rrc > 0) + { Feptr = mb->end_subject; // Partial match - CHECK_PARTIAL(); + CHECK_PARTIAL(); + } RRETURN(MATCH_NOMATCH); } @@ -6004,8 +6038,10 @@ match(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, uint16_t top_bracket, PCRE2 if (rrc != 0) { if (rrc > 0) + { Feptr = mb->end_subject; // Partial match - CHECK_PARTIAL(); + CHECK_PARTIAL(); + } RRETURN(MATCH_NOMATCH); } @@ -8404,8 +8440,8 @@ pcre2_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, PCRE2 { if (has_first_cu || start_bits != NULL) { - BOOL ok = start_match < end_subject; - if (ok) + BOOL ok = start_match < end_subject || mb->partial != 0; + if (start_match < end_subject) { PCRE2_UCHAR c = *start_match; ok = has_first_cu && (c == first_cu || c == first_cu2); diff --git a/testdata/testinput10 b/testdata/testinput10 index 3886b38f4..1bf5a8119 100644 --- a/testdata/testinput10 +++ b/testdata/testinput10 @@ -749,4 +749,9 @@ /[\x00-\x2f\x11-\xff]{4,}/B,utf abcd +/\b/utf,use_offset_limit + \x{300}\x{4e2d}\x{1f600}1\=offset_limit=9 +\= Expect no match + \x{300}\x{4e2d}\x{1f600}1\=offset_limit=6 + # End of testinput10 diff --git a/testdata/testinput12 b/testdata/testinput12 index c4a89a263..0df1e480f 100644 --- a/testdata/testinput12 +++ b/testdata/testinput12 @@ -743,4 +743,7 @@ # --------------------------------------------------------- +/(?<=\x{1f600})/utf,use_offset_limit + \x{1f600}\x{1f600}\=offset_limit=1 + # End of testinput12 diff --git a/testdata/testinput2 b/testdata/testinput2 index bfa443fb9..3403d22e8 100644 --- a/testdata/testinput2 +++ b/testdata/testinput2 @@ -6217,6 +6217,55 @@ a)"xI /(*naplb:ab?c|PQ).../g abcdefgacxyzPQR123 +/y(? not fixed length) @@ -8414,4 +8463,92 @@ a)"xI abc\=ps,substitute_replacement_only,replace=>$_< abc\=ps,substitute_replacement_only,replace=>$'< +/(?<=a?(*THEN)(?<=e)|x)B/ +\= Expect no match + eBx + +/(?<=x|a?(*THEN)(?<=e))B/ +\= Expect no match + eBx + +/((*naplb:(a)?(*THEN)))[a-c]/ +\= Expect no match + eb + +/(?!(?=(*THEN)(*F))?)/ +\= Expect no match + x + +/(?!(?<=a?(*THEN))?)b/ +\= Expect no match + xb + +/(*naplb:(?(?=x)a))/B + ae\=offset=2 + aee\=offset=2 + +/(?<=(?(?=e)a))/ + ae\=offset=2 + +/(? not fixed length) @@ -23837,6 +23909,139 @@ Failed: error -76 at offset 3 in replacement: replacement $' or $_ not supported Failed: error -76 at offset 3 in replacement: replacement $' or $_ not supported with partial match here: >$' |<--| < +/(?<=a?(*THEN)(?<=e)|x)B/ +\= Expect no match + eBx +No match + +/(?<=x|a?(*THEN)(?<=e))B/ +\= Expect no match + eBx +No match + +/((*naplb:(a)?(*THEN)))[a-c]/ +\= Expect no match + eb +No match + +/(?!(?=(*THEN)(*F))?)/ +\= Expect no match + x +No match + +/(?!(?<=a?(*THEN))?)b/ +\= Expect no match + xb +No match + +/(*naplb:(?(?=x)a))/B +------------------------------------------------------------------ + Bra + Non-atomic assert back + 0 VReverse 1 + Cond + Assert + x + Ket + a + Ket + Ket + Ket + End +------------------------------------------------------------------ + ae\=offset=2 + 0: + aee\=offset=2 + 0: + +/(?<=(?(?=e)a))/ + ae\=offset=2 + 0: + +/(?