diff --git a/src/Compilers/CSharp/Test/Emit2/PDB/PDBTests.cs b/src/Compilers/CSharp/Test/Emit2/PDB/PDBTests.cs
index 78ef00e6a8aaa..2ff12f8b6fbbe 100644
--- a/src/Compilers/CSharp/Test/Emit2/PDB/PDBTests.cs
+++ b/src/Compilers/CSharp/Test/Emit2/PDB/PDBTests.cs
@@ -22,6 +22,7 @@
using Roslyn.Test.PdbUtilities;
using Roslyn.Test.Utilities;
using Roslyn.Test.Utilities.TestGenerators;
+using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.PDB
@@ -367,6 +368,83 @@ public void SymWriterErrors4()
Assert.False(result.Success);
}
+ [ConditionalTheory(typeof(WindowsOnly), Reason = ConditionalSkipReason.NativePdbRequiresDesktop)]
+ [WorkItem("https://github.com/dotnet/roslyn/issues/75237")]
+ [InlineData(0x9_999)]
+ [InlineData(0x9_000)]
+ public void NativeWriterLimit_Under(int length)
+ {
+ CompileWithMockedCustomMetadata(length).Diagnostics.Verify();
+ }
+
+ [ConditionalTheory(typeof(WindowsOnly), Reason = ConditionalSkipReason.NativePdbRequiresDesktop)]
+ [WorkItem("https://github.com/dotnet/roslyn/issues/75237")]
+ [InlineData(0x10_000)]
+ [InlineData(0x20_000)]
+ public void NativeWriterLimit_Over(int length)
+ {
+ CompileWithMockedCustomMetadata(length).Diagnostics.Verify(
+ // error CS0041: Unexpected error writing debug information -- 'Insufficient memory to continue the execution of the program.'
+ Diagnostic(ErrorCode.FTL_DebugEmitFailure).WithArguments(new OutOfMemoryException().Message).WithLocation(1, 1));
+ }
+
+ private static EmitResult CompileWithMockedCustomMetadata(int length)
+ {
+ var comp = CreateCompilation("""
+ class C
+ {
+ void M() { }
+ }
+ """);
+ return comp.Emit(
+ peStream: new MemoryStream(),
+ metadataPEStream: null,
+ pdbStream: new MemoryStream(),
+ xmlDocumentationStream: null,
+ cancellationToken: default,
+ win32Resources: null,
+ manifestResources: null,
+ options: null,
+ debugEntryPoint: null,
+ sourceLinkStream: null,
+ embeddedTexts: null,
+ rebuildData: null,
+ testData: new CompilationTestData
+ {
+ SymWriterFactory = metadataProvider =>
+ {
+ var writer = SymWriterTestUtilities.CreateUnmanagedWriter(metadataProvider);
+ return new CustomMetadataSymUnmanagedWriter(writer, new byte[length]);
+ },
+ });
+ }
+
+ [ConditionalFact(typeof(WindowsOnly), Reason = ConditionalSkipReason.NativePdbRequiresDesktop)]
+ [WorkItem("https://github.com/dotnet/roslyn/issues/75237")]
+ public void NativeWriterLimit_EndToEnd()
+ {
+ var locals = Enumerable.Range(0, 14_000)
+ .Select(i => $"""
+ var local{i} = {i};
+ M2(local{i});
+ """)
+ .Join(Environment.NewLine);
+ var source = $$"""
+ namespace N;
+ class C
+ {
+ void M1()
+ {
+ {{locals}}
+ }
+ void M2(int x) { }
+ }
+ """;
+ CreateCompilation(source, options: TestOptions.DebugDll).VerifyEmitDiagnostics(
+ // error CS0041: Unexpected error writing debug information -- 'Cannot emit native PDB for method 'N.C.M1()' because its debug metadata size 69096 is over the limit 65536.'
+ Diagnostic(ErrorCode.FTL_DebugEmitFailure).WithArguments(string.Format(CodeAnalysisResources.SymWriterMetadataOverLimit, "N.C.M1()", 69096, 65536)).WithLocation(1, 1));
+ }
+
[WorkItem(1067635, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1067635")]
[Fact]
public void SuppressDynamicAndEncCDIForWinRT()
diff --git a/src/Compilers/Core/Portable/CodeAnalysisResources.resx b/src/Compilers/Core/Portable/CodeAnalysisResources.resx
index fc24b236c5a27..c013f246a5a59 100644
--- a/src/Compilers/Core/Portable/CodeAnalysisResources.resx
+++ b/src/Compilers/Core/Portable/CodeAnalysisResources.resx
@@ -507,6 +507,9 @@
Windows PDB writer doesn't support SourceLink feature: '{0}'
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
The attribute {0} has an invalid value of {1}.
diff --git a/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs b/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs
index 5b7acff12829c..3f13fd4ff794b 100644
--- a/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs
+++ b/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs
@@ -148,6 +148,16 @@ public void SerializeDebugInfo(IMethodBody methodBody, StandaloneSignatureHandle
if (blob.Length > 0)
{
+ const int limit = 0x10_000;
+ if (blob.Length > limit)
+ {
+ throw new SymUnmanagedWriterException(string.Format(
+ CodeAnalysisResources.SymWriterMetadataOverLimit,
+ methodBody.MethodDefinition,
+ blob.Length,
+ limit));
+ }
+
_symWriter.DefineCustomMetadata(blob);
}
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf
index e27948360035c..2df3ee048a081 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf
@@ -268,6 +268,11 @@
SuppressionDescriptor musí mít ID, které není null, prázdný řetězec ani řetězec obsahující jenom prázdné znaky.
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ Pokud jsou zadané anotace prvků řazené kolekce členů s možnou hodnotou null, musí se počet anotací shodovat s kardinalitou této řazené kolekce členů.
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf
index 2f1024bd36d3f..94bb96efb0917 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf
@@ -268,6 +268,11 @@
Ein SuppressionDescriptor muss eine ID aufweisen, die weder NULL noch eine leere Zeichenfolge noch eine Zeichenfolge ist, die nur Leerzeichen enthält.
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ Wenn Nullable-Anmerkungen für Tupelelemente angegeben werden, muss die Anzahl von Anmerkungen der Kardinalität des Tupels entsprechen.
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf
index 184b373347e55..3c49dabe1c642 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf
@@ -268,6 +268,11 @@
Un elemento SuppressionDescriptor debe tener un id. que no sea NULL, una cadena vacía ni una cadena que solo contenga un espacio en blanco.
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ Si se especifican las anotaciones que aceptan valores NULL de los elementos de tupla, el número de anotaciones debe coincidir con la cardinalidad de la tupla.
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf
index bc48129b024c3..8364a6e0d57d7 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf
@@ -268,6 +268,11 @@
SuppressionDescriptor doit avoir un ID qui n'est ni une valeur null, ni une chaîne vide, ni une chaîne contenant uniquement des espaces blancs.
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ Si des annotations de type Nullable pour des éléments de tuples sont spécifiées, le nombre d'annotations doit correspondre à la cardinalité du tuple.
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf
index c55bd8e1bd77b..4e1ea7458a093 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf
@@ -268,6 +268,11 @@
L'ID di un elemento SuppressionDescriptor non deve essere Null, né una stringa vuota o una stringa composta solo da spazi vuoti.
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ Se si specificano annotazioni nullable di elementi di tupla, il numero delle annotazioni deve corrispondere alla cardinalità della tupla.
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf
index 348b8333d5d9d..bbe59f873bdcb 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf
@@ -268,6 +268,11 @@
SuppressionDescriptor では、null でも、空の文字列でも、空白のみの文字列でもない ID が必要です。
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ タプル要素の Null 許容の注釈を指定する場合、注釈の数はタプルの基数と一致する必要があります。
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf
index 6bcf6900e8733..db8f19aed58d0 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf
@@ -268,6 +268,11 @@
SuppressionDescriptor에 null, 빈 문자열 및 공백만 포함된 문자열이 아닌 ID가 있어야 합니다.
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ 튜플 요소 nullable 주석이 지정된 경우, 주석 수는 튜플의 카디널리티와 일치해야 합니다.
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf
index 17cbdb97b7166..cc98075bccb34 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf
@@ -268,6 +268,11 @@
Interfejs DiagnosticDescriptor musi mieć identyfikator, który nie ma wartości null, nie jest ciągiem pustym ani nie jest ciągiem zawierającym tylko białe znaki.
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ Jeśli określono adnotacje elementów krotki z możliwością ustawiania wartości null, liczba adnotacji musi zgadzać się z kardynalnością krotki.
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf
index 9952ed99f3eb2..52a2d40046885 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf
@@ -268,6 +268,11 @@
A ID do SuppressionDescriptor não pode ser nula, não deve ser uma cadeia de caracteres vazia nem deve ser uma cadeia de caracteres que contenha apenas espaços em branco.
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ Se as anotações anuláveis de elementos de tupla forem especificadas, o número de anotações deverá corresponder à cardinalidade da tupla.
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf
index 75e0c337d706f..7137861c3cee9 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf
@@ -268,6 +268,11 @@
SuppressionDescriptor должен иметь идентификатор, который не является значением NULL, пустой строкой или строкой, состоящей из одного пробела.
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ Если указаны аннотации элементов кортежа, допускающих значения null, то число аннотаций должно соответствовать кратности кортежа.
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf
index 6b008f54f5c42..c18509b928aee 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf
@@ -268,6 +268,11 @@
SuppressionDescriptor türünün kimliği, null veya boş bir dize ya da yalnızca boşluk içeren bir dize olmamalıdır.
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ Demet öğelerine yönelik boş değer atanabilir ek açıklamalar belirtildiyse, ek açıklamaların sayısı demetin kardinalitesiyle eşleşmelidir.
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf
index f5e63e3d44c6d..195a98abb1b34 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf
@@ -268,6 +268,11 @@
A SuppressionDescriptor 必须具有一个 ID,且该 ID 不为 null、不是空字符串且不是仅包含空格的字符串。
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ 如果已指定元组元素可以为 null 的注释,则注释的数量必须与元组基数相匹配。
diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf
index 57ee62adf5847..d0daf896b2cdd 100644
--- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf
+++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf
@@ -268,6 +268,11 @@
SuppressionDescriptor 的識別碼不得為 null、空白字串或只包含空白字元的字串。
+
+
+ Cannot emit native PDB for method '{0}' because its debug metadata size {1} is over the limit {2}.
+
+ 如果指定元組元素可為 Null 的註釋,註釋數目就必須符合元組的基數。
diff --git a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb
index 057a7f2316d38..0057d5ef01e7f 100644
--- a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb
+++ b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb
@@ -208,6 +208,31 @@ End Class
result.Diagnostics.Verify(Diagnostic(ERRID.ERR_DebugEntryPointNotSourceMethodDefinition))
End Sub
+
+
+ Public Sub NativeWriterLimit()
+ Dim locals = Enumerable.Range(0, 14_000).
+ Select(Function(i) $"
+Dim local{i} As Integer = {i}
+M2(local{i})
+").
+ Join(Environment.NewLine)
+ Dim source = $"
+Namespace N
+Class C
+ Shared Sub M1()
+ {locals}
+ End Sub
+ Shared Sub M2(x As Integer)
+ End Sub
+End Class
+End Namespace
+"
+ ' Cannot emit native PDB for method 'Public Shared Sub M1()' because its debug metadata size 69328 is over the limit 65536.
+ CreateCompilation(source, options:=TestOptions.DebugDll).VerifyEmitDiagnostics(
+ Diagnostic(ERRID.ERR_PDBWritingFailed).WithArguments(String.Format(CodeAnalysisResources.SymWriterMetadataOverLimit, "Public Shared Sub M1()", 69328, 65536)).WithLocation(1, 1))
+ End Sub
+
#End Region
diff --git a/src/Test/PdbUtilities/Writer/CustomMetadataSymUnmanagedWriter.cs b/src/Test/PdbUtilities/Writer/CustomMetadataSymUnmanagedWriter.cs
new file mode 100644
index 0000000000000..f2bf8b3032dda
--- /dev/null
+++ b/src/Test/PdbUtilities/Writer/CustomMetadataSymUnmanagedWriter.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.DiaSymReader;
+
+namespace Roslyn.Test.PdbUtilities;
+
+internal sealed class CustomMetadataSymUnmanagedWriter(SymUnmanagedWriter target, byte[] customMetadata) : DelegatingSymUnmanagedWriter(target)
+{
+ private readonly byte[] _customMetadata = customMetadata;
+
+ public override void DefineCustomMetadata(byte[] metadata)
+ {
+ base.DefineCustomMetadata(_customMetadata);
+ }
+}
diff --git a/src/Test/PdbUtilities/Writer/DelegatingSymUnmanagedWriter.cs b/src/Test/PdbUtilities/Writer/DelegatingSymUnmanagedWriter.cs
index da765c30c53cd..32ee70b2dc908 100644
--- a/src/Test/PdbUtilities/Writer/DelegatingSymUnmanagedWriter.cs
+++ b/src/Test/PdbUtilities/Writer/DelegatingSymUnmanagedWriter.cs
@@ -26,6 +26,11 @@ public override int DocumentTableCapacity
set => _target.DocumentTableCapacity = value;
}
+ public override void AddCompilerInfo(ushort major, ushort minor, ushort build, ushort revision, string name)
+ {
+ _target.AddCompilerInfo(major, minor, build, revision, name);
+ }
+
public override void Dispose() => _target.Dispose();
public override void CloseMethod() => _target.CloseMethod();
public override void CloseScope(int endOffset) => _target.CloseScope(endOffset);
diff --git a/src/Test/PdbUtilities/Writer/SymWriterTestUtilities.cs b/src/Test/PdbUtilities/Writer/SymWriterTestUtilities.cs
index 3d154fe733097..e35ac26c31719 100644
--- a/src/Test/PdbUtilities/Writer/SymWriterTestUtilities.cs
+++ b/src/Test/PdbUtilities/Writer/SymWriterTestUtilities.cs
@@ -13,5 +13,10 @@ internal static class SymWriterTestUtilities
{
public static readonly Func ThrowingFactory =
_ => throw new SymUnmanagedWriterException("xxx", new NotSupportedException(), "");
+
+ public static SymUnmanagedWriter CreateUnmanagedWriter(ISymWriterMetadataProvider metadataProvider)
+ {
+ return SymUnmanagedWriterFactory.CreateWriter(metadataProvider);
+ }
}
}