From 311367620ac98ca141d904252ad98b0f3524a991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 17:22:56 +0200 Subject: [PATCH 01/17] girepository/build: Actually use our compiler to generate GLib typelibs We are overriding the default g-ir-compiler for local usage, but this is not actually happen since that's computed while parsing introspection So generate the compiler as first thing, then in case handle the introspection data --- girepository/meson.build | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/girepository/meson.build b/girepository/meson.build index 3a17cf5c8..fa0adc631 100644 --- a/girepository/meson.build +++ b/girepository/meson.build @@ -240,6 +240,8 @@ pkg.generate(libgirepository, libraries: [libglib_dep, libgobject_dep], ) +subdir('compiler') + if enable_gir subdir('introspection') endif @@ -248,6 +250,5 @@ if build_tests subdir('tests') endif -subdir('compiler') subdir('decompiler') -subdir('inspector') \ No newline at end of file +subdir('inspector') From 47cf6387ad07e8997efbab14c0f1fb645600ece2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 17:24:49 +0200 Subject: [PATCH 02/17] girepository/compiler: Free the parser when not needed The compiler code was full of leaks and nothing really checked on them. While it's not a big deal per se, per the nature of it, it's still better to ensure that memory management is well done so that there are no problems when using it with sanitizers. So, the source of the problems was not freeing the parser, but that wasn't enough, more to come... --- girepository/compiler/compiler.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/girepository/compiler/compiler.c b/girepository/compiler/compiler.c index c786d4f5e..e9b1b1563 100644 --- a/girepository/compiler/compiler.c +++ b/girepository/compiler/compiler.c @@ -218,6 +218,7 @@ main (int argc, char **argv) char *message = g_strdup_printf (_("Error parsing file ā€˜%s’: %s"), input[0], error->message); g_fprintf (stderr, "%s\n", message); g_free (message); + gi_ir_parser_free (parser); return 1; } @@ -253,10 +254,7 @@ main (int argc, char **argv) g_debug ("[building] done"); -#if 0 - /* No point */ gi_ir_parser_free (parser); -#endif return 0; } From 1b8ef05321550b339668221c8757371c40db3d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 17:27:28 +0200 Subject: [PATCH 03/17] girepository/girmodule: Free the version, shared library and c prefix Those strings are explicitly duplicated but never free'd --- girepository/girmodule.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/girepository/girmodule.c b/girepository/girmodule.c index e595f7a46..6d1e89493 100644 --- a/girepository/girmodule.c +++ b/girepository/girmodule.c @@ -75,6 +75,9 @@ gi_ir_module_free (GIIrModule *module) GList *e; g_free (module->name); + g_free (module->version); + g_free (module->shared_library); + g_free (module->c_prefix); for (e = module->entries; e; e = e->next) gi_ir_node_free ((GIIrNode *)e->data); From 9f4b97bb923ac2bdcf53734d51402c5571146f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 17:28:17 +0200 Subject: [PATCH 04/17] girepository/girmodule: Cleanup the builder types hash keys We were adding new keys but never removing them, so use the proper destroy notify for them and clarify the ownership on the caller. --- girepository/girmodule.c | 2 +- girepository/girnode.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/girepository/girmodule.c b/girepository/girmodule.c index 6d1e89493..af416c3a2 100644 --- a/girepository/girmodule.c +++ b/girepository/girmodule.c @@ -374,7 +374,7 @@ gi_ir_module_build_typelib (GIIrModule *module) restart: gi_ir_node_init_stats (); strings = g_hash_table_new (g_str_hash, g_str_equal); - types = g_hash_table_new (g_str_hash, g_str_equal); + types = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); nodes_with_attributes = NULL; n_entries = g_list_length (module->entries); diff --git a/girepository/girnode.c b/girepository/girnode.c index b3ea89323..2bc84e8ba 100644 --- a/girepository/girnode.c +++ b/girepository/girnode.c @@ -1477,7 +1477,8 @@ gi_ir_node_build_typelib (GIIrNode *node, else { unique_types_count += 1; - g_hash_table_insert (types, s, GUINT_TO_POINTER(*offset2)); + g_hash_table_insert (types, g_steal_pointer (&s), + GUINT_TO_POINTER(*offset2)); blob->offset = *offset2; switch (type->tag) From 6f69fd53df62c6709fec59433588d1f5f5d92bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 17:36:23 +0200 Subject: [PATCH 05/17] girepository/girnode: Simplify the ownership fo the serialized type string --- girepository/girnode.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/girepository/girnode.c b/girepository/girnode.c index 2bc84e8ba..66fa40105 100644 --- a/girepository/girnode.c +++ b/girepository/girnode.c @@ -1460,24 +1460,22 @@ gi_ir_node_build_typelib (GIIrNode *node, else { GString *str; - char *s; gpointer value; str = g_string_new (0); serialize_type (build, type, str); - s = g_string_free (str, FALSE); types_count += 1; - value = g_hash_table_lookup (types, s); + value = g_hash_table_lookup (types, str->str); if (value) { blob->offset = GPOINTER_TO_UINT (value); - g_free (s); + g_string_free (g_steal_pointer (&str), TRUE); } else { unique_types_count += 1; - g_hash_table_insert (types, g_steal_pointer (&s), + g_hash_table_insert (types, g_string_free_and_steal (g_steal_pointer (&str)), GUINT_TO_POINTER(*offset2)); blob->offset = *offset2; From 05f606f3c5227f73a7fe83c28b97d44408219671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 17:37:23 +0200 Subject: [PATCH 06/17] girepository/girmodule: Cleanup the build stack once we've done The stack is allocated with a list that we need to free once done --- girepository/girmodule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/girepository/girmodule.c b/girepository/girmodule.c index af416c3a2..f3f259397 100644 --- a/girepository/girmodule.c +++ b/girepository/girmodule.c @@ -540,6 +540,7 @@ gi_ir_module_build_typelib (GIIrModule *module) build.n_attributes = header->n_attributes; build.data = data; gi_ir_node_build_typelib (node, NULL, &build, &offset, &offset2, NULL); + g_clear_list (&build.stack, NULL); nodes_with_attributes = build.nodes_with_attributes; header->n_attributes = build.n_attributes; From 6a4f8e5bb7284033568276d187b0d29c8dcb08e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 17:52:01 +0200 Subject: [PATCH 07/17] girepository/girmodule: Use clearer scope for the build struct Allocate it only when needed avoiding manual memset --- girepository/girmodule.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/girepository/girmodule.c b/girepository/girmodule.c index f3f259397..253415be9 100644 --- a/girepository/girmodule.c +++ b/girepository/girmodule.c @@ -481,7 +481,6 @@ gi_ir_module_build_typelib (GIIrModule *module) for (e = module->entries, i = 0; e; e = e->next, i++) { - GIIrTypelibBuild build; GIIrNode *node = e->data; if (strchr (node->name, '.')) @@ -524,6 +523,7 @@ gi_ir_module_build_typelib (GIIrModule *module) } else { + GIIrTypelibBuild build = {0}; old_offset = offset; offset2 = offset + gi_ir_node_get_size (node); @@ -532,7 +532,6 @@ gi_ir_module_build_typelib (GIIrModule *module) entry->offset = offset; entry->name = gi_ir_write_string (node->name, strings, data, &offset2); - memset (&build, 0, sizeof (build)); build.module = module; build.strings = strings; build.types = types; From 4cdf53a15c01a0d106c804aaaa215868483689a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 17:37:59 +0200 Subject: [PATCH 08/17] girepository/girmodule: Cleanup the temporary dependencies string It's used during build phase, as a temporary variable but never freed --- girepository/girmodule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/girepository/girmodule.c b/girepository/girmodule.c index 253415be9..549a984ae 100644 --- a/girepository/girmodule.c +++ b/girepository/girmodule.c @@ -592,6 +592,7 @@ gi_ir_module_build_typelib (GIIrModule *module) g_hash_table_destroy (strings); g_hash_table_destroy (types); g_list_free (nodes_with_attributes); + g_free (dependencies); return typelib; } From a359333dd06e63c2b1c4231039cb4bc6d026e3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 17:46:52 +0200 Subject: [PATCH 09/17] girepository/girnode: Fully free the members and discriminators lists We were removing the contents but not the lists themselves --- girepository/girnode.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/girepository/girnode.c b/girepository/girnode.c index 66fa40105..aacc2a0d3 100644 --- a/girepository/girnode.c +++ b/girepository/girnode.c @@ -415,10 +415,8 @@ gi_ir_node_free (GIIrNode *node) g_free (union_->free_func); gi_ir_node_free ((GIIrNode *)union_->discriminator_type); - for (l = union_->members; l; l = l->next) - gi_ir_node_free ((GIIrNode *)l->data); - for (l = union_->discriminators; l; l = l->next) - gi_ir_node_free ((GIIrNode *)l->data); + g_clear_list (&union_->members, (GDestroyNotify) gi_ir_node_free); + g_clear_list (&union_->discriminators, (GDestroyNotify) gi_ir_node_free); } break; From 98dce8a1c6ac70a9b389cf7cebcf4c79495b354d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 17:53:19 +0200 Subject: [PATCH 10/17] girepository/girparser: Do not allocate the same node name twice We were setting the node name two times, and the latter was overwriting the first one, making impossible to free the value when destroying the node --- girepository/girparser.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/girepository/girparser.c b/girepository/girparser.c index dee322b50..f0c578fd4 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -1353,8 +1353,6 @@ start_parameter (GMarkupParseContext *context, param->closure = closure ? atoi (closure) : -1; param->destroy = destroy ? atoi (destroy) : -1; - ((GIIrNode *)param)->name = g_strdup (name); - switch (CURRENT_NODE (ctx)->type) { case GI_IR_NODE_FUNCTION: From 997d32e9cdd21476b452c6de6ffb99e37e902324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 18:01:52 +0200 Subject: [PATCH 11/17] girepository/girparser: Free the struct or union node if was not tracked In case the node was pushed to a non-empty node stack, then we were not tracking it in the entries list, and so nothing was freeing it on destruction. As per this, once parsing is done, we can free it or we'd leak. --- girepository/girparser.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/girepository/girparser.c b/girepository/girparser.c index f0c578fd4..046ba2f98 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -3376,13 +3376,19 @@ state_switch_end_struct_or_union (GMarkupParseContext *context, const char *element_name, GError **error) { - pop_node (ctx); + GIIrNode *node = pop_node (ctx); + if (ctx->node_stack == NULL) { state_switch (ctx, STATE_NAMESPACE); } else { + /* In this case the node was not tracked by any other node, so we need + * to free the node, or we'd leak. + */ + g_clear_pointer (&node, gi_ir_node_free); + if (CURRENT_NODE (ctx)->type == GI_IR_NODE_STRUCT) state_switch (ctx, STATE_STRUCT); else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_UNION) From 9d65076eba305cbf07798348d1f4e51a41c27636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 18:06:20 +0200 Subject: [PATCH 12/17] girepository/girparser: Cleanup the node stack if anything destroyed it If we've leftover nodes in the stack we should cleanup it --- girepository/girparser.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/girepository/girparser.c b/girepository/girparser.c index 046ba2f98..2ff9009a0 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -3740,6 +3740,8 @@ cleanup (GMarkupParseContext *context, ParseContext *ctx = user_data; GList *m; + g_clear_slist (&ctx->node_stack, NULL); + for (m = ctx->modules; m; m = m->next) gi_ir_module_free (m->data); g_list_free (ctx->modules); @@ -3821,6 +3823,7 @@ gi_ir_parser_parse_string (GIIrParser *parser, g_list_free (ctx.include_modules); } + g_clear_slist (&ctx.node_stack, NULL); g_markup_parse_context_free (context); if (ctx.modules) From 6e38293fecc5262aed1f61b6def137ecb3f5b092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 18:08:26 +0200 Subject: [PATCH 13/17] girepository/girparser: Move dependencies ownership to each module In this way the module can survive without that the parser is fully alive. At the moment a module has not a ref-count system, but this makes things clearer when we return the module from a parser. --- girepository/girmodule-private.h | 2 +- girepository/girmodule.c | 2 +- girepository/girparser.c | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/girepository/girmodule-private.h b/girepository/girmodule-private.h index c3cb9df2a..fba781d5e 100644 --- a/girepository/girmodule-private.h +++ b/girepository/girmodule-private.h @@ -47,7 +47,7 @@ struct _GIIrModule char *version; char *shared_library; char *c_prefix; - GList *dependencies; + GList *dependencies; /* (owned) */ GList *entries; /* All modules that are included directly or indirectly */ diff --git a/girepository/girmodule.c b/girepository/girmodule.c index 549a984ae..c3309cdc2 100644 --- a/girepository/girmodule.c +++ b/girepository/girmodule.c @@ -83,7 +83,7 @@ gi_ir_module_free (GIIrModule *module) gi_ir_node_free ((GIIrNode *)e->data); g_list_free (module->entries); - /* Don't free dependencies, we inherit that from the parser */ + g_clear_list (&module->dependencies, g_free); g_list_free (module->include_modules); diff --git a/girepository/girparser.c b/girepository/girparser.c index 2ff9009a0..de60eef1f 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -3194,7 +3194,9 @@ start_element_handler (GMarkupParseContext *context, ctx->include_modules = NULL; ctx->modules = g_list_append (ctx->modules, ctx->current_module); - ctx->current_module->dependencies = ctx->dependencies; + g_clear_list (&ctx->current_module->dependencies, g_free); + ctx->current_module->dependencies = + g_list_copy_deep (ctx->dependencies, (GCopyFunc) g_strdup, NULL); state_switch (ctx, STATE_NAMESPACE); goto out; @@ -3824,6 +3826,7 @@ gi_ir_parser_parse_string (GIIrParser *parser, } g_clear_slist (&ctx.node_stack, NULL); + g_clear_list (&ctx.dependencies, g_free); g_markup_parse_context_free (context); if (ctx.modules) From b59c3f73eed238ffe7f21e440f86845311fc7e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 18:10:48 +0200 Subject: [PATCH 14/17] girepository/girparser: Free the parsed modules list elements We were removing the modules themselves, but not the list items --- girepository/girparser.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/girepository/girparser.c b/girepository/girparser.c index de60eef1f..9cb25e482 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -212,13 +212,10 @@ gi_ir_parser_set_debug (GIIrParser *parser, void gi_ir_parser_free (GIIrParser *parser) { - GList *l; - g_strfreev (parser->includes); g_strfreev (parser->gi_gir_path); - for (l = parser->parsed_modules; l; l = l->next) - gi_ir_module_free (l->data); + g_clear_list (&parser->parsed_modules, (GDestroyNotify) gi_ir_module_free); g_slice_free (GIIrParser, parser); } From 23d3a5e859e9f378171a8fe28ea17180532c3ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 18:14:38 +0200 Subject: [PATCH 15/17] girepository/girparser: Free the temporary context modules list when done When we're about to return the found module we can just drop the list of modules that we had previously copied in the temporary context --- girepository/girparser.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/girepository/girparser.c b/girepository/girparser.c index 9cb25e482..df3983a82 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -3819,6 +3819,7 @@ gi_ir_parser_parse_string (GIIrParser *parser, g_clear_pointer (&ctx.aliases, g_hash_table_unref); g_clear_pointer (&ctx.disguised_structures, g_hash_table_unref); g_clear_pointer (&ctx.pointer_structures, g_hash_table_unref); + g_clear_list (&ctx.modules, (GDestroyNotify) gi_ir_module_free); g_list_free (ctx.include_modules); } @@ -3827,7 +3828,12 @@ gi_ir_parser_parse_string (GIIrParser *parser, g_markup_parse_context_free (context); if (ctx.modules) - return ctx.modules->data; + { + GIIrModule *module = ctx.modules->data; + + g_clear_list (&ctx.modules, NULL); + return module; + } if (error && *error == NULL) g_set_error (error, From 2e2e60620896753ff9a6b1a93a6bedadec8e5f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 18:18:19 +0200 Subject: [PATCH 16/17] girparser: Simplify the ownership of context modules and parsed ones There's no need to copy the list of modules and free it again, we can just handle this by moving the modules to the parser promptly. --- girepository/girparser.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/girepository/girparser.c b/girepository/girparser.c index df3983a82..091b947c6 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -3775,6 +3775,7 @@ gi_ir_parser_parse_string (GIIrParser *parser, { ParseContext ctx = { 0 }; GMarkupParseContext *context; + GIIrModule *module = NULL; ctx.parser = parser; ctx.state = STATE_START; @@ -3806,12 +3807,15 @@ gi_ir_parser_parse_string (GIIrParser *parser, if (!g_markup_parse_context_end_parse (context, error)) goto out; - parser->parsed_modules = g_list_concat (g_list_copy (ctx.modules), + if (ctx.modules) + module = ctx.modules->data; + + parser->parsed_modules = g_list_concat (g_steal_pointer (&ctx.modules), parser->parsed_modules); out: - if (ctx.modules == NULL) + if (module == NULL) { /* An error occurred before we created a module, so we haven't * transferred ownership of these hash tables to the module. @@ -3827,13 +3831,8 @@ gi_ir_parser_parse_string (GIIrParser *parser, g_clear_list (&ctx.dependencies, g_free); g_markup_parse_context_free (context); - if (ctx.modules) - { - GIIrModule *module = ctx.modules->data; - - g_clear_list (&ctx.modules, NULL); - return module; - } + if (module) + return module; if (error && *error == NULL) g_set_error (error, From b27fbf503b5fb6b9b5f6ff6f1c0a91a9b2d5fe0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 10 May 2024 18:35:04 +0200 Subject: [PATCH 17/17] girepository/girparser,girmodule: Use a GPtrArray to hold the dependencies It's just better than a list of strings for various reasons, but mostly here it allows also to avoid copying the lists but making the ownership clearer through references --- girepository/girmodule-private.h | 2 +- girepository/girmodule.c | 48 +++++++++++++++++--------------- girepository/girparser.c | 20 +++++++------ 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/girepository/girmodule-private.h b/girepository/girmodule-private.h index fba781d5e..c6b9f413c 100644 --- a/girepository/girmodule-private.h +++ b/girepository/girmodule-private.h @@ -47,7 +47,7 @@ struct _GIIrModule char *version; char *shared_library; char *c_prefix; - GList *dependencies; /* (owned) */ + GPtrArray *dependencies; /* (owned) */ GList *entries; /* All modules that are included directly or indirectly */ diff --git a/girepository/girmodule.c b/girepository/girmodule.c index c3309cdc2..87bb13ad3 100644 --- a/girepository/girmodule.c +++ b/girepository/girmodule.c @@ -83,7 +83,7 @@ gi_ir_module_free (GIIrModule *module) gi_ir_node_free ((GIIrNode *)e->data); g_list_free (module->entries); - g_clear_list (&module->dependencies, g_free); + g_clear_pointer (&module->dependencies, g_ptr_array_unref); g_list_free (module->include_modules); @@ -351,25 +351,29 @@ gi_ir_module_build_typelib (GIIrModule *module) /* Serialize dependencies into one string; this is convenient * and not a major change to the typelib format. */ - { - GString *dependencies_str = g_string_new (""); - GList *link; - for (link = module->dependencies; link; link = link->next) - { - const char *dependency = link->data; - if (!strcmp (dependency, module->name)) - continue; - g_string_append (dependencies_str, dependency); - if (link->next) - g_string_append_c (dependencies_str, '|'); - } - dependencies = g_string_free (dependencies_str, FALSE); - if (!dependencies[0]) - { - g_free (dependencies); - dependencies = NULL; - } - } + if (module->dependencies->len) + { + GString *dependencies_str = g_string_new (NULL); + for (guint i = module->dependencies->len; i > 0; --i) + { + const char *dependency = g_ptr_array_index (module->dependencies, i-1); + if (!strcmp (dependency, module->name)) + continue; + g_string_append (dependencies_str, dependency); + if (i > 1) + g_string_append_c (dependencies_str, '|'); + } + dependencies = g_string_free (dependencies_str, FALSE); + if (dependencies && !dependencies[0]) + { + g_free (dependencies); + dependencies = NULL; + } + } + else + { + dependencies = NULL; + } restart: gi_ir_node_init_stats (); @@ -378,8 +382,8 @@ gi_ir_module_build_typelib (GIIrModule *module) nodes_with_attributes = NULL; n_entries = g_list_length (module->entries); - g_message ("%d entries (%d local), %d dependencies", n_entries, n_local_entries, - g_list_length (module->dependencies)); + g_message ("%d entries (%d local), %u dependencies", n_entries, n_local_entries, + module->dependencies ? module->dependencies->len : 0); dir_size = n_entries * sizeof (DirEntry); size = header_size + dir_size; diff --git a/girepository/girparser.c b/girepository/girparser.c index 091b947c6..a469d3dd2 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -120,7 +120,7 @@ struct _ParseContext GList *modules; GList *include_modules; - GList *dependencies; + GPtrArray *dependencies; GHashTable *aliases; GHashTable *disguised_structures; GHashTable *pointer_structures; @@ -3101,9 +3101,8 @@ start_element_handler (GMarkupParseContext *context, return; } - ctx->dependencies = g_list_prepend (ctx->dependencies, - g_strdup_printf ("%s-%s", name, version)); - + g_ptr_array_insert (ctx->dependencies, 0, + g_strdup_printf ("%s-%s", name, version)); state_switch (ctx, STATE_INCLUDE); goto out; @@ -3191,9 +3190,12 @@ start_element_handler (GMarkupParseContext *context, ctx->include_modules = NULL; ctx->modules = g_list_append (ctx->modules, ctx->current_module); - g_clear_list (&ctx->current_module->dependencies, g_free); - ctx->current_module->dependencies = - g_list_copy_deep (ctx->dependencies, (GCopyFunc) g_strdup, NULL); + + if (ctx->current_module->dependencies != ctx->dependencies) + { + g_clear_pointer (&ctx->current_module->dependencies, g_ptr_array_unref); + ctx->current_module->dependencies = g_ptr_array_ref (ctx->dependencies); + } state_switch (ctx, STATE_NAMESPACE); goto out; @@ -3786,7 +3788,7 @@ gi_ir_parser_parse_string (GIIrParser *parser, ctx.disguised_structures = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); ctx.pointer_structures = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); ctx.type_depth = 0; - ctx.dependencies = NULL; + ctx.dependencies = g_ptr_array_new_with_free_func (g_free); ctx.current_module = NULL; context = g_markup_parse_context_new (&firstpass_parser, 0, &ctx, NULL); @@ -3828,7 +3830,7 @@ gi_ir_parser_parse_string (GIIrParser *parser, } g_clear_slist (&ctx.node_stack, NULL); - g_clear_list (&ctx.dependencies, g_free); + g_clear_pointer (&ctx.dependencies, g_ptr_array_unref); g_markup_parse_context_free (context); if (module)