[PATCH] mm-base-manager: ref MMDevice before releasing port
Aleksander Morgado
aleksander at aleksander.es
Fri Feb 23 11:42:52 UTC 2018
On 21/02/18 22:49, Eric Caruso wrote:
> Releasing the port on the device looks benign but because it emits
> a signal, it could call device_context_port_released and unref the
> MMDevice in port_context_unref. This means the MMDevice might be
> disposed before we get to the g_object_ref and the subsequent call
> to g_hash_table_remove will try to hash a null string, which makes
> MM crash.
Yeah, looks like PORT_REMOVED signal handler may end up calling device_support_check_ready() and that removes the device also from the HT. I'm going to push a follow up commit adding the explicit extra indentation between the ref/unref to make it clear that this is just to keep a reference valid for that block of logic.
> ---
> src/mm-base-manager.c | 30 +++++++++++++++---------------
> 1 file changed, 15 insertions(+), 15 deletions(-)
>
> diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c
> index 4b92ab0b..7738ce0d 100644
> --- a/src/mm-base-manager.c
> +++ b/src/mm-base-manager.c
> @@ -220,28 +220,28 @@ device_removed (MMBaseManager *self,
> /* Handle tty/net/wdm port removal */
> device = find_device_by_port (self, kernel_device);
> if (device) {
> + /* The callbacks triggered when the port is released or device support is
> + * cancelled may end up unreffing the device or removing it from the HT, and
> + * so in order to make sure the reference is still valid when we call
> + * support_check_cancel() and g_hash_table_remove(), we hold a full reference
> + * ourselves. */
> + g_object_ref (device);
> +
> mm_info ("(%s/%s): released by device '%s'", subsys, name, mm_device_get_uid (device));
> mm_device_release_port (device, kernel_device);
>
> /* If port probe list gets empty, remove the device object iself */
> if (!mm_device_peek_port_probe_list (device)) {
> - /* The callback triggered when the device support is cancelled may end up
> - * removing the device from the HT, and that was the last full reference
> - * we kept. So, in order to make sure the reference is still valid after
> - * support_check_cancel(), we hold a full reference ourselves. */
> mm_dbg ("Removing empty device '%s'", mm_device_get_uid (device));
> - g_object_ref (device);
> - {
> - if (mm_plugin_manager_device_support_check_cancel (self->priv->plugin_manager, device))
> - mm_dbg ("Device support check has been cancelled");
> -
> - /* The device may have already been removed from the tracking HT, we
> - * just try to remove it and if it fails, we ignore it */
> - mm_device_remove_modem (device);
> - g_hash_table_remove (self->priv->devices, mm_device_get_uid (device));
> - }
> - g_object_unref (device);
> + if (mm_plugin_manager_device_support_check_cancel (self->priv->plugin_manager, device))
> + mm_dbg ("Device support check has been cancelled");
> +
> + /* The device may have already been removed from the tracking HT, we
> + * just try to remove it and if it fails, we ignore it */
> + mm_device_remove_modem (device);
> + g_hash_table_remove (self->priv->devices, mm_device_get_uid (device));
> }
> + g_object_unref (device);
> }
>
> return;
>
--
Aleksander
https://aleksander.es
More information about the ModemManager-devel
mailing list