Skip to content

removeTagsWherePresent<T>() removes region tags of every type, not just T #1184

Description

@torokati44

Type: bug
Component: src/inet/common/packet/tag
Version: INET 4.7.0 (dfe270b21f, 2026-07-07)

The bug

SharingRegionTagSet::removeTagsWherePresent<T>() filters its return value by T, but not its removal:

template<typename T>
inline std::vector<SharingRegionTagSet::RegionTag<T>> SharingRegionTagSet::removeTagsWherePresent(b offset, b length)
{
    auto result = getAllTags<T>(offset, length);
    clearTags(offset, length);          // <-- not templated
    return result;
}

clearTags() (SharingRegionTagSet.cc) truncates, splits or erases every region intersecting [offset, offset+length) with no type check anywhere in the loop. So the call removes all region tags over the range, returns only those of type T, and the caller never learns the rest are gone.

It reaches users through Chunk::removeTagsWherePresent<T>() (Chunk.h:810) and Packet::removeRegionTagsWherePresent<T>() (Packet.h:1469), which both forward straight to it.

The single-tag operations next to it are type-correct - removeTag<T>() and removeTagIfPresent<T>() go through getTagIndex(typeid(T), ...) - so the inconsistency looks accidental.

Reproduction

SharingRegionTagSet tags;
tags.addTag<CreationTimeTag>(b(0), b(1000))->setCreationTime(42);
tags.addTag<PropagationTimeTag>(b(0), b(1000));   // any second type

auto removed = tags.removeTagsWherePresent<CreationTimeTag>(b(0), b(1000));

ASSERT(removed.size() == 1);        // passes
ASSERT(tags.getNumTags() == 1);     // FAILS: 0 -- the PropagationTimeTag is gone too

Affected call sites

src/inet/common/ResidenceTimeMeasurer.cc:55 and :75

packet->removeRegionTagsWherePresent<ResidenceTimeTag>(offset, length);

with offset = b(0), length = packet->getDataLength(), so it clears the packet's whole region tag set over the data range. PacketEventTag (FlowMeasurementStarter.cc:90) and FlowTag (FlowTag.cc:17) live in that same set, so running residence-time measurement alongside flow measurement destroys the flow tags at every measurementEnd and every packetDropped.

src/inet/applications/tcpapp/TcpEchoApp.cc:124

content->removeTagsWherePresent<CreationTimeTag>(b(0), content->getChunkLength());

Any other region tag on the echoed content goes with it.

Why no test catches it

tests/packet/UnitTest.cc:1793 ("11. removeTagsWherePresent") only ever puts CreationTimeTag in the set, so the type-blindness is invisible to it. The reproduction above is that test with a second tag type added.

Suggested fix

Add a type-aware clearTags() overload and call it from removeTagsWherePresent<T>(). The four intersection cases are already written; they need the typeInfo != typeid(*tagObject) -> continue guard that getTagIndex() already uses:

void SharingRegionTagSet::clearTags(const std::type_info& typeInfo, b offset, b length);

template<typename T>
inline std::vector<SharingRegionTagSet::RegionTag<T>> SharingRegionTagSet::removeTagsWherePresent(b offset, b length)
{
    auto result = getAllTags<T>(offset, length);
    clearTags(typeid(T), offset, length);
    return result;
}

The untyped clearTags(offset, length) stays as it is - it is type-blind by design, backing the public clearTags() / clearRegionTags().

This is behaviour-changing for anyone relying on the wipe, so it probably wants a WHATSNEW line.

Workaround until then: iterate getAllTags<T>(offset, length) and call removeTag<T>(region.getOffset(), region.getLength()) per region.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions