You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue was filed with GitHub Copilot assistance.
Description
In .NET 11 preview.3, LibraryImportDiagnosticsAnalyzer fails to report SYSLIB1051 for StringBuilder parameters when StringMarshalling = StringMarshalling.Utf16 is set on the LibraryImportAttribute. Without StringMarshalling, the error is correctly reported.
This is a regression from preview.2. PR #123780 moved diagnostic reporting from inline in LibraryImportGenerator to a separate LibraryImportDiagnosticsAnalyzer. The generator now discards diagnostics (discardedDiagnostics at LibraryImportGenerator.cs:297), relying on the analyzer to re-derive and report them. The analyzer fails to do so for StringBuilder when StringMarshalling.Utf16 is specified.
SYSLIB1051 is DiagnosticSeverity.Error -- a hard build failure. When the error is not reported, the generator silently produces code that compiles but gives wrong results at runtime (see "Consequence" section below).
Standalone reproduction
Note: you must use the preview.3 SDK specifically. Roslyn analyzer unit tests that run the analyzer from source may not reproduce this, since they do not use the shipped SDK binary.
usingSystem;usingSystem.Runtime.InteropServices;usingSystem.Text;Console.WriteLine("If you see this, SYSLIB1051 was NOT reported.");staticpartialclassNativeMethods{[LibraryImport("kernel32.dll",StringMarshalling=StringMarshalling.Utf16)]internalstaticpartialintGetVolumeNameForVolumeMountPointW(stringvolumeMountPoint,[Out]StringBuildervolumeName,intbufferLength);}
Expected:dotnet build fails with SYSLIB1051 ("The type 'System.Text.StringBuilder' is not supported by source-generated P/Invokes...")
Actual with .NET 11 preview.3 SDK (11.0.100-preview.3.26170.106): Build succeeds. No error.
Actual with .NET 11 preview.2 SDK (11.0.100-preview.2.26159.112): SYSLIB1051 correctly reported.
Remove StringMarshalling = StringMarshalling.Utf16 and preview.3 does correctly report SYSLIB1051.
Consequence when the error is missing
When SYSLIB1051 is absent, the generator uses a "forwarder" strategy -- it creates an inner [DllImport] that passes the StringBuilder through to the runtime marshaller. However, the generated inner DllImport omits CharSet = CharSet.Unicode. For W-suffix APIs this means UTF-16 output is marshalled as Ansi: for example, \\?\Volume{guid}\ is read as just \ (0x5C followed by 0x00 is treated as a null-terminated Ansi string).
This is what caused the silent wrong behavior in PR #126660 (commit 8ccebe9), which was caught and fixed in d694082 only because the test happened to fail, not because of any build error.
Why Roslyn analyzer unit tests may not reproduce this
The VerifyAnalyzerAsync tests in LibraryImportGenerator.UnitTests instantiate the analyzer from the locally-built source code, not from the shipped SDK binary. If the shipped preview.3 binary has a bug that the current source on main does not, the unit tests will pass while the standalone repro above fails. The reproduction requires actually using the preview.3 SDK to compile a project.
Docs gap
The official P/Invoke source generation docs do not mention StringBuilder (or CriticalHandle or HandleRef) as unsupported types. The design doc (Compatibility.md) does mention them. It would be useful for the official docs to list the types that trigger SYSLIB1051 so users know what to avoid.
SDK version matrix
SDK
SYSLIB1051 for StringBuilder + StringMarshalling.Utf16
.NET 10.0.201
Correctly reported
.NET 11 preview.2 (11.0.100-preview.2)
Correctly reported
.NET 11 preview.3 (11.0.100-preview.3)
NOT reported (this bug)
Root cause
PR #123780 (commit d97a9c1) introduced LibraryImportDiagnosticsAnalyzer as a separate Roslyn DiagnosticAnalyzer. The generator itself now discards diagnostics. The analyzer's CalculateDiagnostics method recreates SignatureContext and ManagedToNativeStubGenerator to re-derive diagnostics, but the code path for StringBuilder with StringMarshalling.Utf16 fails to produce the expected diagnostic. The exact failure point in the resolver chain was not pinpointed -- the StringMarshallingInfoProvider only handles System.String, not StringBuilder, so StringBuilder should fall through to NotSupportedResolver regardless, but somehow the diagnostic is lost when StringMarshalling is set.
Note
This issue was filed with GitHub Copilot assistance.
Description
In .NET 11 preview.3,
LibraryImportDiagnosticsAnalyzerfails to report SYSLIB1051 forStringBuilderparameters whenStringMarshalling = StringMarshalling.Utf16is set on theLibraryImportAttribute. WithoutStringMarshalling, the error is correctly reported.This is a regression from preview.2. PR #123780 moved diagnostic reporting from inline in
LibraryImportGeneratorto a separateLibraryImportDiagnosticsAnalyzer. The generator now discards diagnostics (discardedDiagnosticsat LibraryImportGenerator.cs:297), relying on the analyzer to re-derive and report them. The analyzer fails to do so forStringBuilderwhenStringMarshalling.Utf16is specified.SYSLIB1051 is
DiagnosticSeverity.Error-- a hard build failure. When the error is not reported, the generator silently produces code that compiles but gives wrong results at runtime (see "Consequence" section below).Standalone reproduction
Note: you must use the preview.3 SDK specifically. Roslyn analyzer unit tests that run the analyzer from source may not reproduce this, since they do not use the shipped SDK binary.
global.json -- pin to preview.3:
{ "sdk": { "version": "11.0.100-preview.3.26170.106", "allowPrerelease": true } }Project file:
Program.cs:
Expected:
dotnet buildfails with SYSLIB1051 ("The type 'System.Text.StringBuilder' is not supported by source-generated P/Invokes...")Actual with .NET 11 preview.3 SDK (11.0.100-preview.3.26170.106): Build succeeds. No error.
Actual with .NET 11 preview.2 SDK (11.0.100-preview.2.26159.112): SYSLIB1051 correctly reported.
Remove
StringMarshalling = StringMarshalling.Utf16and preview.3 does correctly report SYSLIB1051.Consequence when the error is missing
When SYSLIB1051 is absent, the generator uses a "forwarder" strategy -- it creates an inner
[DllImport]that passes theStringBuilderthrough to the runtime marshaller. However, the generated innerDllImportomitsCharSet = CharSet.Unicode. For W-suffix APIs this means UTF-16 output is marshalled as Ansi: for example,\\?\Volume{guid}\is read as just\(0x5C followed by 0x00 is treated as a null-terminated Ansi string).This is what caused the silent wrong behavior in PR #126660 (commit 8ccebe9), which was caught and fixed in d694082 only because the test happened to fail, not because of any build error.
Why Roslyn analyzer unit tests may not reproduce this
The
VerifyAnalyzerAsynctests inLibraryImportGenerator.UnitTestsinstantiate the analyzer from the locally-built source code, not from the shipped SDK binary. If the shipped preview.3 binary has a bug that the current source on main does not, the unit tests will pass while the standalone repro above fails. The reproduction requires actually using the preview.3 SDK to compile a project.Docs gap
The official P/Invoke source generation docs do not mention
StringBuilder(orCriticalHandleorHandleRef) as unsupported types. The design doc (Compatibility.md) does mention them. It would be useful for the official docs to list the types that trigger SYSLIB1051 so users know what to avoid.SDK version matrix
Root cause
PR #123780 (commit d97a9c1) introduced
LibraryImportDiagnosticsAnalyzeras a separate RoslynDiagnosticAnalyzer. The generator itself now discards diagnostics. The analyzer'sCalculateDiagnosticsmethod recreatesSignatureContextandManagedToNativeStubGeneratorto re-derive diagnostics, but the code path forStringBuilderwithStringMarshalling.Utf16fails to produce the expected diagnostic. The exact failure point in the resolver chain was not pinpointed -- theStringMarshallingInfoProvideronly handlesSystem.String, notStringBuilder, soStringBuildershould fall through toNotSupportedResolverregardless, but somehow the diagnostic is lost whenStringMarshallingis set.