summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2013-01-10 22:55:51 +0100
committerHans de Goede <hdegoede@redhat.com>2013-01-15 14:30:59 +0100
commitd2e1f939fec9b4d852a009cc55c4bbb3d2a94d3b (patch)
treeb62045db39271740afc98872cf80edfd9c705923 /server
parentcf8ebbc48491cf5178e4edc57f49ceded20ead55 (diff)
downloadspice-d2e1f939fec9b4d852a009cc55c4bbb3d2a94d3b.tar.gz
spice-d2e1f939fec9b4d852a009cc55c4bbb3d2a94d3b.tar.xz
spice-d2e1f939fec9b4d852a009cc55c4bbb3d2a94d3b.zip
server: Fix SpiceWorker-CRITICAL **: red_worker.c:10968:red_push_monitors_config: condition `monitors_config != NULL' failed
During my dynamic monitor support testing today, I hit the following assert in red_worker.c: "red_push_monitors_config: condition `monitors_config != NULL' failed" This is caused by the following scenario: 1) Guest causes handle_dev_monitors_config_async() to be called 2) handle_dev_monitors_config_async() calls worker_update_monitors_config() 3) handle_dev_monitors_config_async() pushes worker->monitors_config, this takes a ref on the current monitors_config 4) Guest causes handle_dev_monitors_config_async() to be called *again* 5) handle_dev_monitors_config_async() calls worker_update_monitors_config() 6) worker_update_monitors_config() does a decref on worker->monitors_config, releasing the workers reference, this monitor_config from step 2 is not yet free-ed though as the pipe-item still holds a ref 7) worker_update_monitors_config() creates a new monitors_config with an initial ref-count of 1 and stores that in worker->monitors_config 8) The pipe-item of the *first* monitors_config is send, upon completion a decref is done on the monitors_config, and monitors_config_decref not only frees the monitor_config, but *also* sets worker->monitors_config to NULL, even though worker->monitors_config no longer refers to the monitor_config being freed, it refers to the 2nd monitor_config! 9) The client which was connected when this all happened disconnects 10) A new client connects, leading to the assert: at red_worker.c:9519 num_common_caps=1, common_caps=0x5555569b6f60, migrate=0, stream=<optimized out>, client=<optimized out>, worker=<optimized out>) at red_worker.c:10423 at red_worker.c:11301 Note that red_worker.c:9519 is: red_push_monitors_config(dcc); gdb does not point to the actual line of the assert because the function gets inlined. The fix is easy and obvious, don't set worker->monitors_config to NULL in monitors_config_decref. I'm a bit baffled as to why that code is there in the first place, the whole point of ref-counting is to not have one single unique place to store the reference... This fix should not have any adverse side-effects as the 4 callers of monitors_config_decref fall into 2 categories: 1) Code which immediately after the decref replaces worker->monitors_config with a new monitors_config: worker_update_monitors_config() set_monitors_config_to_primary() 2) pipe-item freeing code, which should not touch the worker state at all to being with Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'server')
-rw-r--r--server/red_worker.c3
1 files changed, 1 insertions, 2 deletions
diff --git a/server/red_worker.c b/server/red_worker.c
index 085e3e6b..de070a69 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1239,8 +1239,7 @@ static void monitors_config_decref(MonitorsConfig *monitors_config)
return;
}
- spice_debug("removing worker monitors config");
- monitors_config->worker->monitors_config = NULL;
+ spice_debug("freeing monitors config");
free(monitors_config);
}