--- embedaddon/php/ext/pcre/php_pcre.c 2012/02/21 23:47:59 1.1.1.1 +++ embedaddon/php/ext/pcre/php_pcre.c 2014/06/15 20:03:52 1.1.1.4 @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2012 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_pcre.c,v 1.1.1.1 2012/02/21 23:47:59 misho Exp $ */ +/* $Id: php_pcre.c,v 1.1.1.4 2014/06/15 20:03:52 misho Exp $ */ #include "php.h" #include "php_ini.h" @@ -244,11 +244,19 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache int count = 0; unsigned const char *tables = NULL; #if HAVE_SETLOCALE - char *locale = setlocale(LC_CTYPE, NULL); + char *locale; #endif pcre_cache_entry *pce; pcre_cache_entry new_entry; + char *tmp = NULL; +#if HAVE_SETLOCALE +# if defined(PHP_WIN32) && defined(ZTS) + _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); +# endif + locale = setlocale(LC_CTYPE, NULL); +#endif + /* Try to lookup the cached regex entry, and if successful, just pass back the compiled pattern, otherwise go on and compile it. */ if (zend_hash_find(&PCRE_G(pcre_cache), regex, regex_len+1, (void **)&pce) == SUCCESS) { @@ -275,7 +283,8 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache 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; } @@ -292,21 +301,18 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache 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 @@ -314,7 +320,6 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache * 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) @@ -323,10 +328,17 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache 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. */ @@ -337,7 +349,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache /* 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; @@ -368,7 +380,11 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache 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; } @@ -430,9 +446,26 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache 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; } /* }}} */ @@ -507,7 +540,7 @@ static void php_do_pcre_match(INTERNAL_FUNCTION_PARAME 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; } @@ -609,7 +642,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, 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