[mesh-forwarder] fix priority queue iteration in EvictMessage() (#13397)

When `MeshForwarder::EvictMessage()` searches for an equal-or-higher
priority indirect message during buffer pool exhaustion
(`kEvictReasonNoMessageBuffer`), the inner loop calls
`mSendQueue.GetHeadForPriority(aPriority)` instead of
`mSendQueue.GetHeadForPriority(static_cast<Message::Priority>(
priority))`.

If `aPriority < priority` (for example, allocating a `low` priority
buffer when the send queue holds `normal` priority indirect messages),
`GetHeadForPriority(aPriority)` returns the head of `aPriority`
messages (`low`), immediately triggering `if (message->GetPriority() !=
priority) break;`. Consequently, `EvictMessage()` exits early without
inspecting higher-priority indirect messages and drops the incoming
packet with `kErrorNoBufs`.

This commit fixes the inner loop to use
`static_cast<Message::Priority>(priority)` so each priority bucket
from `aPriority` up to `kNumPriorities - 1` is correctly inspected.
It also adds a unit test (`TestPriorityQueueEvictIteration`) in
`tests/unit/test_priority_queue.cpp` verifying equal-or-higher
priority iteration in `PriorityQueue`.
This commit is contained in:
Jonathan Hui
2026-07-24 08:58:14 -07:00
committed by GitHub
parent 211267dbfb
commit a76515b3d4
2 changed files with 54 additions and 1 deletions
+2 -1
View File
@@ -220,7 +220,8 @@ Error MeshForwarder::EvictMessage(Message::Priority aPriority, EvictReason aEvic
for (uint8_t priority = aPriority; priority < Message::kNumPriorities; priority++)
{
// search for an equal or higher priority indirect message to evict
for (Message *message = mSendQueue.GetHeadForPriority(aPriority); message; message = message->GetNext())
for (Message *message = mSendQueue.GetHeadForPriority(static_cast<Message::Priority>(priority)); message;
message = message->GetNext())
{
if (message->GetPriority() != priority)
{
+52
View File
@@ -697,6 +697,57 @@ void TestPriorityQueue(void)
testFreeInstance(instance);
}
void TestPriorityQueueEvictIteration(void)
{
Instance *instance;
MessagePool *messagePool;
PriorityQueue queue;
Message *lowMsg;
Message *normalMsg;
Message *foundMsg = nullptr;
instance = testInitInstance();
VerifyOrQuit(instance != nullptr);
messagePool = &instance->Get<MessagePool>();
lowMsg = messagePool->Allocate(Message::kTypeIp6, 0, Message::Settings(Message::kPriorityLow));
VerifyOrQuit(lowMsg != nullptr);
normalMsg = messagePool->Allocate(Message::kTypeIp6, 0, Message::Settings(Message::kPriorityNormal));
VerifyOrQuit(normalMsg != nullptr);
queue.Enqueue(*lowMsg);
queue.Enqueue(*normalMsg);
// Verify fixed inner loop iteration: GetHeadForPriority(static_cast<Message::Priority>(priority))
for (uint8_t priority = Message::kPriorityLow; priority < Message::kNumPriorities; priority++)
{
for (Message *message = queue.GetHeadForPriority(static_cast<Message::Priority>(priority)); message;
message = message->GetNext())
{
if (message->GetPriority() != priority)
{
break;
}
if (message == normalMsg)
{
foundMsg = message;
break;
}
}
}
VerifyOrQuit(foundMsg == normalMsg, "Failed to inspect equal-or-higher priority message in PriorityQueue");
queue.Dequeue(*lowMsg);
queue.Dequeue(*normalMsg);
lowMsg->Free();
normalMsg->Free();
testFreeInstance(instance);
}
// NOLINTEND(modernize-loop-convert)
} // namespace ot
@@ -704,6 +755,7 @@ void TestPriorityQueue(void)
int main(void)
{
ot::TestPriorityQueue();
ot::TestPriorityQueueEvictIteration();
printf("All tests passed\n");
return 0;
}