diff --git a/changes/api/529.fix-xml-error-handler.bugfix.md b/changes/api/529.fix-xml-error-handler.bugfix.md new file mode 100644 index 00000000..3a186ed9 --- /dev/null +++ b/changes/api/529.fix-xml-error-handler.bugfix.md @@ -0,0 +1,4 @@ +registry: Fixed `libxml2` global error handler not reset after parsing, which +could trigger a crash if the corresponding `rxkb_context` has been freed. + +Contributed by Sebastian Keller. diff --git a/meson.build b/meson.build index 37f0db23..19aff944 100644 --- a/meson.build +++ b/meson.build @@ -879,7 +879,7 @@ if get_option('enable-xkbregistry') 'registry', executable('test-registry', 'test/registry.c', include_directories: include_directories('src'), - dependencies: [dep_libxkbregistry, test_dep]), + dependencies: [dep_libxkbregistry, dep_libxml, test_dep]), env: test_env, ) endif diff --git a/src/registry.c b/src/registry.c index ea5aa80f..acdeb814 100644 --- a/src/registry.c +++ b/src/registry.c @@ -1250,20 +1250,32 @@ parse(struct rxkb_context *ctx, const char *path, doc = xmlParseFile(path); if (!doc) - return false; + goto parse_error; if (!validate(ctx, doc)) { log_err(ctx, XKB_LOG_MESSAGE_NO_ID, "XML error: failed to validate document at %s\n", path); - goto error; + goto validate_error; } root = xmlDocGetRootElement(doc); parse_rules_xml(ctx, root, popularity); success = true; -error: +validate_error: xmlFreeDoc(doc); +parse_error: + /* + * Reset the default libxml2 error handler to default, because this handler + * is global and may be used on an invalid rxkb_context, e.g. *after* the + * following sequence: + * + * rxkb_context_new(); + * rxkb_context_parse(); + * rxkb_context_unref(); + */ + /* TODO: use the new API xmlCtxtSetErrorHandler */ + xmlSetGenericErrorFunc(NULL, NULL); return success; } diff --git a/test/registry.c b/test/registry.c index 6ce56de1..26b47fbf 100644 --- a/test/registry.c +++ b/test/registry.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include "xkbcommon/xkbregistry.h" @@ -1065,11 +1067,36 @@ test_invalid_include(void) rxkb_context_unref(ctx); } +/* Check that libxml2 error handler is reset after parsing */ +static void +test_xml_error_handler(void) +{ + struct test_model system_models[] = { {NULL} }; + struct test_layout system_layouts[] = { {NULL} }; + struct test_option_group system_groups[] = { { NULL } }; + struct rxkb_context *ctx; + + ctx = test_setup_context(system_models, NULL, + system_layouts, NULL, + system_groups, NULL); + assert(ctx); + rxkb_context_unref(ctx); + + const char invalid_xml[] = "