提交 5f108382 编写于 作者: J Jared Parsons

Merge pull request #9028 from TyOverby/pe-write-exception-stabil-2

Handle PE writing exceptions by appending a diagnostic (base against stabilzation)
......@@ -4675,4 +4675,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_TooManyUserStrings" xml:space="preserve">
<value>Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals.</value>
</data>
</root>
\ No newline at end of file
<data name="ERR_PeWritingFailure" xml:space="preserve">
<value>An error occurred while writing the output file.</value>
</data>
</root>
......@@ -1320,5 +1320,6 @@ internal enum ErrorCode
ERR_InvalidPathMap = 8101,
ERR_PublicSignButNoKey = 8102,
ERR_TooManyUserStrings = 8103,
ERR_PeWritingFailure = 8104,
}
}
......@@ -202,6 +202,7 @@ public override void ReportDuplicateMetadataReferenceWeak(DiagnosticBag diagnost
public override int ERR_MetadataNameTooLong { get { return (int)ErrorCode.ERR_MetadataNameTooLong; } }
public override int ERR_EncReferenceToAddedMember { get { return (int)ErrorCode.ERR_EncReferenceToAddedMember; } }
public override int ERR_TooManyUserStrings { get { return (int)ErrorCode.ERR_TooManyUserStrings; } }
public override int ERR_PeWritingFailure { get { return (int)ErrorCode.ERR_PeWritingFailure; } }
public override void ReportInvalidAttributeArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, AttributeData attribute)
{
......
......@@ -54,8 +54,8 @@ class C
options: options);
comp.VerifyEmitDiagnostics(
// error CS7028: Error signing output with public key from container 'RoslynTestContainer' -- This is a test IOException
Diagnostic(ErrorCode.ERR_PublicKeyContainerFailure).WithArguments("RoslynTestContainer", "This is a test IOException").WithLocation(1, 1));
// error CS8104: An error occurred while writing the Portable Executable file.
Diagnostic(ErrorCode.ERR_PeWritingFailure).WithArguments("This is a test IOException").WithLocation(1, 1));
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
......@@ -2699,10 +2698,16 @@ public void BrokenOutStream()
var compilation = CreateCompilationWithMscorlib(source);
var output = new BrokenStream();
Assert.Throws<IOException>(() => compilation.Emit(output));
var result = compilation.Emit(output);
result.Diagnostics.Verify(
// error CS8104: An error occurred while writing the Portable Executable file.
Diagnostic(ErrorCode.ERR_PeWritingFailure).WithArguments("I/O error occurred.").WithLocation(1, 1));
output.BreakHow = 1;
Assert.Throws<NotSupportedException>(() => compilation.Emit(output));
result = compilation.Emit(output);
result.Diagnostics.Verify(
// error CS8104: An error occurred while writing the Portable Executable file.
Diagnostic(ErrorCode.ERR_PeWritingFailure).WithArguments("Specified method is not supported.").WithLocation(1, 1));
// disposed stream is not writable
var outReal = new MemoryStream();
......@@ -2949,5 +2954,27 @@ static int M(dynamic d, object o)
AssertEx.Equal(expectedNames, actualNames);
}
}
[Fact]
[WorkItem(3240, "https://github.com/dotnet/roslyn/pull/8227")]
public void FailingEmitter()
{
string source = @"
public class X
{
public static void Main()
{
}
}";
var compilation = CreateCompilationWithMscorlib(source);
var broken = new BrokenStream();
broken.BreakHow = 0;
var result = compilation.Emit(broken);
Assert.False(result.Success);
result.Diagnostics.Verify(
// error CS8104: An error occurred while writing the Portable Executable file.
Diagnostic(ErrorCode.ERR_PeWritingFailure).WithArguments("I/O error occurred.").WithLocation(1, 1));
}
}
}
......@@ -20,71 +20,4 @@ public Stream GetXmlInclude(SyntaxTree syntaxTree, string xmlIncludeFile)
throw new NotImplementedException();
}
}
internal class BrokenStream : Stream
{
public int BreakHow;
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override void Flush()
{
}
public override long Length
{
get
{
return 0;
}
}
public override long Position
{
get
{
return 0;
}
set
{
if (BreakHow == 1)
throw new NotSupportedException();
}
}
public override int Read(byte[] buffer, int offset, int count)
{
return 0;
}
public override long Seek(long offset, SeekOrigin origin)
{
return 0;
}
public override void SetLength(long value)
{
if (BreakHow == 2)
throw new IOException();
}
public override void Write(byte[] buffer, int offset, int count)
{
if (BreakHow == 0)
throw new IOException();
}
}
}
......@@ -1844,17 +1844,8 @@ private static EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool su
{
Debug.Assert(Options.StrongNameProvider != null);
// Targeted try-catch for errors during CreateInputStream as found in TFS 1140649
// TODO: Put this wrapping in PeWriter to catch all potential PE writing exceptions
try
{
signingInputStream = Options.StrongNameProvider.CreateInputStream();
retStream = signingInputStream;
}
catch (Exception e)
{
throw new Cci.PeWritingException(e);
}
signingInputStream = Options.StrongNameProvider.CreateInputStream();
retStream = signingInputStream;
}
else
{
......@@ -1917,9 +1908,8 @@ private static EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool su
}
catch (Cci.PeWritingException e)
{
// Targeted fix for TFS 1140649
// TODO: Add resource and better error message for a variety of PE exceptions
diagnostics.Add(StrongNameKeys.GetError(StrongNameKeys.KeyFilePath, StrongNameKeys.KeyContainer, e.Message, MessageProvider));
diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_PeWritingFailure, Location.None, e.Message));
return false;
}
catch (ResourceException e)
{
......
......@@ -203,6 +203,7 @@ public DiagnosticInfo FilterDiagnosticInfo(DiagnosticInfo diagnosticInfo, Compil
public abstract int ERR_MetadataNameTooLong { get; }
public abstract int ERR_EncReferenceToAddedMember { get; }
public abstract int ERR_TooManyUserStrings { get; }
public abstract int ERR_PeWritingFailure { get; }
public abstract void ReportInvalidAttributeArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, AttributeData attribute);
public abstract void ReportInvalidNamedArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int namedArgumentIndex, ITypeSymbol attributeClass, string parameterName);
......
......@@ -12,6 +12,7 @@
using Microsoft.CodeAnalysis;
using Roslyn.Utilities;
using EmitContext = Microsoft.CodeAnalysis.Emit.EmitContext;
using Microsoft.CodeAnalysis.CodeGen;
namespace Microsoft.Cci
{
......@@ -88,10 +89,17 @@ internal sealed class PeWriter
// If PDB writer is given, we have to have PDB path.
Debug.Assert(nativePdbWriterOpt == null || pdbPathOpt != null);
var peWriter = new PeWriter(context.Module.Properties, context.Module.Win32Resources, context.Module.Win32ResourceSection, pdbPathOpt, deterministic);
var mdWriter = FullMetadataWriter.Create(context, messageProvider, allowMissingMethodBodies, deterministic, getPortablePdbStreamOpt != null, cancellationToken);
try
{
var peWriter = new PeWriter(context.Module.Properties, context.Module.Win32Resources, context.Module.Win32ResourceSection, pdbPathOpt, deterministic);
var mdWriter = FullMetadataWriter.Create(context, messageProvider, allowMissingMethodBodies, deterministic, getPortablePdbStreamOpt != null, cancellationToken);
return peWriter.WritePeToStream(mdWriter, getPeStream, getPortablePdbStreamOpt, nativePdbWriterOpt);
return peWriter.WritePeToStream(mdWriter, getPeStream, getPortablePdbStreamOpt, nativePdbWriterOpt);
}
catch (Exception ex) when (!(ex is PdbWritingException || ex is ResourceException || ex is PermissionSetFileReadException))
{
throw new PeWritingException(ex);
}
}
private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream, Func<Stream> getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt)
......
......@@ -1682,6 +1682,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
ERR_InvalidPathMap = 37253
ERR_PublicSignNoKey = 37254
ERR_TooManyUserStrings = 37255
ERR_PeWritingFailure = 37256
ERR_LastPlusOne
......
......@@ -480,6 +480,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return ERRID.ERR_TooManyUserStrings
End Get
End Property
Public Overrides ReadOnly Property ERR_PeWritingFailure As Integer
Get
Return ERRID.ERR_PeWritingFailure
End Get
End Property
End Class
End Namespace
......@@ -5347,4 +5347,7 @@
<data name="ERR_TooManyUserStrings" xml:space="preserve">
<value>Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string or XML literals.</value>
</data>
</root>
\ No newline at end of file
<data name="ERR_PeWritingFailure" xml:space="preserve">
<value>An error occurred while writing the output file.</value>
</data>
</root>
......@@ -54,7 +54,8 @@ End Class
</compilation>, options:=options)
comp.VerifyEmitDiagnostics(
Diagnostic(ERRID.ERR_PublicKeyContainerFailure).WithArguments("RoslynTestContainer", "This is a test IOException").WithLocation(1, 1))
Diagnostic(ERRID.ERR_PeWritingFailure).WithArguments("This is a test IOException").WithLocation(1, 1))
End Sub
End Class
......@@ -2923,5 +2923,30 @@ End Class
End Using
End Sub
<Fact>
Public Sub FailingEmitter()
' Check that Compilation.Emit actually produces compilation errors.
Dim compilation = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(
<compilation>
<file name="a.vb">
Module M1
Sub Main()
End Sub
End Module
</file>
</compilation>)
Dim emitResult As EmitResult
Using output = New BrokenStream()
output.BreakHow = 0
emitResult = compilation.Emit(output, Nothing, Nothing, Nothing)
End Using
CompilationUtils.AssertTheseDiagnostics(emitResult.Diagnostics,
<expected>
BC37256: An error occurred while writing the output file.
</expected>)
End Sub
End Class
End Namespace
......@@ -362,5 +362,13 @@ public override int ERR_TooManyUserStrings
throw new NotImplementedException();
}
}
public override int ERR_PeWritingFailure
{
get
{
throw new NotImplementedException();
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
namespace Roslyn.Test.Utilities
{
internal class BrokenStream : Stream
{
public int BreakHow;
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override void Flush()
{
}
public override long Length
{
get
{
return 0;
}
}
public override long Position
{
get
{
return 0;
}
set
{
if (BreakHow == 1)
throw new NotSupportedException();
}
}
public override int Read(byte[] buffer, int offset, int count)
{
return 0;
}
public override long Seek(long offset, SeekOrigin origin)
{
return 0;
}
public override void SetLength(long value)
{
if (BreakHow == 2)
throw new IOException();
}
public override void Write(byte[] buffer, int offset, int count)
{
if (BreakHow == 0)
throw new IOException();
}
}
}
......@@ -60,6 +60,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Pdb\MockSymWriter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Pdb\PdbTestUtilities.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Pdb\PdbValidation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Pe\BrokenStream.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Syntax\SourceUtilities.cs" />
<Compile Include="$(MSBuildThisFileDirectory)TempFiles\DisposableDirectory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)TempFiles\DisposableFile.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册