mirror of
https://github.com/espressif/openthread.git
synced 2026-09-22 08:57:39 +00:00
[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:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user