Skip to content

Bug: ribbon-controller-engines-null-unsafe #507

Description

@drmoisan
  • Work Mode: minor-audit

Summary

RibbonController.Engines is declared internal IAppItemEngines Engines => Globals.Engines; with no null guard on Globals, unlike its sibling properties SB and Triage in the same file which both use Globals?.. Any ribbon callback that reaches Engines before SetGlobals has run throws NullReferenceException.

Environment

  • OS/version: Windows 11, Outlook desktop (VSTO add-in host)
  • Runtime: .NET Framework 4.8.1, TaskMaster VSTO add-in
  • Command/flags used: Outlook Explorer ribbon, Spam Manager and Triage configuration menus
  • Data source or fixture: Live Outlook profile during add-in startup

Steps to Reproduce

  1. Reload the TaskMaster add-in so the ribbon is constructed before the controller's Globals is assigned.
  2. Invoke any callback that routes through RibbonController.Engines - TestSpam_Click, SpamBayesEnabled_Click, SpamBayesEnabled_GetPressed, SpamSaveNetwork_Click, SpamSaveLocal_Click, GetSaveLocation_Click, TriageEnabled_Click, TriageEnabled_GetPressed, TriageSaveNetwork_Click, TriageSaveLocal_Click, or TriageGetSaveLocation_Click.
  3. Observe the NullReferenceException.

Expected Behavior

Engines behaves like its siblings and returns null rather than throwing when Globals has not yet been assigned, so callers can guard. The sibling precedent is already in the same file:

return Globals?.Engines?.InboxEngines?.TryGetValue("Spam", out var engine) ?? false
    ? engine as SpamBayes
    : null;

Actual Behavior

internal IAppItemEngines Engines => Globals.Engines;

(TaskMaster/Ribbon/RibbonController.Intelligence.cs, Spam Manager region.)

Globals is unguarded, so the property throws instead of returning null.

Logs / Screenshots

  • Attached minimal logs or snippet
  • Snippet:
System.NullReferenceException: Object reference not set to an instance of an object.
   at TaskMaster.RibbonController.get_Engines()

Impact / Severity

  • Blocker
  • High
  • Medium
  • Low

The reachable window is narrower than the one in issue #503 (it requires the callback to run before SetGlobals rather than merely before InitAsync), and the affected callbacks are in configuration submenus rather than primary commands. It is nevertheless a real inconsistency with the sibling properties and an avoidable throw.

Source

From: docs/features/potential/2026-08-08-ribbon-controller-engines-null-unsafe.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions