Skip to content

[Microsoft.Gen.Logging] [LogProperties(Transitive = true)] crashes the compiler with a stack overflow on a cycle through an inherited property (e.g. a System.Type property) #7858

Open

Description

@AdCodicem

Description

With [LogProperties(Transitive = true)], the [LoggerMessage] generator reports a cycle in the logged type (LOGGEN021) when the cycle goes through a property the type declares. When the cycle goes through a property declared on a base class, whose type is the derived class, the cycle is not detected. The generator recurses until the compiler process dies with Stack overflow. A property of type System.Type is enough to hit it, through the inherited properties of the reflection types.

With the shared compiler server, the server process dies as well (Error reading response: Reached end of stream before end of read.). MSBuild then falls back to csc, which dies the same way.

Reproduction Steps

Full project, with a repro.sh: https://github.com/AdCodicem/dotnet-upstream-repros/tree/main/extensions-genlogging-transitive-stack-overflow

public class Node
{
    public Leaf? Next { get; init; } // declared on the base class, of the derived type
}

public sealed class Leaf : Node;

public sealed class Holder
{
    public Leaf? Leaf { get; init; }
}

internal static partial class Log
{
    [LoggerMessage(Level = LogLevel.Information, Message = "Received")]
    public static partial void Received(ILogger logger, [LogProperties(Transitive = true)] Holder holder);
}

The same happens with:

public sealed class Message
{
    public Type? Kind { get; init; }
}

[LoggerMessage(Level = LogLevel.Information, Message = "Received")]
public static partial void Received(ILogger logger, [LogProperties(Transitive = true)] Message message);

Expected behavior

LOGGEN021, as when Next is declared on Leaf itself:

Library.cs(17,99): error LOGGEN021: Parameter "holder" annotated for properties logging within logging method "Received" has type with a cycle in its hierarchy: Leaf? ⇆ Leaf? (https://aka.ms/dotnet-extensions-warnings/LOGGEN021)

Actual behavior

Stack overflow.
   at Microsoft.Gen.Logging.Parsing.Parser.<ProcessLogPropertiesForParameter>g__GetTypePropertiesToLog|17_1(...)    <- 1376 times
   at Microsoft.Gen.Logging.Parsing.Parser.ProcessLogPropertiesForParameter(...)
   at Microsoft.Gen.Logging.Parsing.Parser.GetLogTypes(...)
   at Microsoft.Gen.Logging.LoggingGenerator.HandleAnnotatedTypes(...)

The build reports this as hundreds of error : lines from Microsoft.CSharp.Core.targets, one per stack frame. The same trace appears for the System.Type property.

Regression?

Not known.

Known Workarounds

Do not use Transitive on a type that reaches such a cycle, or mark the property [LogPropertyIgnore]. Note that under Transitive the ignored property is then logged whole, as reported in #7856.

Configuration

  • Windows 11 (10.0.26200), x64, .NET SDK 10.0.402 (Roslyn 5.9), net10.0.
  • Microsoft.Extensions.Telemetry.Abstractions 10.11.0.

Other information

On main (42a0f35), GetTypePropertiesToLog walks the type and then its base types (namedType = namedType.BaseType). Before recursing into a property's type, it adds namedType, the type currently walked, to typesChain (Parser.LogProperties.cs#L278), rather than type, the type being expanded. For a property declared on a base class, the chain therefore holds Node and never Leaf, so the check typesChain.Contains(extractedType) (L261) never matches. Adding type as well, or instead, would probably close it. A depth limit would also stop a large acyclic graph (System.Type's) from growing without bound.

#4231 fixed a similar crash in the metering generator.

Investigation and write-up assisted by Claude (Anthropic); the linked repro was run on Windows 11 (10.0.26200), .NET SDK 10.0.402, Microsoft.Extensions.Telemetry.Abstractions 10.11.0, and I reviewed this report.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions