port-serial: avoid invalid memory write on cancellation logic
If the GCancellable is already cancelled when trying to connect a
signal, the callback given will be run right away, and that may end up
completing the async task and removing the last MMPortSerial
reference.
==30627== Invalid write of size 8
==30627== at 0x1ED43B: port_serial_queue_process (mm-port-serial.c:812)
==30627== by 0x66DE342: ??? (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DD8C4: g_main_context_dispatch (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DDC87: ??? (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DDFA1: g_main_loop_run (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x143F9B: main (main.c:180)
==30627== Address 0xf6f0e98 is 200 bytes inside a block of size 328 free'd
==30627== at 0x4C2E14B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30627== by 0x64742B2: g_type_free_instance (in /usr/lib/libgobject-2.0.so.0.5200.3)
==30627== by 0x1ED0F2: port_serial_got_response (mm-port-serial.c:704)
==30627== by 0x1ED21B: port_serial_response_wait_cancelled (mm-port-serial.c:757)
==30627== by 0x60E1A81: g_cancellable_connect (in /usr/lib/libgio-2.0.so.0.5200.3)
==30627== by 0x1ED43A: port_serial_queue_process (mm-port-serial.c:812)
==30627== by 0x66DE342: ??? (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DD8C4: g_main_context_dispatch (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DDC87: ??? (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DDFA1: g_main_loop_run (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x143F9B: main (main.c:180)
==30627== Block was alloc'd at
==30627== at 0x4C2CE5F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30627== by 0x66E3028: g_malloc (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66FAB25: g_slice_alloc (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66FAFB8: g_slice_alloc0 (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x6473FB5: g_type_create_instance (in /usr/lib/libgobject-2.0.so.0.5200.3)
==30627== by 0x6455027: ??? (in /usr/lib/libgobject-2.0.so.0.5200.3)
==30627== by 0x6456DBC: g_object_new_valist (in /usr/lib/libgobject-2.0.so.0.5200.3)
==30627== by 0x6457200: g_object_new (in /usr/lib/libgobject-2.0.so.0.5200.3)
==30627== by 0x1F253A: mm_port_serial_at_new (mm-port-serial-at.c:533)
==30627== by 0x1AC7E7: serial_open_at (mm-port-probe.c:1210)
==30627== by 0x66DD8C4: g_main_context_dispatch (in /usr/lib/libglib-2.0.so.0.5200.3)
==30627== by 0x66DDC87: ??? (in /usr/lib/libglib-2.0.so.0.5200.3)
This commit is contained in:
+17
-13
@@ -808,21 +808,25 @@ port_serial_queue_process (gpointer data)
|
||||
|
||||
/* Setup the cancellable so that we can stop waiting for a response */
|
||||
if (ctx->cancellable) {
|
||||
gulong cancellable_id;
|
||||
|
||||
self->priv->cancellable = g_object_ref (ctx->cancellable);
|
||||
self->priv->cancellable_id = (g_cancellable_connect (
|
||||
ctx->cancellable,
|
||||
(GCallback)port_serial_response_wait_cancelled,
|
||||
self,
|
||||
NULL));
|
||||
if (!self->priv->cancellable_id) {
|
||||
error = g_error_new (MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_CANCELLED,
|
||||
"Won't wait for the reply");
|
||||
/* Note: may complete last operation and unref the MMPortSerial */
|
||||
port_serial_got_response (self, NULL, error);
|
||||
g_error_free (error);
|
||||
|
||||
/* If the GCancellable is already cancelled here, the callback will be
|
||||
* called right away, and a GError will be propagated as response. In
|
||||
* this case we need to completely avoid doing anything else with the
|
||||
* MMPortSerial, as it may already be disposed.
|
||||
* So, use an intermediate variable to store the cancellable id, and
|
||||
* just return without further processing if we're already cancelled.
|
||||
*/
|
||||
cancellable_id = g_cancellable_connect (ctx->cancellable,
|
||||
(GCallback)port_serial_response_wait_cancelled,
|
||||
self,
|
||||
NULL);
|
||||
if (!cancellable_id)
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
self->priv->cancellable_id = cancellable_id;
|
||||
}
|
||||
|
||||
/* If the command is finished being sent, schedule the timeout */
|
||||
|
||||
Reference in New Issue
Block a user