mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-07 15:08:40 +00:00
Compare commits
1 Commits
8112b122fb
...
expand-exc
Author | SHA1 | Date | |
---|---|---|---|
|
56fbf7e398 |
@@ -193,6 +193,24 @@ module TestPureCases =
|
|||||||
NativeImpls = MockEnv.make ()
|
NativeImpls = MockEnv.make ()
|
||||||
LocalVariablesOfMain = [ CliType.Numeric (CliNumericType.Int32 10) ] |> Some
|
LocalVariablesOfMain = [ CliType.Numeric (CliNumericType.Int32 10) ] |> Some
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
FileName = "ExceptionWithNestedHandlers.cs"
|
||||||
|
ExpectedReturnCode = 10112
|
||||||
|
NativeImpls = NativeImpls.PassThru ()
|
||||||
|
LocalVariablesOfMain =
|
||||||
|
[ 10112 ]
|
||||||
|
|> List.map (fun i -> CliType.Numeric (CliNumericType.Int32 i))
|
||||||
|
|> Some
|
||||||
|
}
|
||||||
|
{
|
||||||
|
FileName = "ExceptionWithTypeMatching.cs"
|
||||||
|
ExpectedReturnCode = 10112
|
||||||
|
NativeImpls = NativeImpls.PassThru ()
|
||||||
|
LocalVariablesOfMain =
|
||||||
|
[ 10112 ]
|
||||||
|
|> List.map (fun i -> CliType.Numeric (CliNumericType.Int32 i))
|
||||||
|
|> Some
|
||||||
|
}
|
||||||
{
|
{
|
||||||
FileName = "Floats.cs"
|
FileName = "Floats.cs"
|
||||||
ExpectedReturnCode = 0
|
ExpectedReturnCode = 0
|
||||||
|
@@ -26,6 +26,8 @@
|
|||||||
<EmbeddedResource Include="sourcesPure\Ldelema.cs" />
|
<EmbeddedResource Include="sourcesPure\Ldelema.cs" />
|
||||||
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpCatch.cs" />
|
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpCatch.cs" />
|
||||||
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpFinally.cs" />
|
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpFinally.cs" />
|
||||||
|
<EmbeddedResource Include="sourcesPure\ExceptionWithNestedHandlers.cs" />
|
||||||
|
<EmbeddedResource Include="sourcesPure\ExceptionWithTypeMatching.cs" />
|
||||||
<EmbeddedResource Include="sourcesPure\TryCatchWithThrowInBody.cs" />
|
<EmbeddedResource Include="sourcesPure\TryCatchWithThrowInBody.cs" />
|
||||||
<EmbeddedResource Include="sourcesPure\ComplexTryCatch.cs" />
|
<EmbeddedResource Include="sourcesPure\ComplexTryCatch.cs" />
|
||||||
<EmbeddedResource Include="sourcesPure\TriangleNumber.cs" />
|
<EmbeddedResource Include="sourcesPure\TriangleNumber.cs" />
|
||||||
|
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace HelloWorld
|
||||||
|
{
|
||||||
|
class Program {
|
||||||
|
static int Test_NestedHandlers()
|
||||||
|
{
|
||||||
|
int x = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
x = 1;
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
x = 2;
|
||||||
|
throw new ArgumentException(); // Re-throw different exception
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
x += 10; // Inner finally
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ArgumentException)
|
||||||
|
{
|
||||||
|
x += 100; // Outer catch
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
x += 1000; // This should NOT execute
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
x += 10000; // Outer finally
|
||||||
|
}
|
||||||
|
|
||||||
|
return x; // Expected: 10112 (1 -> 2 -> 12 -> 112 -> 10112)
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Main(string[] args)
|
||||||
|
{
|
||||||
|
return Test_NestedHandlers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace HelloWorld
|
||||||
|
{
|
||||||
|
class Program {
|
||||||
|
static int Test_TypeMatching()
|
||||||
|
{
|
||||||
|
int x = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
x = 1;
|
||||||
|
throw new ArgumentNullException(); // Derives from ArgumentException
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
x = 999; // Should NOT execute
|
||||||
|
}
|
||||||
|
catch (ArgumentException) // This should catch ArgumentNullException
|
||||||
|
{
|
||||||
|
x = 2;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
x = 888; // Should NOT execute (more general handler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
x = 777; // Should NOT execute (outer handler)
|
||||||
|
}
|
||||||
|
return x; // Expected: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Main(string[] args)
|
||||||
|
{
|
||||||
|
return Test_TypeMatching();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,32 +1,29 @@
|
|||||||
namespace WoofWare.PawPrint
|
namespace WoofWare.PawPrint
|
||||||
|
|
||||||
open System
|
|
||||||
open System.Collections.Immutable
|
open System.Collections.Immutable
|
||||||
|
|
||||||
/// Represents a location in the code where an exception occurred
|
/// Represents a location in the code where an exception occurred
|
||||||
type ExceptionStackFrame<'typeGen, 'methodGen, 'methodVar
|
type ExceptionStackFrame =
|
||||||
when 'typeGen : comparison and 'typeGen :> IComparable<'typeGen>> =
|
|
||||||
{
|
{
|
||||||
Method : WoofWare.PawPrint.MethodInfo<'typeGen, 'methodGen, 'methodVar>
|
Method : WoofWare.PawPrint.MethodInfo<TypeDefn, TypeDefn>
|
||||||
/// The number of bytes into the IL of the method we were in
|
/// The number of bytes into the IL of the method we were in
|
||||||
IlOffset : int
|
IlOffset : int
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a CLI exception being propagated
|
/// Represents a CLI exception being propagated
|
||||||
type CliException<'typeGen, 'methodGen, 'methodVar when 'typeGen : comparison and 'typeGen :> IComparable<'typeGen>> =
|
type CliException =
|
||||||
{
|
{
|
||||||
/// The exception object allocated on the heap
|
/// The exception object allocated on the heap
|
||||||
ExceptionObject : ManagedHeapAddress
|
ExceptionObject : ManagedHeapAddress
|
||||||
/// Stack trace built during unwinding
|
/// Stack trace built during unwinding
|
||||||
StackTrace : ExceptionStackFrame<'typeGen, 'methodGen, 'methodVar> list
|
StackTrace : ExceptionStackFrame list
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents what to do after executing a finally/filter block
|
/// Represents what to do after executing a finally/filter block
|
||||||
type ExceptionContinuation<'typeGen, 'methodGen, 'methodVar
|
type ExceptionContinuation =
|
||||||
when 'typeGen : comparison and 'typeGen :> IComparable<'typeGen>> =
|
|
||||||
| ResumeAfterFinally of targetPC : int
|
| ResumeAfterFinally of targetPC : int
|
||||||
| PropagatingException of exn : CliException<'typeGen, 'methodGen, 'methodVar>
|
| PropagatingException of exn : CliException
|
||||||
| ResumeAfterFilter of handlerPC : int * exn : CliException<'typeGen, 'methodGen, 'methodVar>
|
| ResumeAfterFilter of handlerPC : int * exn : CliException
|
||||||
|
|
||||||
/// Helper functions for exception handling
|
/// Helper functions for exception handling
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
@@ -47,7 +44,7 @@ module ExceptionHandling =
|
|||||||
let findExceptionHandler
|
let findExceptionHandler
|
||||||
(currentPC : int)
|
(currentPC : int)
|
||||||
(exceptionTypeCrate : TypeInfoCrate)
|
(exceptionTypeCrate : TypeInfoCrate)
|
||||||
(method : WoofWare.PawPrint.MethodInfo<'typeGen, 'methodGeneric, 'methodVar>)
|
(method : WoofWare.PawPrint.MethodInfo<TypeDefn, 'methodGeneric>)
|
||||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||||
: (WoofWare.PawPrint.ExceptionRegion * bool) option // handler, isFinally
|
: (WoofWare.PawPrint.ExceptionRegion * bool) option // handler, isFinally
|
||||||
=
|
=
|
||||||
@@ -56,46 +53,68 @@ module ExceptionHandling =
|
|||||||
| Some instructions ->
|
| Some instructions ->
|
||||||
|
|
||||||
// Find all handlers that cover the current PC
|
// Find all handlers that cover the current PC
|
||||||
instructions.ExceptionRegions
|
let handlers =
|
||||||
|> Seq.choose (fun region ->
|
instructions.ExceptionRegions
|
||||||
match region with
|
|> Seq.choose (fun region ->
|
||||||
| ExceptionRegion.Catch (typeToken, offset) ->
|
match region with
|
||||||
if currentPC >= offset.TryOffset && currentPC < offset.TryOffset + offset.TryLength then
|
| ExceptionRegion.Catch (typeToken, offset) ->
|
||||||
// Check if exception type matches
|
if currentPC >= offset.TryOffset && currentPC < offset.TryOffset + offset.TryLength then
|
||||||
if isExceptionAssignableTo exceptionTypeCrate typeToken assemblies then
|
// Check if exception type matches
|
||||||
Some (region, false)
|
if isExceptionAssignableTo exceptionTypeCrate typeToken assemblies then
|
||||||
|
Some (region, false, offset.TryOffset, offset.TryLength)
|
||||||
|
else
|
||||||
|
None
|
||||||
else
|
else
|
||||||
None
|
None
|
||||||
else
|
| ExceptionRegion.Filter (filterOffset, offset) ->
|
||||||
|
if currentPC >= offset.TryOffset && currentPC < offset.TryOffset + offset.TryLength then
|
||||||
|
failwith "TODO: filter needs to be evaluated"
|
||||||
|
else
|
||||||
|
None
|
||||||
|
| ExceptionRegion.Finally offset ->
|
||||||
|
// Don't return finally blocks here - they're handled separately
|
||||||
None
|
None
|
||||||
| ExceptionRegion.Filter (filterOffset, offset) ->
|
| ExceptionRegion.Fault offset ->
|
||||||
if currentPC >= offset.TryOffset && currentPC < offset.TryOffset + offset.TryLength then
|
// Fault blocks are only executed when propagating exceptions
|
||||||
failwith "TODO: filter needs to be evaluated"
|
|
||||||
else
|
|
||||||
None
|
None
|
||||||
| ExceptionRegion.Finally offset ->
|
)
|
||||||
if currentPC >= offset.TryOffset && currentPC < offset.TryOffset + offset.TryLength then
|
|> Seq.toList
|
||||||
Some (region, true)
|
|
||||||
else
|
// If multiple catch handlers, return the innermost one (highest TryOffset)
|
||||||
None
|
match handlers with
|
||||||
| ExceptionRegion.Fault offset ->
|
| [] ->
|
||||||
if currentPC >= offset.TryOffset && currentPC < offset.TryOffset + offset.TryLength then
|
// No catch/filter handler found, check for finally/fault blocks
|
||||||
Some (region, true)
|
// that need to run while propagating
|
||||||
else
|
instructions.ExceptionRegions
|
||||||
None
|
|> Seq.choose (fun region ->
|
||||||
)
|
match region with
|
||||||
|> Seq.toList
|
| ExceptionRegion.Finally offset ->
|
||||||
|> fun x ->
|
if currentPC >= offset.TryOffset && currentPC < offset.TryOffset + offset.TryLength then
|
||||||
match x with
|
Some (region, true, offset.TryOffset, offset.TryLength)
|
||||||
| [] -> None
|
else
|
||||||
| [ x ] -> Some x
|
None
|
||||||
| _ -> failwith "multiple exception regions"
|
| ExceptionRegion.Fault offset ->
|
||||||
|
if currentPC >= offset.TryOffset && currentPC < offset.TryOffset + offset.TryLength then
|
||||||
|
Some (region, true, offset.TryOffset, offset.TryLength)
|
||||||
|
else
|
||||||
|
None
|
||||||
|
| _ -> None
|
||||||
|
)
|
||||||
|
|> Seq.sortByDescending (fun (_, _, tryOffset, _) -> tryOffset)
|
||||||
|
|> Seq.tryHead
|
||||||
|
|> Option.map (fun (region, isFinally, _, _) -> (region, isFinally))
|
||||||
|
| handlers ->
|
||||||
|
// Return the innermost handler (highest TryOffset, or smallest TryLength for same offset)
|
||||||
|
handlers
|
||||||
|
|> List.sortBy (fun (_, _, tryOffset, tryLength) -> (-tryOffset, tryLength))
|
||||||
|
|> List.head
|
||||||
|
|> fun (region, isFinally, _, _) -> Some (region, isFinally)
|
||||||
|
|
||||||
/// Find finally blocks that need to run when leaving a try region
|
/// Find finally blocks that need to run when leaving a try region
|
||||||
let findFinallyBlocksToRun
|
let findFinallyBlocksToRun
|
||||||
(currentPC : int)
|
(currentPC : int)
|
||||||
(targetPC : int)
|
(targetPC : int)
|
||||||
(method : WoofWare.PawPrint.MethodInfo<'typeGeneric, 'methodGeneric, 'methodVar>)
|
(method : WoofWare.PawPrint.MethodInfo<TypeDefn, 'methodGeneric>)
|
||||||
: ExceptionOffset list
|
: ExceptionOffset list
|
||||||
=
|
=
|
||||||
match method.Instructions with
|
match method.Instructions with
|
||||||
@@ -125,7 +144,7 @@ module ExceptionHandling =
|
|||||||
/// Get the active exception regions at a given offset
|
/// Get the active exception regions at a given offset
|
||||||
let getActiveRegionsAtOffset
|
let getActiveRegionsAtOffset
|
||||||
(offset : int)
|
(offset : int)
|
||||||
(method : WoofWare.PawPrint.MethodInfo<'a, 'b, 'c>)
|
(method : WoofWare.PawPrint.MethodInfo<TypeDefn, 'methodGeneric>)
|
||||||
: WoofWare.PawPrint.ExceptionRegion list
|
: WoofWare.PawPrint.ExceptionRegion list
|
||||||
=
|
=
|
||||||
match method.Instructions with
|
match method.Instructions with
|
||||||
|
Reference in New Issue
Block a user