Skip to content

RadioMedium: fix two null dereferences in the communication cache - #1298

Merged
torokati44 merged 2 commits into
inet-framework:masterfrom
torokati44:listeningfilter-crash-fix
Oct 13, 2026
Merged

torokati44 merged 2 commits into
inet-framework:masterfrom
torokati44:listeningfilter-crash-fix

Conversation

@torokati44

@torokati44 torokati44 commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

RadioMedium can crash with a segfault in two situations, because two code paths read per-radio cache entries that the medium never creates. addTransmission() caches no arrival and no listening at the transmitting radio itself, and none at a radio without a receiver, such as NoiseSource. Two other paths assume those entries exist:

  • With listeningFilter = true, when a radio changes its listening (for example, it switches channel), the handler refreshes the radio's listening for every cached transmission, including the radio's own. Its arrival is null.
  • addRadio() creates a listening at the new radio for every cached transmission, through the radio's receiver. For a NoiseSource the receiver is null.

Both crashes need a transmission still in the cache, that is, before the medium purges it after its interference end time. The first needs a listening change within that window after the radio's own transmission. The second needs a receiver-less radio created at runtime (for example by the ScenarioManager create-module command), because the cache is empty at network initialization. Both reproduce on master. The transmission purge mode proposed in #1281 widens the first window: with it, the crash happens even 0.5 s after the transmission, so this pull request should land first.

Each fix skips the missing case, as addTransmission(), sendToRadio() and pickUpSignals() already do. Neither changes behavior anywhere else: each skipped case crashed before. Neither touches an interface, a parameter or packet content.

Commits

  1. physicallayer: fix: skip own transmissions on a listening change: fixes the listening-change handler, with the module test RadioMedium_ListeningFilter_1.
  2. physicallayer: fix: add a radio without a receiver during transmissions: fixes addRadio(), with the module test RadioMedium_AddRadioWithoutReceiver_1.

Each commit is a fix with its own regression test. Neither depends on the other.

Evidence

Each test segfaults on its parent commit and passes on its own commit:

cd tests/module && inet_run_module_tests -m debug -f 'RadioMedium_'

At the head, the related module tests pass (87 PASS):

inet_run_module_tests -m debug -f 'Radio|Ieee80211|Medium|Wireless|Apsk|Ideal|Noise|Scenario'

No fingerprint moves. The only configuration with listeningFilter = true, and the one with a NoiseSource, pass unchanged (7 rows, OK):

cd tests/fingerprint && ./fingerprinttest -F tyf -m 'wireless/filtering' -m 'wireless/analogmodel'

Both commits build in debug and release mode. check-commits.sh and check-classification.sh pass on the series.


Devin Review

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Devin Review: 1 flag

Not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

communicationCache->setCachedListening(radio, transmission, listening);
});
// like addTransmission(), cache no arrival and no listening at a radio without a receiver
if (radio->getReceiver() != nullptr) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A receiver cannot be null.

/**
 * Returns the receiver part of this radio. This function never returns nullptr.
 */
virtual const IReceiver *getReceiver() const = 0;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NoiseSource breaks this contract, and it is already accomodated for: a2a3925f96

Should the "non-radio transmitter/receiver" change (mentioned yesterday) be done first then?

With listeningFilter = true, a radio that changes its listening, for
example by switching channel, while one of its own transmissions is
still in the communication cache crashes the simulation.
RadioMedium::receiveSignal() refreshes the cached listening of the radio
for every cached transmission, but addTransmission() caches no arrival
at the transmitter itself, so the handler dereferences a null arrival.
The handler now skips the radio's own transmissions, as
addTransmission(), sendToRadio() and pickUpSignals() already do.

The window is as long as a transmission stays cached, which is until
the medium purges it after its interference end time.

Reproduce: run the new module test RadioMedium_ListeningFilter_1. Host1
pings host2 at 0.5s, and both radios switch channel at 0.502s. Before
this commit, the run segfaults in RadioMedium::receiveSignal().

No fingerprint moves: the only configuration with listeningFilter = true,
examples/wireless/filtering, never reaches the skipped case, and its four
rows pass unchanged.

Change: src.physicallayer.RadioMedium | behavior.change.fix | test
Adding a radio without a receiver, such as a NoiseSource, to the radio
medium while transmissions are in its communication cache crashes the
simulation. RadioMedium::addRadio() creates a listening at the new
radio for every cached transmission, and dereferences the radio's null
receiver to do so. addRadio() now caches no arrival, interval or listening at
such a radio, as addTransmission() already does for a transmission that
starts after the radio was added.

At network initialization the cache is empty, so the crash needs a
radio that is created at runtime, for example by the ScenarioManager
create-module command, within a transmission's purge window.

Reproduce: run the new module test RadioMedium_AddRadioWithoutReceiver_1.
Host1 pings host2 at 0.5s, and a NoiseSource is created at 0.502s.
Before this commit, the run segfaults in RadioMedium::addRadio().

No fingerprint moves: the change only affects radios added at runtime
without a receiver, which crashed before. The rows of the noise
configuration of showcases/wireless/analogmodel pass unchanged.

Change: src.physicallayer.RadioMedium | behavior.change.fix | test
@torokati44
torokati44 force-pushed the listeningfilter-crash-fix branch from 744b545 to d7ee856 Compare October 13, 2026 10:58
@torokati44
torokati44 merged commit 165cec4 into inet-framework:master Oct 13, 2026
15 checks passed
@torokati44
torokati44 deleted the listeningfilter-crash-fix branch October 13, 2026 13:21
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.

2 participants