Skip to content

Commit 2111ee3

Browse files
committed
Refactoring, bugs & leaks
1 parent ccf15cf commit 2111ee3

File tree

1 file changed

+97
-52
lines changed

1 file changed

+97
-52
lines changed

ext/standard/string.c

Lines changed: 97 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2863,7 +2863,91 @@ static int php_strtr_compare_hash_suffix(const void *a, const void *b, void *ctx
28632863
hash_b = php_strtr_hash(&S(&pnr_b->pat)[res->m - res->B], res->B)
28642864
& res->hash->table_mask;
28652865
/* TODO: don't recalculate the hashes all the time */
2866-
return hash_a - hash_b;
2866+
if (hash_a > hash_b) {
2867+
return 1;
2868+
} else if (hash_a < hash_b) {
2869+
return -1;
2870+
} else {
2871+
/* longer patterns must be sorted first */
2872+
if (L(&pnr_a->pat) > L(&pnr_b->pat)) {
2873+
return -1;
2874+
} else if (L(&pnr_a->pat) < L(&pnr_b->pat)) {
2875+
return 1;
2876+
} else {
2877+
return 0;
2878+
}
2879+
}
2880+
}
2881+
/* }}} */
2882+
/* {{{ php_strtr_free_strp */
2883+
static void php_strtr_free_strp(void *strp)
2884+
{
2885+
STR_FREE(*(char**)strp);
2886+
}
2887+
/* }}} */
2888+
/* {{{ php_strtr_array_prepare_repls */
2889+
static PATNREPL *php_strtr_array_prepare_repls(int slen, HashTable *pats, zend_llist **allocs, int *outsize)
2890+
{
2891+
PATNREPL *patterns;
2892+
HashPosition hpos;
2893+
zval **entry;
2894+
int num_pats = zend_hash_num_elements(pats),
2895+
i;
2896+
2897+
patterns = safe_emalloc(num_pats, sizeof(*patterns), 0);
2898+
*allocs = emalloc(sizeof **allocs);
2899+
zend_llist_init(*allocs, sizeof(void*), &php_strtr_free_strp, 0);
2900+
2901+
for (i = 0, zend_hash_internal_pointer_reset_ex(pats, &hpos);
2902+
zend_hash_get_current_data_ex(pats, (void **)&entry, &hpos) == SUCCESS;
2903+
zend_hash_move_forward_ex(pats, &hpos)) {
2904+
char *string_key;
2905+
uint string_key_len;
2906+
ulong num_key;
2907+
zval *tzv = NULL;
2908+
2909+
switch (zend_hash_get_current_key_ex(pats, &string_key, &string_key_len, &num_key, 0, &hpos)) {
2910+
case HASH_KEY_IS_LONG:
2911+
string_key_len = 1 + zend_spprintf(&string_key, 0, "%ld", (long)num_key);
2912+
zend_llist_add_element(*allocs, &string_key);
2913+
/* break missing intentionally */
2914+
2915+
case HASH_KEY_IS_STRING:
2916+
string_key_len--; /* exclude final '\0' */
2917+
if (string_key_len == 0) { /* empty string given as pattern */
2918+
efree(patterns);
2919+
zend_llist_destroy(*allocs);
2920+
efree(*allocs);
2921+
*allocs = NULL;
2922+
return NULL;
2923+
}
2924+
if (string_key_len > slen) { /* this pattern can never match */
2925+
continue;
2926+
}
2927+
2928+
if (Z_TYPE_PP(entry) != IS_STRING) {
2929+
tzv = *entry;
2930+
zval_addref_p(tzv);
2931+
SEPARATE_ZVAL(&tzv);
2932+
convert_to_string(tzv);
2933+
entry = &tzv;
2934+
zend_llist_add_element(*allocs, &Z_STRVAL_PP(entry));
2935+
}
2936+
2937+
S(&patterns[i].pat) = string_key;
2938+
L(&patterns[i].pat) = string_key_len;
2939+
S(&patterns[i].repl) = Z_STRVAL_PP(entry);
2940+
L(&patterns[i].repl) = Z_STRLEN_PP(entry);
2941+
i++;
2942+
2943+
if (tzv) {
2944+
efree(tzv);
2945+
}
2946+
}
2947+
}
2948+
2949+
*outsize = i;
2950+
return patterns;
28672951
}
28682952
/* }}} */
28692953

@@ -2952,7 +3036,7 @@ static void php_strtr_array_do_repl(STR *text, PPRES *d, zval *return_value)
29523036
STRLEN shift = d->shift->entries[h];
29533037

29543038
if (shift > 0) {
2955-
smart_str_appendl(&result, &S(text)[pos], shift);
3039+
smart_str_appendl(&result, &S(text)[pos], MIN(shift, L(text) - pos));
29563040
pos += shift;
29573041
} else {
29583042
HASH h2 = h & d->hash->table_mask,
@@ -2999,64 +3083,25 @@ end_outer_loop: ;
29993083
/* {{{ php_strtr_array */
30003084
static void php_strtr_array(zval *return_value, char *str, int slen, HashTable *pats)
30013085
{
3002-
PPRES *data;
3003-
STR text;
3004-
PATNREPL *patterns;
3005-
HashPosition hpos;
3006-
zval **entry;
3007-
int num_pats = zend_hash_num_elements(pats),
3008-
i;
3086+
PPRES *data;
3087+
STR text;
3088+
PATNREPL *patterns;
3089+
int patterns_len;
3090+
zend_llist *allocs;
30093091

30103092
S(&text) = str;
30113093
L(&text) = slen;
3012-
patterns = safe_emalloc(num_pats, sizeof(*patterns), 0);
3013-
3014-
for (i = 0, zend_hash_internal_pointer_reset_ex(pats, &hpos);
3015-
zend_hash_get_current_data_ex(pats, (void **)&entry, &hpos) == SUCCESS;
3016-
i++, zend_hash_move_forward_ex(pats, &hpos)) {
3017-
char *string_key;
3018-
uint string_key_len;
3019-
ulong num_key;
3020-
int free_str = 0,
3021-
free_repl = 0;
3022-
zval *tzv;
3023-
3024-
switch (zend_hash_get_current_key_ex(pats, &string_key, &string_key_len, &num_key, 0, &hpos)) {
3025-
case HASH_KEY_IS_LONG:
3026-
string_key_len = 1 + zend_spprintf(&string_key, 0, "%ld", (long)num_key);
3027-
free_str = 1;
3028-
/* break missing intentionally */
30293094

3030-
case HASH_KEY_IS_STRING:
3031-
string_key_len--; /* exclude final '\0' */
3032-
if (string_key_len == 0) { /* empty string given as pattern */
3033-
efree(patterns);
3034-
RETURN_FALSE;
3035-
}
3036-
if (string_key_len > slen) { /* this pattern can never match */
3037-
continue;
3038-
}
3039-
3040-
if (Z_TYPE_PP(entry) != IS_STRING) {
3041-
tzv = *entry;
3042-
zval_addref_p(tzv);
3043-
SEPARATE_ZVAL(&tzv);
3044-
convert_to_string(tzv);
3045-
entry = &tzv;
3046-
free_repl = 1;
3047-
}
3048-
3049-
S(&patterns[i].pat) = string_key;
3050-
L(&patterns[i].pat) = string_key_len;
3051-
S(&patterns[i].repl) = Z_STRVAL_PP(entry);
3052-
L(&patterns[i].repl) = Z_STRLEN_PP(entry);
3053-
}
3095+
patterns = php_strtr_array_prepare_repls(slen, pats, &allocs, &patterns_len);
3096+
if (patterns == NULL) {
3097+
RETURN_FALSE;
30543098
}
3055-
3056-
data = php_strtr_array_prepare(&text, patterns, i, 2, 2);
3099+
data = php_strtr_array_prepare(&text, patterns, patterns_len, 2, 2);
30573100
efree(patterns);
30583101
php_strtr_array_do_repl(&text, data, return_value);
30593102
php_strtr_array_destroy_ppres(data);
3103+
zend_llist_destroy(allocs);
3104+
efree(allocs);
30603105
}
30613106
/* }}} */
30623107

0 commit comments

Comments
 (0)