diff options
author | David Mitchell <davem@iabyn.com> | 2017-06-16 15:46:19 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2017-06-16 15:46:19 +0100 |
commit | bb152a4b442f7718fd37d32cc558be675e8ae1ae (patch) | |
tree | e11cac104d1b6f97cb88028da323c0c891a5cb61 | |
parent | 9a4e033ca5abe2a94a5b47e25968106278ede709 (diff) | |
download | perl-bb152a4b442f7718fd37d32cc558be675e8ae1ae.tar.gz |
don't call Perl_fbm_instr() with negative length
RT #131575
re_intuit_start() could calculate a maximum end position less than the
current start position. This used to get rejected by fbm_intr(), until
v5.23.3-110-g147f21b, which made fbm_intr() faster and removed unnecessary
checks.
This commits fixes re_intuit_start(), and adds an assert to fbm_intr().
-rw-r--r-- | regexec.c | 17 | ||||
-rw-r--r-- | t/re/pat.t | 13 | ||||
-rw-r--r-- | util.c | 2 |
3 files changed, 25 insertions, 7 deletions
@@ -126,13 +126,16 @@ static const char* const non_utf8_target_but_utf8_required (U8*)(off >= 0 ? reginfo->strend : reginfo->strbeg)) \ : (U8*)(pos + off)) -#define HOPBACKc(pos, off) \ - (char*)(reginfo->is_utf8_target \ - ? reghopmaybe3((U8*)pos, (SSize_t)0-off, (U8*)(reginfo->strbeg)) \ - : (pos - off >= reginfo->strbeg) \ - ? (U8*)pos - off \ +/* like HOPMAYBE3 but backwards. lim must be +ve. Returns NULL on overshoot */ +#define HOPBACK3(pos, off, lim) \ + (reginfo->is_utf8_target \ + ? reghopmaybe3((U8*)pos, (SSize_t)0-off, (U8*)(lim)) \ + : (pos - off >= lim) \ + ? (U8*)pos - off \ : NULL) +#define HOPBACKc(pos, off) ((char*)HOPBACK3(pos, off, reginfo->strbeg)) + #define HOP3(pos,off,lim) (reginfo->is_utf8_target ? reghop3((U8*)(pos), off, (U8*)(lim)) : (U8*)(pos + off)) #define HOP3c(pos,off,lim) ((char*)HOP3(pos,off,lim)) @@ -884,7 +887,9 @@ Perl_re_intuit_start(pTHX_ (IV)prog->check_end_shift); }); - end_point = HOP3(strend, -end_shift, strbeg); + end_point = HOPBACK3(strend, end_shift, rx_origin); + if (!end_point) + goto fail_finish; start_point = HOPMAYBE3(rx_origin, start_shift, end_point); if (!start_point) goto fail_finish; diff --git a/t/re/pat.t b/t/re/pat.t index 3ac95e91cf..fb6d4c4a69 100644 --- a/t/re/pat.t +++ b/t/re/pat.t @@ -23,7 +23,7 @@ BEGIN { skip_all('no re module') unless defined &DynaLoader::boot_DynaLoader; skip_all_without_unicode_tables(); -plan tests => 836; # Update this when adding/deleting tests. +plan tests => 837; # Update this when adding/deleting tests. run_tests() unless caller; @@ -1906,6 +1906,17 @@ EOP # [perl #129281] buffer write overflow, detected by ASAN, valgrind fresh_perl_is('/0(?0)|^*0(?0)|^*(^*())0|/', '', {}, "don't bump whilem_c too much"); } + + { + # RT #131575 intuit skipping back from the end to find the highest + # possible start point, was potentially hopping back beyond pos() + # and crashing by calling fbm_instr with a negative length + + my $text = "=t=\x{5000}"; + pos($text) = 3; + ok(scalar($text !~ m{(~*=[a-z]=)}g), "RT #131575"); + } + } # End of sub run_tests 1; @@ -816,6 +816,8 @@ Perl_fbm_instr(pTHX_ unsigned char *big, unsigned char *bigend, SV *littlestr, U PERL_ARGS_ASSERT_FBM_INSTR; + assert(bigend >= big); + if ((STRLEN)(bigend - big) < littlelen) { if ( tail && ((STRLEN)(bigend - big) == littlelen - 1) |