Skip to content

splice(indexOf()) without -1 guard silently removes wrong array element in 4 locations #315167

@SebTardif

Description

@SebTardif

Does this issue occur when all extensions are disabled?: Yes

  • VS Code Version: 1.120.0 (main branch, commit 89fc639)
  • OS Version: All platforms

Bug

Multiple locations in the codebase use the pattern array.splice(array.indexOf(item), 1) without checking whether indexOf returned -1. When the element is not found, indexOf returns -1, and splice(-1, 1) silently removes the last element of the array instead of being a no-op.

This causes incorrect behavior: the wrong keyboard layout, activity badge, progress indicator, or settings entry is silently removed.

Affected locations

File Method Impact
keyboardLayoutService.ts:116-119 removeKeyboardLayout Removes wrong layout from MRU if called with stale ref
activityService.ts:95, 158 showViewContainerActivity / showActivity dispose callback Removes wrong activity badge on double dispose
progressService.ts:135 withWindowProgress finally block Removes wrong progress task if promise resolved before delay
settingsTree.ts:2871 ApplySettingToAllProfilesAction.run Removes wrong setting from all-profiles list (TOCTOU between this.checked and fresh getValue())

Steps to Reproduce

activityService.ts (double dispose scenario):

  1. Register a view container activity via showViewContainerActivity
  2. Store the returned IDisposable
  3. Call .dispose() on it twice
  4. On the second call, indexOf returns -1 because the activity was already removed
  5. splice(-1, 1) removes the last activity in the array (belonging to a different view container)
  6. The wrong activity badge disappears from the UI

settingsTree.ts (TOCTOU scenario):

  1. Open Settings UI
  2. Toggle "Apply Setting to All Profiles" for a setting
  3. If another VS Code window or process removes that setting from the configurationService.allProfiles list between the this.checked guard (set via config listener) and the getValue() call, indexOf returns -1
  4. splice(-1, 1) removes the last entry in the all-profiles list (a different setting)

Fix

A PR is available: #314635

The fix adds index !== -1 guards before each splice call. This is a standard defensive pattern with zero cost.

Metadata

Metadata

Assignees

No one assigned

    Labels

    insiders-releasedPatch has been released in VS Code Insiders

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions