Skip to content

Fix uninitialized-pointer crash and double-free in ModuleFrn init failure paths - #808

Open
MarkRose wants to merge 1 commit into
sm0svx:masterfrom
MarkRose:fix-modulefrn-init-lifecycle
Open

Fix uninitialized-pointer crash and double-free in ModuleFrn init failure paths#808
MarkRose wants to merge 1 commit into
sm0svx:masterfrom
MarkRose:fix-modulefrn-init-lifecycle

Conversation

@MarkRose

Copy link
Copy Markdown
Contributor
  • audio_fifo was never set in the ModuleFrn constructor, only assigned
    later in initialize(). If Module::initialize() fails early (e.g. a
    version mismatch), ModuleFrn::initialize() returns before any of the
    audio pipeline members (audio_fifo, audio_splitter, audio_valve) are
    assigned, leaving them as garbage/null. The destructor then
    unconditionally calls audio_fifo->unregisterSource(),
    audio_splitter->removeSink(), and audio_valve->unregisterSink() on
    those pointers, crashing the module. Fixed by initializing audio_fifo
    to null in the constructor and guarding all three dereferences in
    moduleCleanup() with null checks.

  • When qso->initOk() returns false (any required FRN config variable is
    missing), initialize() deletes qso but leaves the member pointing at
    the freed object. The module is then destroyed, and moduleCleanup()
    uses the dangling qso pointer (audio_splitter->removeSink(qso)) and
    deletes it a second time. Fixed by nulling qso immediately after the
    delete on this failure path.

Co-Authored-By: Claude Opus 4.8 [email protected]


This PR also adds a unit test (ModuleFrnTest.cpp). It is auto-discovered and executed by the CTest suite proposed in #762 once that is merged; without that suite present the test file is inert and does not affect the build.

…lure paths

- audio_fifo was never set in the ModuleFrn constructor, only assigned
  later in initialize(). If Module::initialize() fails early (e.g. a
  version mismatch), ModuleFrn::initialize() returns before any of the
  audio pipeline members (audio_fifo, audio_splitter, audio_valve) are
  assigned, leaving them as garbage/null. The destructor then
  unconditionally calls audio_fifo->unregisterSource(),
  audio_splitter->removeSink(), and audio_valve->unregisterSink() on
  those pointers, crashing the module. Fixed by initializing audio_fifo
  to null in the constructor and guarding all three dereferences in
  moduleCleanup() with null checks.

- When qso->initOk() returns false (any required FRN config variable is
  missing), initialize() deletes qso but leaves the member pointing at
  the freed object. The module is then destroyed, and moduleCleanup()
  uses the dangling qso pointer (audio_splitter->removeSink(qso)) and
  deletes it a second time. Fixed by nulling qso immediately after the
  delete on this failure path.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@MarkRose MarkRose closed this Jul 12, 2026
@MarkRose MarkRose reopened this Jul 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant