diff options
Diffstat (limited to 'ext/pcre/php_pcre.c')
-rw-r--r-- | ext/pcre/php_pcre.c | 64 |
1 files changed, 45 insertions, 19 deletions
diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index cab3a4c8dd..20fb2a20b3 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -248,6 +248,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le #endif pcre_cache_entry *pce; pcre_cache_entry new_entry; + char *tmp = NULL; #if HAVE_SETLOCALE # ifdef PHP_WIN32 && ZTS @@ -282,7 +283,8 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le get to the end without encountering a delimiter. */ while (isspace((int)*(unsigned char *)p)) p++; if (*p == 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty regular expression"); + php_error_docref(NULL TSRMLS_CC, E_WARNING, + p < regex + regex_len ? "Null byte in regex" : "Empty regular expression"); return NULL; } @@ -299,21 +301,18 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le delimiter = pp[5]; end_delimiter = delimiter; + pp = p; + if (start_delimiter == end_delimiter) { /* We need to iterate through the pattern, searching for the ending delimiter, but skipping the backslashed delimiters. If the ending delimiter is not found, display a warning. */ - pp = p; while (*pp != 0) { if (*pp == '\\' && pp[1] != 0) pp++; else if (*pp == delimiter) break; pp++; } - if (*pp == 0) { - php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending delimiter '%c' found", delimiter); - return NULL; - } } else { /* We iterate through the pattern, searching for the matching ending * delimiter. For each matching starting delimiter, we increment nesting @@ -321,7 +320,6 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le * reach the end of the pattern without matching, display a warning. */ int brackets = 1; /* brackets nesting level */ - pp = p; while (*pp != 0) { if (*pp == '\\' && pp[1] != 0) pp++; else if (*pp == end_delimiter && --brackets <= 0) @@ -330,10 +328,17 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le brackets++; pp++; } - if (*pp == 0) { - php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending matching delimiter '%c' found", end_delimiter); - return NULL; + } + + if (*pp == 0) { + if (pp < regex + regex_len) { + php_error_docref(NULL TSRMLS_CC,E_WARNING, "Null byte in regex"); + } else if (start_delimiter == end_delimiter) { + php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending delimiter '%c' found", delimiter); + } else { + php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending matching delimiter '%c' found", delimiter); } + return NULL; } /* Make a copy of the actual pattern. */ @@ -344,7 +349,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le /* Parse through the options, setting appropriate flags. Display a warning if we encounter an unknown modifier. */ - while (*pp != 0) { + while (pp < regex + regex_len) { switch (*pp++) { /* Perl compatible options */ case 'i': coptions |= PCRE_CASELESS; break; @@ -375,7 +380,11 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le break; default: - php_error_docref(NULL TSRMLS_CC,E_WARNING, "Unknown modifier '%c'", pp[-1]); + if (pp[-1]) { + php_error_docref(NULL TSRMLS_CC,E_WARNING, "Unknown modifier '%c'", pp[-1]); + } else { + php_error_docref(NULL TSRMLS_CC,E_WARNING, "Null byte in regex"); + } efree(pattern); return NULL; } @@ -437,9 +446,26 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le new_entry.locale = pestrdup(locale, 1); new_entry.tables = tables; #endif + + /* + * Interned strings are not duplicated when stored in HashTable, + * but all the interned strings created during HTTP request are removed + * at end of request. However PCRE_G(pcre_cache) must be consistent + * on the next request as well. So we disable usage of interned strings + * as hash keys especually for this table. + * See bug #63180 + */ + if (IS_INTERNED(regex)) { + regex = tmp = estrndup(regex, regex_len); + } + zend_hash_update(&PCRE_G(pcre_cache), regex, regex_len+1, (void *)&new_entry, sizeof(pcre_cache_entry), (void**)&pce); + if (tmp) { + efree(tmp); + } + return pce; } /* }}} */ @@ -514,7 +540,7 @@ static void php_do_pcre_match(INTERNAL_FUNCTION_PARAMETERS, int global) /* {{{ * long flags = 0; /* Match control flags */ long start_offset = 0; /* Where the new search starts */ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, ((global) ? "ssz|ll" : "ss|zll"), ®ex, ®ex_len, + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|zll", ®ex, ®ex_len, &subject, &subject_len, &subpats, &flags, &start_offset) == FAILURE) { RETURN_FALSE; } @@ -616,7 +642,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, char *subject, int subjec offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0); /* Allocate match sets array and initialize the values. */ - if (global && subpats_order == PREG_PATTERN_ORDER) { + if (global && subpats && subpats_order == PREG_PATTERN_ORDER) { match_sets = (zval **)safe_emalloc(num_subpats, sizeof(zval *), 0); for (i=0; i<num_subpats; i++) { ALLOC_ZVAL(match_sets[i]); @@ -658,7 +684,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, char *subject, int subjec } if (global) { /* global pattern matching */ - if (subpats_order == PREG_PATTERN_ORDER) { + if (subpats && subpats_order == PREG_PATTERN_ORDER) { /* For each subpattern, insert it into the appropriate array. */ for (i = 0; i < count; i++) { if (offset_capture) { @@ -748,7 +774,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, char *subject, int subjec } while (global); /* Add the match sets to the output array and clean up */ - if (global && subpats_order == PREG_PATTERN_ORDER) { + if (global && subpats && subpats_order == PREG_PATTERN_ORDER) { for (i = 0; i < num_subpats; i++) { if (subpat_names[i]) { zend_hash_update(Z_ARRVAL_P(subpats), subpat_names[i], @@ -780,7 +806,7 @@ static PHP_FUNCTION(preg_match) } /* }}} */ -/* {{{ proto int preg_match_all(string pattern, string subject, array &subpatterns [, int flags [, int offset]]) +/* {{{ proto int preg_match_all(string pattern, string subject [, array &subpatterns [, int flags [, int offset]]]) Perform a Perl-style global regular expression match */ static PHP_FUNCTION(preg_match_all) { @@ -907,7 +933,7 @@ static int preg_do_eval(char *eval_str, int eval_str_len, char *subject, match = subject + offsets[backref<<1]; match_len = offsets[(backref<<1)+1] - offsets[backref<<1]; if (match_len) { - esc_match = php_addslashes_ex(match, match_len, &esc_match_len, 0, 1 TSRMLS_CC); + esc_match = php_addslashes(match, match_len, &esc_match_len, 0 TSRMLS_CC); } else { esc_match = match; esc_match_len = 0; @@ -1847,7 +1873,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_preg_match, 0, 0, 2) ZEND_ARG_INFO(0, offset) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_preg_match_all, 0, 0, 3) +ZEND_BEGIN_ARG_INFO_EX(arginfo_preg_match_all, 0, 0, 2) ZEND_ARG_INFO(0, pattern) ZEND_ARG_INFO(0, subject) ZEND_ARG_INFO(1, subpatterns) /* array */ |