Skip to content

[Telemetry Logging] LegacyTagJoiner and ModernTagJoiner could cause OutOfMemoryException #7505

@iliar-turdushev

Description

@iliar-turdushev

Description

LegacyTagJoiner dynamically calculates its Count property and its GetEnumerator() method iterates over items that could change dynamically during the iteration. This could lead to OOM if not used properly. See reproduction steps.

The same issue exists in ModernTagJoiner as well.

Reproduction Steps

Add and run the following unit test. The memory will start growing and eventually an OOM will be thrown.

[Fact]
public static void OutOfMemoryTest()
{
    var joiner = new ExtendedLogger.LegacyTagJoiner { StaticTags = [] };
    joiner.SetIncomingTags(
        new List<KeyValuePair<string, object?>>
        {
            new("K1", "V1"),
            new("K2", "V2"),
        }.AsReadOnly());
    var source = joiner.Append(new KeyValuePair<string, object?>("K3", "V3"));
    joiner.EnrichmentTagCollector.AddRange(source);
}

When AddRange enumerates source that references the joiner while adding to _extraTags (an inner collection in joiner holding its items), Count increases with each added item --> the enumerator loop never terminates --> unbounded memory growth until OOM.

Expected behavior

OOM shouldn't be thrown, items from the source should be added to the joiner.

Actual behavior

An infinite loop adding items from the source to the joiner causes OOM.

Regression?

No response

Known Workarounds

If you materialize the source by invoking ToArray or ToList the items will be added to the joiner and OOM will not be thrown.

Configuration

No response

Other information

No response

Metadata

Metadata

Labels

area-telemetrybugThis issue describes a behavior which is not expected - a bug.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions