I'm looking into this with the help claude-code. This may be caused by a
race condition in locations.js, and I am testing the following changes.
I will update this bug if it fixes the issue.

## Analysis

The ubuntu-dock extension's `locations.js` accesses a GProxyVolume
object after the CD has been ejected and gvfs has disposed of the
volume. This use-after-free corrupts heap memory, causing an immediate
crash (signal 6 / SIGABRT from glibc's malloc corruption detection).

### Stack trace breakdown

**Line 504** (`MountableVolumeAppInfo.vfunc_get_id`):
```javascript
vfunc_get_id() {
    const uuid = this.mount?.get_uuid() ?? this.volume.get_uuid();
    //                                      ^^^^^^^^^^^^^^^^^^^
    // Accesses disposed GProxyVolume here - no null/disposed check
    return uuid ? 'mountable-volume:%s'.format(uuid) : super.vfunc_get_id();
}
```

**Line 316** (`_updateLocationIcon` catch block):
```javascript
} catch (e) {
    if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
        logError(e, 'Impossible to update icon for %s'.format(this.get_id()));
        //                                                     ^^^^^^^^^^^
        // This calls vfunc_get_id() which accesses the disposed volume
}
```

### Root cause: Race condition on volume removal

The `Removables` class (line 1383-1503) monitors `Gio.VolumeMonitor` for
volume events. When a CD is ejected:

1. **gvfs disposes** the `GProxyVolume` object immediately
2. **Signal handlers still fire** - the `changed` signal handler at line 574 
may trigger `_update()`
3. **`volume-removed` arrives later** - cleanup in `_onVolumeRemoved()` (line 
1472) hasn't run yet
4. **Async operations in flight** - `_updateLocationIcon()` is async and may 
still be running

### Specific problems in the code

1. **No disposed check** - `vfunc_get_id()` at line 504 accesses
`this.volume.get_uuid()` without checking if volume is still valid

2. **Signal handler race** - `_monitorChanges()` (line 570) connects to
`removable.changed`, but doesn't disconnect when the volume is about to
be disposed

3. **Async operation not cancelled early enough** - The cancellable is
only set to null *after* finding the volume in `_onVolumeRemoved()`, but
async operations may already be in the error path

### Proposed fixes

```javascript
// Fix 1: Guard vfunc_get_id (line 504)
vfunc_get_id() {
    try {
        const uuid = this.mount?.get_uuid() ?? this.volume?.get_uuid?.();
        return uuid ? 'mountable-volume:%s'.format(uuid) : super.vfunc_get_id();
    } catch (e) {
        return super.vfunc_get_id();
    }
}

// Fix 2: Cancel operations BEFORE accessing disposed objects
// In _onVolumeRemoved (line 1472), cancel first:
_onVolumeRemoved(volume) {
    const volumeIndex = this._volumeApps.findIndex(({appInfo}) =>
        appInfo.volume === volume);
    if (volumeIndex !== -1) {
        const [volumeApp] = this._volumeApps.splice(volumeIndex, 1);
        volumeApp.appInfo.cancellable?.cancel();  // Cancel FIRST
        volumeApp.destroy();
        this.emit('changed');
    }
}
```

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2137078

Title:
  GNOME Shell crashes after CD eject - ubuntu-dock accesses disposed
  GProxyVolume

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/gnome-shell-extension-ubuntu-dock/+bug/2137078/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to