From: Scott MacVicar Date: Fri, 29 May 2009 00:03:28 +0000 (+0000) Subject: MFH: Fix bug #48416 - Force a cache size for ereg to stop it getting out of control... X-Git-Tag: php-5.2.10RC2~64 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4b5eda20ae8c8398f57338e3da4813673a05c96a;p=php MFH: Fix bug #48416 - Force a cache size for ereg to stop it getting out of control. Lazy LRU here. --- diff --git a/ext/standard/reg.c b/ext/standard/reg.c index 5a05983568..b37630f9c2 100644 --- a/ext/standard/reg.c +++ b/ext/standard/reg.c @@ -31,9 +31,43 @@ ZEND_DECLARE_MODULE_GLOBALS(reg) typedef struct { regex_t preg; int cflags; + unsigned int lastuse; } reg_cache; static int reg_magic = 0; +#define EREG_CACHE_SIZE 4096 + +/* {{{ ereg_lru_cmp */ +static int ereg_lru_cmp(const void *a, const void *b TSRMLS_DC) +{ + Bucket *f = *((Bucket **) a); + Bucket *s = *((Bucket **) b); + + if (((reg_cache *)f->pData)->lastuse < + ((reg_cache *)s->pData)->lastuse) { + return -1; + } else if (((reg_cache *)f->pData)->lastuse == + ((reg_cache *)s->pData)->lastuse) { + return 0; + } else { + return 1; + } +} +/* }}} */ + +/* {{{ static ereg_clean_cache */ +static int ereg_clean_cache(void *data, void *arg TSRMLS_DC) +{ + int *num_clean = (int *)arg; + + if (*num_clean > 0) { + (*num_clean)--; + return ZEND_HASH_APPLY_REMOVE; + } else { + return ZEND_HASH_APPLY_STOP; + } +} +/* }}} */ /* {{{ _php_regcomp */ @@ -43,7 +77,17 @@ static int _php_regcomp(regex_t *preg, const char *pattern, int cflags) int patlen = strlen(pattern); reg_cache *rc = NULL; TSRMLS_FETCH(); - + + if (zend_hash_num_elements(®(ht_rc)) >= EREG_CACHE_SIZE) { + if (REG(lru_counter) >= (1 << 31) || zend_hash_sort(®(ht_rc), zend_qsort, ereg_lru_cmp, 0 TSRMLS_CC) == FAILURE) { + zend_hash_clean(®(ht_rc)); + REG(lru_counter) = 0; + } else { + int num_clean = EREG_CACHE_SIZE / 2; + zend_hash_apply_with_argument(®(ht_rc), ereg_clean_cache, &num_clean TSRMLS_CC); + } + } + if(zend_hash_find(®(ht_rc), (char *) pattern, patlen+1, (void **) &rc) == SUCCESS && rc->cflags == cflags) { #ifdef HAVE_REGEX_T_RE_MAGIC @@ -53,6 +97,7 @@ static int _php_regcomp(regex_t *preg, const char *pattern, int cflags) */ if (rc->preg.re_magic != reg_magic) { zend_hash_clean(®(ht_rc)); + REG(lru_counter) = 0; } else { memcpy(preg, &rc->preg, sizeof(*preg)); return r; @@ -64,6 +109,7 @@ static int _php_regcomp(regex_t *preg, const char *pattern, int cflags) reg_cache rcp; rcp.cflags = cflags; + rcp.lastuse = ++(REG(lru_counter)); memcpy(&rcp.preg, preg, sizeof(*preg)); /* * Since we don't have access to the actual MAGIC1 definition in the private @@ -82,6 +128,7 @@ static int _php_regcomp(regex_t *preg, const char *pattern, int cflags) reg_cache rcp; rcp.cflags = cflags; + rcp.lastuse = ++(REG(lru_counter)); memcpy(&rcp.preg, preg, sizeof(*preg)); zend_hash_update(®(ht_rc), (char *) pattern, patlen+1, (void *) &rcp, sizeof(rcp), NULL); @@ -105,6 +152,7 @@ static void _free_reg_cache(reg_cache *rc) static void php_reg_init_globals(zend_reg_globals *reg_globals TSRMLS_DC) { zend_hash_init(®_globals->ht_rc, 0, NULL, (void (*)(void *)) _free_reg_cache, 1); + reg_globals->lru_counter = 0; } static void php_reg_destroy_globals(zend_reg_globals *reg_globals TSRMLS_DC) diff --git a/ext/standard/reg.h b/ext/standard/reg.h index 0b6b6378f6..28ada1d10c 100644 --- a/ext/standard/reg.h +++ b/ext/standard/reg.h @@ -34,6 +34,7 @@ PHPAPI PHP_FUNCTION(sql_regcase); ZEND_BEGIN_MODULE_GLOBALS(reg) HashTable ht_rc; + unsigned int lru_counter; ZEND_END_MODULE_GLOBALS(reg) PHP_MINIT_FUNCTION(regex);