diff options
author | George Greer <perl@greerga.m-l.org> | 2013-03-11 21:39:13 -0600 |
---|---|---|
committer | Karl Williamson <public@khwilliamson.com> | 2013-03-12 16:06:47 -0600 |
commit | 9b139d09af7013f395939ac80e537edd55bb404a (patch) | |
tree | 1b56effbb030753d7f0b64115f1434e7169b908f | |
parent | 46391258eca955edb5120d04f4c8fc6a1b087124 (diff) | |
download | perl-9b139d09af7013f395939ac80e537edd55bb404a.tar.gz |
Fix some ASAN-identified problems
Clang under Address sanitizer is showing several problems when building
Perl, having to do when a limit reaches I32_MAX. This commit fixes
those problems by doing special tests for I32_MAX, and preventing
overflow.
-rw-r--r-- | regcomp.c | 47 | ||||
-rw-r--r-- | scope.c | 4 |
2 files changed, 35 insertions, 16 deletions
@@ -749,7 +749,7 @@ S_scan_commit(pTHX_ const RExC_state_t *pRExC_state, scan_data_t *data, I32 *min data->offset_float_min = l ? data->last_start_min : data->pos_min; data->offset_float_max = (l ? data->last_start_max - : data->pos_min + data->pos_delta); + : (data->pos_delta == I32_MAX ? I32_MAX : data->pos_min + data->pos_delta)); if (is_inf || (U32)data->offset_float_max > (U32)I32_MAX) data->offset_float_max = I32_MAX; if (data->flags & SF_BEFORE_EOL) @@ -3126,10 +3126,11 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, stopparen, recursed, NULL, f,depth+1); if (min1 > minnext) min1 = minnext; - if (max1 < minnext + deltanext) - max1 = minnext + deltanext; - if (deltanext == I32_MAX) + if (deltanext == I32_MAX) { is_inf = is_inf_internal = 1; + max1 = I32_MAX; + } else if (max1 < minnext + deltanext) + max1 = minnext + deltanext; scan = next; if (data_fake.flags & (SF_HAS_PAR|SF_IN_PAR)) pars++; @@ -3152,12 +3153,18 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, min1 = 0; if (flags & SCF_DO_SUBSTR) { data->pos_min += min1; - data->pos_delta += max1 - min1; + if (data->pos_delta >= I32_MAX - (max1 - min1)) + data->pos_delta = I32_MAX; + else + data->pos_delta += max1 - min1; if (max1 != min1 || is_inf) data->longest = &(data->longest_float); } min += min1; - delta += max1 - min1; + if (delta == I32_MAX || I32_MAX - delta - (max1 - min1) < 0) + delta = I32_MAX; + else + delta += max1 - min1; if (flags & SCF_DO_STCLASS_OR) { cl_or(pRExC_state, data->start_class, &accum); if (min1) { @@ -3886,11 +3893,13 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, } min += minnext * mincount; - is_inf_internal |= ((maxcount == REG_INFTY - && (minnext + deltanext) > 0) - || deltanext == I32_MAX); + is_inf_internal |= deltanext == I32_MAX + || (maxcount == REG_INFTY && minnext + deltanext > 0); is_inf |= is_inf_internal; - delta += (minnext + deltanext) * maxcount - minnext * mincount; + if (is_inf) + delta = I32_MAX; + else + delta += (minnext + deltanext) * maxcount - minnext * mincount; /* Try powerful optimization CURLYX => CURLYN. */ if ( OP(oscan) == CURLYX && data @@ -4075,7 +4084,16 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, } /* It is counted once already... */ data->pos_min += minnext * (mincount - counted); - data->pos_delta += - counted * deltanext + +#if 0 +PerlIO_printf(Perl_debug_log, "counted=%d deltanext=%d I32_MAX=%d minnext=%d maxcount=%d mincount=%d\n", + counted, deltanext, I32_MAX, minnext, maxcount, mincount); +if (deltanext != I32_MAX) +PerlIO_printf(Perl_debug_log, "LHS=%d RHS=%d\n", -counted * deltanext + (minnext + deltanext) * maxcount - minnext * mincount, I32_MAX - data->pos_delta); +#endif + if (deltanext == I32_MAX || -counted * deltanext + (minnext + deltanext) * maxcount - minnext * mincount >= I32_MAX - data->pos_delta) + data->pos_delta = I32_MAX; + else + data->pos_delta += - counted * deltanext + (minnext + deltanext) * maxcount - minnext * mincount; if (mincount != maxcount) { /* Cannot extend fixed substrings found inside @@ -4593,10 +4611,11 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, if (min1 > (I32)(minnext + trie->minlen)) min1 = minnext + trie->minlen; - if (max1 < (I32)(minnext + deltanext + trie->maxlen)) - max1 = minnext + deltanext + trie->maxlen; - if (deltanext == I32_MAX) + if (deltanext == I32_MAX) { is_inf = is_inf_internal = 1; + max1 = I32_MAX; + } else if (max1 < (I32)(minnext + deltanext + trie->maxlen)) + max1 = minnext + deltanext + trie->maxlen; if (data_fake.flags & (SF_HAS_PAR|SF_IN_PAR)) pars++; @@ -394,7 +394,7 @@ Perl_save_int(pTHX_ int *intp) { dVAR; const int i = *intp; - UV type = ((UV)(i << SAVE_TIGHT_SHIFT) | SAVEt_INT_SMALL); + UV type = ((UV)((UV)i << SAVE_TIGHT_SHIFT) | SAVEt_INT_SMALL); int size = 2; dSS_ADD; @@ -441,7 +441,7 @@ Perl_save_I32(pTHX_ I32 *intp) { dVAR; const I32 i = *intp; - UV type = ((I32)(i << SAVE_TIGHT_SHIFT) | SAVEt_I32_SMALL); + UV type = ((I32)((U32)i << SAVE_TIGHT_SHIFT) | SAVEt_I32_SMALL); int size = 2; dSS_ADD; |