From: Nikita Popov Date: Fri, 21 Jun 2019 10:10:09 +0000 (+0200) Subject: Fix memory leaks in browscap parsing X-Git-Tag: php-7.4.0alpha2~16 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1de7c4b91941347d1a5fc4a9d2990601b6d33fe7;p=php Fix memory leaks in browscap parsing Also make the interning a bit more efficient, no need to check for a "real" interned string every time, we can also store that in the HT. --- diff --git a/ext/standard/browscap.c b/ext/standard/browscap.c index 237517c91f..e489ea1424 100644 --- a/ext/standard/browscap.c +++ b/ext/standard/browscap.c @@ -223,12 +223,15 @@ typedef struct _browscap_parser_ctx { } browscap_parser_ctx; static zend_string *browscap_intern_str( - browscap_parser_ctx *ctx, zend_string *str) { + browscap_parser_ctx *ctx, zend_string *str, zend_bool persistent) { zend_string *interned = zend_hash_find_ptr(&ctx->str_interned, str); if (interned) { zend_string_addref(interned); } else { interned = zend_string_copy(str); + if (persistent) { + interned = zend_new_interned_string(str); + } zend_hash_add_new_ptr(&ctx->str_interned, interned, interned); } @@ -249,6 +252,9 @@ static zend_string *browscap_intern_str_ci( zend_string_addref(interned); } else { interned = zend_string_dup(lcname, persistent); + if (persistent) { + interned = zend_new_interned_string(interned); + } zend_hash_add_new_ptr(&ctx->str_interned, interned, interned); } @@ -322,18 +328,7 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb ) { new_value = ZSTR_EMPTY_ALLOC(); } else { /* Other than true/false setting */ - new_value = browscap_intern_str(ctx, Z_STR_P(arg2)); - - if (persistent) { - new_value = zend_new_interned_string(zend_string_copy(new_value)); - if (ZSTR_IS_INTERNED(new_value)) { - if (new_value == Z_STR_P(arg2)) { - Z_TYPE_FLAGS_P(arg2) = 0; - } - } else { - zend_string_release(new_value); - } - } + new_value = browscap_intern_str(ctx, Z_STR_P(arg2), persistent); } if (!strcasecmp(Z_STRVAL_P(arg1), "parent")) { @@ -354,18 +349,6 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb ctx->current_entry->parent = new_value; } else { new_key = browscap_intern_str_ci(ctx, Z_STR_P(arg1), persistent); - - if (persistent) { - new_key = zend_new_interned_string(zend_string_copy(new_key)); - if (ZSTR_IS_INTERNED(new_key)) { - if (new_key == Z_STR_P(arg1)) { - Z_TYPE_FLAGS_P(arg1) = 0; - } - } else { - zend_string_release(new_key); - } - } - browscap_add_kv(bdata, new_key, new_value, persistent); ctx->current_entry->kv_end = bdata->kv_used; } @@ -417,6 +400,10 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb } /* }}} */ +static void str_interned_dtor(zval *zv) { + zend_string_release(Z_STR_P(zv)); +} + static int browscap_read_file(char *filename, browser_data *browdata, int persistent) /* {{{ */ { zend_file_handle fh; @@ -449,7 +436,7 @@ static int browscap_read_file(char *filename, browser_data *browdata, int persis ctx.bdata = browdata; ctx.current_entry = NULL; ctx.current_section_name = NULL; - zend_hash_init(&ctx.str_interned, 8, NULL, NULL, persistent); + zend_hash_init(&ctx.str_interned, 8, NULL, str_interned_dtor, persistent); zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_RAW, (zend_ini_parser_cb_t) php_browscap_parser_cb, &ctx);