From 5414ea59cfc35852cb68b94982c91ed1ec95d6cf Mon Sep 17 00:00:00 2001 From: Sander Mertens Date: Mon, 19 Aug 2024 17:59:00 -0700 Subject: [PATCH] Fix crash when serializing query plan for trivial query --- flecs.c | 8 +++- src/addons/json/serialize_iter.c | 8 +++- test/meta/project.json | 4 +- test/meta/src/SerializeQueryInfoToJson.c | 58 ++++++++++++++++++++++++ test/meta/src/main.c | 12 ++++- 5 files changed, 84 insertions(+), 6 deletions(-) diff --git a/flecs.c b/flecs.c index 47e22d445c..cbcd3b37da 100644 --- a/flecs.c +++ b/flecs.c @@ -42075,8 +42075,12 @@ void flecs_json_serialize_query_plan( bool prev_color = ecs_log_enable_colors(true); char *plan = ecs_query_plan(q); - flecs_json_string_escape(buf, plan); - ecs_os_free(plan); + if (plan) { + flecs_json_string_escape(buf, plan); + ecs_os_free(plan); + } else { + flecs_json_null(buf); + } ecs_log_enable_colors(prev_color); } diff --git a/src/addons/json/serialize_iter.c b/src/addons/json/serialize_iter.c index 5dd6aef690..4ed2a68912 100644 --- a/src/addons/json/serialize_iter.c +++ b/src/addons/json/serialize_iter.c @@ -130,8 +130,12 @@ void flecs_json_serialize_query_plan( bool prev_color = ecs_log_enable_colors(true); char *plan = ecs_query_plan(q); - flecs_json_string_escape(buf, plan); - ecs_os_free(plan); + if (plan) { + flecs_json_string_escape(buf, plan); + ecs_os_free(plan); + } else { + flecs_json_null(buf); + } ecs_log_enable_colors(prev_color); } diff --git a/test/meta/project.json b/test/meta/project.json index 34931964ed..653936f06d 100644 --- a/test/meta/project.json +++ b/test/meta/project.json @@ -889,7 +889,9 @@ "anonymous_component", "anonymous_tag_recycled", "anonymous_pair_recycled", - "anonymous_component_recycled" + "anonymous_component_recycled", + "serialize_plan_trivial_query", + "serialize_plan_nontrivial_query" ] }, { "id": "MetaUtils", diff --git a/test/meta/src/SerializeQueryInfoToJson.c b/test/meta/src/SerializeQueryInfoToJson.c index bf4f029995..17bfc13242 100644 --- a/test/meta/src/SerializeQueryInfoToJson.c +++ b/test/meta/src/SerializeQueryInfoToJson.c @@ -691,3 +691,61 @@ void SerializeQueryInfoToJson_anonymous_component_recycled(void) { ecs_fini(world); } + +void SerializeQueryInfoToJson_serialize_plan_trivial_query(void) { + ecs_world_t *world = ecs_init(); + + ECS_COMPONENT(world, Position); + + ecs_query_t *q = ecs_query(world, { + .terms = {{ ecs_id(Position) }} + }); + + test_assert(q != NULL); + + ecs_iter_t it = ecs_query_iter(world, q); + ecs_iter_to_json_desc_t desc = { + .serialize_query_plan = true, + .query = q + }; + + char *json = ecs_iter_to_json(&it, &desc); + char *expect = flecs_asprintf("{\"query_plan\":null, \"results\":[]}"); + test_json(json, expect); + ecs_os_free(json); + ecs_os_free(expect); + + ecs_query_fini(q); + + ecs_fini(world); +} + +void SerializeQueryInfoToJson_serialize_plan_nontrivial_query(void) { + ecs_world_t *world = ecs_init(); + + ECS_COMPONENT(world, Position); + + ecs_add_pair(world, ecs_id(Position), EcsOnInstantiate, EcsInherit); + + ecs_query_t *q = ecs_query(world, { + .terms = {{ ecs_id(Position) }} + }); + + test_assert(q != NULL); + + ecs_iter_t it = ecs_query_iter(world, q); + ecs_iter_to_json_desc_t desc = { + .serialize_query_plan = true, + .query = q + }; + + char *json = ecs_iter_to_json(&it, &desc); + char *expect = flecs_asprintf("{\"query_plan\":\"[[0;49m 0. [[[0;37m-1[[0;49m, [[0;32m 1[[0;49m] setids \\n[[0;49m 1. [[[0;37m 0[[0;49m, [[0;32m 2[[0;49m] selfupid [[0;32m$[[0;49m[[[0;32mthis[[0;49m] ([[0;34mPosition[[0;49m)\\n[[0;49m 2. [[[0;37m 1[[0;49m, [[0;32m 3[[0;49m] yield \\n\", \"results\":[]}"); + test_json(json, expect); + ecs_os_free(json); + ecs_os_free(expect); + + ecs_query_fini(q); + + ecs_fini(world); +} diff --git a/test/meta/src/main.c b/test/meta/src/main.c index eed675cb4d..e84906fcee 100644 --- a/test/meta/src/main.c +++ b/test/meta/src/main.c @@ -853,6 +853,8 @@ void SerializeQueryInfoToJson_anonymous_component(void); void SerializeQueryInfoToJson_anonymous_tag_recycled(void); void SerializeQueryInfoToJson_anonymous_pair_recycled(void); void SerializeQueryInfoToJson_anonymous_component_recycled(void); +void SerializeQueryInfoToJson_serialize_plan_trivial_query(void); +void SerializeQueryInfoToJson_serialize_plan_nontrivial_query(void); // Testsuite 'MetaUtils' void MetaUtils_struct_w_2_i32(void); @@ -4235,6 +4237,14 @@ bake_test_case SerializeQueryInfoToJson_testcases[] = { { "anonymous_component_recycled", SerializeQueryInfoToJson_anonymous_component_recycled + }, + { + "serialize_plan_trivial_query", + SerializeQueryInfoToJson_serialize_plan_trivial_query + }, + { + "serialize_plan_nontrivial_query", + SerializeQueryInfoToJson_serialize_plan_nontrivial_query } }; @@ -4681,7 +4691,7 @@ static bake_test_suite suites[] = { "SerializeQueryInfoToJson", NULL, NULL, - 25, + 27, SerializeQueryInfoToJson_testcases }, {