Skip to content

Official package SourceLink checksums require CR/LF normalization #129023

@richlander

Description

@richlander

Description

Several official .NET package PDBs appear to contain source document checksums computed over CRLF-normalized source files, while SourceLink points at GitHub raw URLs that serve LF-normalized blobs.

This means strict SourceLink/PDB byte verification fails, but the same files verify after CR/LF normalization. This does not look like source-content drift; it looks like line-ending drift between official build inputs and the Git blob bytes addressed by SourceLink.

This was found with dotnet-inspect 0.9.0, which reports both strict content mismatches and CR/LF-normalized matches.

Repro

Install/use dotnet-inspect 0.9.0 or newer:

dotnet tool install -g dotnet-inspect --version 0.9.0

Run SourceLink Integrity on a runtime-owned package:

dotnet-inspect library System.Text.Json.dll --package System.Text.Json -S "SourceLink Integrity"

Observed output shape:

## SourceLink Integrity

| Field | Value |
| ----- | ----- |
| Mismatched | 0 |
| CR/LF Mismatch | 338 normalized |
| Status | Partial |
| Unverifiable | 2 |
| Verified | 338 |

A package with no unverifiable source documents shows the same line-ending pattern more cleanly:

dotnet-inspect library System.IO.Pipelines.dll --package System.IO.Pipelines -S "SourceLink Integrity"
| Mismatched | 0 |
| CR/LF Mismatch | 30 normalized |
| Status | Verified |
| Unverifiable | 0 |
| Verified | 30 |

Expected behavior

For SourceLink URLs pinned to immutable Git commits, the source bytes fetched from SourceLink should match the checksums recorded in the portable PDB without line-ending normalization.

Actual behavior

For every sampled source document in the affected packages, strict hash comparison fails, but comparison succeeds after normalizing LF/CRLF. For example, for System.Text.Json, all 338 verified files required CR/LF normalization.

Package sample

Representative packages tested with dotnet-inspect 0.9.0:

Package Source repo Status Verified CR/LF normalized Mismatched Unverifiable
System.Text.Json runtime Partial 338 338 0 2
System.Text.Encodings.Web runtime Partial 27 27 0 2
System.IO.Pipelines runtime Verified 30 30 0 0
System.Collections.Immutable runtime Verified 130 130 0 0
System.Memory runtime Verified 101 101 0 0
System.Buffers runtime Verified 6 6 0 0
System.Diagnostics.DiagnosticSource runtime Partial 76 76 0 2
System.Formats.Asn1 runtime Partial 42 42 0 2
Microsoft.Bcl.AsyncInterfaces runtime Verified 4 4 0 0
Microsoft.Extensions.DependencyInjection runtime Verified 42 42 0 0
Microsoft.Extensions.Logging runtime Verified 21 21 0 0
Microsoft.AspNetCore.OpenApi aspnetcore Verified 48 48 0 0
Microsoft.AspNetCore.Components aspnetcore Verified 217 217 0 0
Microsoft.AspNetCore.Components.Web aspnetcore Verified 116 116 0 0
Microsoft.CodeAnalysis.CSharp roslyn Verified 1149 1149 0 0
Microsoft.CodeAnalysis.Common roslyn Verified 1042 1042 0 0
Microsoft.CodeAnalysis.Workspaces.Common roslyn Verified 1567 1567 0 0
Microsoft.Extensions.AI.OpenAI extensions Verified 24 24 0 0
Microsoft.Extensions.AI extensions Verified 103 103 0 0
Microsoft.Extensions.Caching.Hybrid extensions Verified 30 30 0 0

This appears to affect multiple .NET repos, not just dotnet/runtime or dotnet/extensions.

Control packages

This does not appear to be a dotnet-inspect artifact. Some packages verify with strict byte-for-byte SourceLink/PDB checksums without CR/LF normalization:

Package Group Status Verified CR/LF normalized Mismatched Unverifiable
Markout third-party Verified 70 0 0 0
MarkdownTable.Formatting third-party Verified 22 0 0 0
NuGetFetch third-party Verified 12 0 0 0

For comparison, Newtonsoft.Json also shows the CR/LF-normalized pattern (240/240 verified after normalization), so the issue is not unique to .NET-owned packages. The .NET-owned sample above is included because it demonstrates the same pattern across runtime, aspnetcore, roslyn, and extensions packages.

Why this likely happens

The repo settings generally normalize text into Git but do not force *.cs working-tree files to LF:

  • dotnet/runtime: *.cs text diff=csharp, no eol=lf
  • dotnet/extensions: *.cs text=auto diff=csharp, no eol=lf
  • dotnet/aspnetcore: * text=auto, no *.cs eol=lf
  • dotnet/roslyn: *.cs diff=csharp text, no eol=lf

If official builds run from a Windows checkout or another CRLF working tree, the compiler records CRLF-based source checksums in the PDB. SourceLink then points to GitHub raw URLs for commit-pinned blobs, which are served as LF bytes.

Impact

Tools performing strict SourceLink/PDB source verification will report checksum mismatches for official .NET packages, even though the logical source content matches after line-ending normalization.

dotnet-inspect 0.9.0 now reports this explicitly as CR/LF Mismatch, but ideally official package PDB checksums would match the exact SourceLink bytes without normalization.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions