]> granicus.if.org Git - php/commitdiff
Fix memory leaks in browscap parsing
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 21 Jun 2019 10:10:09 +0000 (12:10 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 21 Jun 2019 10:56:37 +0000 (12:56 +0200)
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.

ext/standard/browscap.c

index 237517c91f554fb8e814c8977041795685bab58c..e489ea1424c3662c5662f7ba29c22ffd5a08aeee 100644 (file)
@@ -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);