The UUID validation happens early enough during the migration process
that the incoming coroutine hasn't yet yielded once so the
EXIT_FAILURE from the coroutine can trigger ASAN leak detection due to
the temporary socket from qio_net_listener_channel_func() still having
an elevated refcount.
Direct leak of 400 byte(s) in 1 object(s) allocated from:
#0 0x55e668890a07 in malloc asan_malloc_linux.cpp:68:3
#1 0x7f3c7e2b6648 in g_malloc ../glib/gmem.c:130
#2 0x55e66a8ef05f in object_new_with_type ../qom/object.c:767:15
#3 0x55e66a8ef178 in object_new ../qom/object.c:789:12
#4 0x55e66a93bcc6 in qio_channel_socket_new ../io/channel-socket.c:70:31
#5 0x55e66a93f34f in qio_channel_socket_accept ../io/channel-socket.c:401:12
#6 0x55e66a96752a in qio_net_listener_channel_func
../io/net-listener.c:64:12
#7 0x55e66a94bdac in qio_channel_fd_source_dispatch
../io/channel-watch.c:84:12
#8 0x7f3c7e2adf4b in g_main_dispatch ../glib/gmain.c:3476
#9 0x7f3c7e2adf4b in g_main_context_dispatch_unlocked ../glib/gmain.c:4284
#10 0x7f3c7e2b00c8 in g_main_context_dispatch ../glib/gmain.c:4272
Direct leak of 32 byte(s) in 1 object(s) allocated from:
#0 0x55e668890a07 in malloc asan_malloc_linux.cpp:68:3
#1 0x7f3c7e2b6648 in g_malloc ../glib/gmem.c:130
#2 0x7f3c7e2ad40c in g_source_set_callback ../glib/gmain.c:1879
#3 0x55e66a95c4d2 in qio_channel_add_watch_full ../io/channel.c:416:5
#4 0x55e66a95c5a9 in qio_channel_add_watch_source ../io/channel.c:444:10
#5 0x55e66a96380c in qio_net_listener_watch ../io/net-listener.c:166:46
#6 0x55e66a96496a in qio_net_listener_set_client_func_internal
../io/net-listener.c:275:5
#7 0x55e66a963e79 in qio_net_listener_set_client_func_full
../io/net-listener.c:284:5
#8 0x55e669e1b3bb in socket_connect_incoming ../migration/socket.c:165:5
#9 0x55e669d26b9f in migration_connect_incoming ../migration/channel.c:83:13
#10 0x55e669d5f6d2 in qemu_setup_incoming_migration
../migration/migration.c:672:5
#11 0x55e669d5f344 in qmp_migrate_incoming ../migration/migration.c:1771:5
This is inconsequential in production, but let's give ourselves an
easier time and avoid this situation when testing. The uuid_error test
doesn't really need to check the exit code, just the migration state
would be sufficient. Set exit-on-error=false for this test.
While looking at this, add a comment to the source explaining that the
incoming coroutine may block the main loop for a (longer than
expected) while.
Signed-off-by: Fabiano Rosas <[email protected]>
---
migration/migration.c | 5 +++++
tests/qtest/migration/misc-tests.c | 4 ++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index f949708629..c77832f851 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -898,6 +898,11 @@ void migration_start_incoming(void)
Coroutine *co = qemu_coroutine_create(process_incoming_migration_co, NULL);
qemu_coroutine_enter(co);
+ /*
+ * This doesn't return right away. The coroutine will run
+ * unimpeded until its first yield, which may happen as late as
+ * the force yield at ram_load_precopy().
+ */
}
int migrate_send_rp_switchover_ack(MigrationIncomingState *mis)
diff --git a/tests/qtest/migration/misc-tests.c
b/tests/qtest/migration/misc-tests.c
index 810e9e6549..06da2657d5 100644
--- a/tests/qtest/migration/misc-tests.c
+++ b/tests/qtest/migration/misc-tests.c
@@ -131,7 +131,7 @@ static void do_test_validate_uuid(MigrateStart *args, bool
should_fail)
g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
QTestState *from, *to;
- if (migrate_start(&from, &to, uri, args)) {
+ if (migrate_start(&from, &to, "defer", args)) {
return;
}
@@ -146,10 +146,10 @@ static void do_test_validate_uuid(MigrateStart *args,
bool should_fail)
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
+ migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
migrate_qmp(from, to, uri, NULL, "{}");
if (should_fail) {
- qtest_set_expected_status(to, EXIT_FAILURE);
wait_for_migration_fail(from, true);
} else {
wait_for_migration_complete(from);
--
2.51.0