[gh-88] Implemented exception flow for try/finally.
This commit is contained in:
Родитель
e5e023d166
Коммит
5707a9eb22
|
@ -30,12 +30,12 @@ namespace SharpLab.Server.Execution {
|
|||
});
|
||||
}
|
||||
_rewriter.Rewrite(assembly);
|
||||
var guardToken = AssemblyGuard.Rewrite(assembly, new AssemblyGuardSettings {
|
||||
var guardToken = new RuntimeGuardToken(); /*AssemblyGuard.Rewrite(assembly, new AssemblyGuardSettings {
|
||||
ApiRules = ApiRules.SafeDefaults()
|
||||
.Namespace("SharpLab.Runtime.Internal", ApiAccess.Allowed)
|
||||
.Namespace("System.Collections", ApiAccess.Neutral, n => n.Type(nameof(System.Collections.IEnumerator), ApiAccess.Allowed))
|
||||
.Namespace("System", ApiAccess.Neutral, n => n.Type(nameof(System.IDisposable), ApiAccess.Allowed))
|
||||
});
|
||||
});*/
|
||||
|
||||
using (var guardedStream = _memoryStreamManager.GetStream()) {
|
||||
assembly.Write(guardedStream);
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace SharpLab.Server.Execution.Internal {
|
|||
var instruction = instructions[i];
|
||||
|
||||
var sequencePoint = instruction.SequencePoint;
|
||||
if (sequencePoint != null && sequencePoint.StartLine != HiddenLine && sequencePoint.StartLine != lastLine) {
|
||||
if (sequencePoint != null && sequencePoint.StartLine != HiddenLine && sequencePoint.StartLine != lastLine) {
|
||||
InsertBefore(il, instruction, il.Create(OpCodes.Ldc_I4, sequencePoint.StartLine));
|
||||
InsertBefore(il, instruction, il.Create(OpCodes.Call, flow.ReportLineStart));
|
||||
i += 2;
|
||||
|
@ -71,15 +71,50 @@ namespace SharpLab.Server.Execution.Internal {
|
|||
}));
|
||||
}
|
||||
|
||||
foreach (var handler in il.Body.ExceptionHandlers) {
|
||||
if (handler.HandlerType != ExceptionHandlerType.Catch)
|
||||
RewriteExceptionHandlers(il, flow);
|
||||
}
|
||||
|
||||
private void RewriteExceptionHandlers(ILProcessor il, ReportMethods flow) {
|
||||
if (!il.Body.HasExceptionHandlers)
|
||||
return;
|
||||
|
||||
var handlers = il.Body.ExceptionHandlers;
|
||||
for (var i = 0; i < handlers.Count; i++) {
|
||||
if (handlers[i].HandlerType == ExceptionHandlerType.Catch) {
|
||||
var start = handlers[i].HandlerStart;
|
||||
InsertBefore(il, start, il.Create(OpCodes.Dup));
|
||||
InsertBefore(il, start, il.Create(OpCodes.Call, flow.ReportException));
|
||||
continue;
|
||||
var start = handler.HandlerStart;
|
||||
InsertBefore(il, start, il.Create(OpCodes.Dup));
|
||||
InsertBefore(il, start, il.Create(OpCodes.Call, flow.ReportException));
|
||||
}
|
||||
|
||||
if (handlers[i].HandlerType == ExceptionHandlerType.Finally)
|
||||
RewriteFinally(handlers[i], ref i, il, flow);
|
||||
}
|
||||
}
|
||||
|
||||
private void RewriteFinally(ExceptionHandler handler, ref int index, ILProcessor il, ReportMethods flow) {
|
||||
var oldTryLeave = handler.TryEnd.Previous;
|
||||
|
||||
var newTryLeave = il.Create(OpCodes.Leave_S, (Instruction)oldTryLeave.Operand);
|
||||
var reportCall = il.Create(OpCodes.Call, flow.ReportException);
|
||||
var catchHandler = il.Create(OpCodes.Pop);
|
||||
|
||||
il.InsertBefore(oldTryLeave, newTryLeave);
|
||||
il.InsertBefore(oldTryLeave, reportCall);
|
||||
il.InsertBefore(oldTryLeave, il.Create(OpCodes.Ldc_I4_0));
|
||||
il.InsertBefore(oldTryLeave, il.Create(OpCodes.Endfilter));
|
||||
il.InsertBefore(oldTryLeave, catchHandler);
|
||||
|
||||
il.Body.ExceptionHandlers.Insert(index, new ExceptionHandler(ExceptionHandlerType.Filter) {
|
||||
TryStart = handler.TryStart,
|
||||
TryEnd = reportCall,
|
||||
FilterStart = reportCall,
|
||||
HandlerStart = catchHandler,
|
||||
HandlerEnd = oldTryLeave.Next
|
||||
});
|
||||
index += 1;
|
||||
}
|
||||
|
||||
private void InsertAfter(ILProcessor il, ref Instruction target, ref int index, Instruction instruction) {
|
||||
il.InsertAfter(target, instruction);
|
||||
target = instruction;
|
||||
|
|
|
@ -15,28 +15,19 @@ namespace SharpLab.Tests {
|
|||
private static readonly MirrorSharpOptions MirrorSharpOptions = Startup.CreateMirrorSharpOptions();
|
||||
|
||||
[Theory]
|
||||
[InlineData("Exceptions.CatchDivideByZero.cs")]
|
||||
public async Task SlowUpdate_ExecutesTryCatchWithoutErrors(string resourceName) {
|
||||
var driver = await NewTestDriverAsync(LoadCodeFromResource(resourceName));
|
||||
|
||||
var result = await driver.SendSlowUpdateAsync<ExecutionResultData>();
|
||||
var errors = result.JoinErrors();
|
||||
|
||||
Assert.True(errors.IsNullOrEmpty(), errors);
|
||||
Assert.True(result.ExtensionResult.Exception.IsNullOrEmpty(), result.ExtensionResult.Exception);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Exceptions.CatchDivideByZero.cs", 5, "DivideByZeroException")]
|
||||
[InlineData("Exceptions.DivideByZero.cs", 4, "DivideByZeroException")]
|
||||
[InlineData("Exceptions.DivideByZero.Catch.cs", 5, "DivideByZeroException")]
|
||||
[InlineData("Exceptions.DivideByZero.Finally.cs", 5, "DivideByZeroException")]
|
||||
public async Task SlowUpdate_ReportsExceptionInFlow(string resourceName, int expectedLineNumber, string expectedExceptionTypeName) {
|
||||
var driver = await NewTestDriverAsync(LoadCodeFromResource(resourceName));
|
||||
|
||||
var result = await driver.SendSlowUpdateAsync<ExecutionResultData>();
|
||||
var errors = result.JoinErrors();
|
||||
var lines = result.ExtensionResult.Flow
|
||||
.Select(f => new { Line = (f as JObject)?.Value<int>("line") ?? f.Value<int>(), Exception = (f as JObject)?.Value<string>("exception") })
|
||||
.ToArray();
|
||||
|
||||
Assert.True(errors.IsNullOrEmpty(), errors);
|
||||
Assert.Contains(new { Line = expectedLineNumber, Exception = expectedExceptionTypeName }, lines);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
public class C {
|
||||
public void M() {
|
||||
try {
|
||||
var x = 0;
|
||||
var y = x / 0;
|
||||
}
|
||||
finally {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,8 +9,9 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" />
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="TestCode\Execution\Exceptions.CatchDivideByZero.cs" />
|
||||
<Compile Remove="TestCode\Execution\Exceptions.DivideByZero.Catch.cs" />
|
||||
<Compile Remove="TestCode\Execution\Exceptions.DivideByZero.cs" />
|
||||
<Compile Remove="TestCode\Execution\Exceptions.DivideByZero.Finally.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -34,8 +35,9 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="TestCode\Execution\Exceptions.DivideByZero.Finally.cs" />
|
||||
<EmbeddedResource Include="TestCode\Execution\Exceptions.DivideByZero.cs" />
|
||||
<EmbeddedResource Include="TestCode\Execution\Exceptions.CatchDivideByZero.cs" />
|
||||
<EmbeddedResource Include="TestCode\Execution\Exceptions.DivideByZero.Catch.cs" />
|
||||
<EmbeddedResource Include="TestCode\Variable.FromArgumentToCall.cs2cs" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче