catch
declare preconditions that an exception must satisfy in order to be caught by a given block. This mechanism does not work in exactly the same way as performing checks inside a catch
.catch
CLR crawls its internal stack of exception handlers and also performs exception filters. Note that this happens before the code is executed in the finally
block. We will discuss this point later. Sub FilterException() Try Dim exception As New Exception exception.Data.Add("foo", "bar1") Console.WriteLine("Throwing") Throw exception Catch ex As Exception When Filter(ex) ' Console.WriteLine("Caught") Finally Console.WriteLine("Finally") End Try End Sub Function Filter(exception As Exception) As Boolean Console.WriteLine("Filtering") Return exception.Data.Item("foo").Equals("bar") End Function
Throwing Filtering Caught Finally
open System let filter (ex : Exception) = printfn "Filtering" ex.Data.["foo"] :?> string = "bar" let filterException() = try let ex = Exception() ex.Data.["foo"] <- "bar" printfn "Throwing" raise ex with // | :? Exception as ex when filter(ex) -> printfn "Caught" [<EntryPoint>] let main argv = filterException() 0
catch [mscorlib]System.Object
. I never managed to force the F # compiler to make an exception filter. If you know of alternative ways to do this - welcome to the comments.ilasm
tool, and collected back using the ilasm
that comes with .NET.ildasm
: .method public static void FilterException() cil managed { // Code size 110 (0x6e) .maxstack 3 .locals init ([0] class [mscorlib]System.Exception exception, [1] class [mscorlib]System.Exception ex) IL_0000: nop IL_0001: nop .try { .try { IL_0002: newobj instance void [mscorlib]System.Exception::.ctor() IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: callvirt instance class [mscorlib]System.Collections.IDictionary [mscorlib]System.Exception::get_Data() IL_000e: ldstr "foo" IL_0013: ldstr "bar" IL_0018: callvirt instance void [mscorlib]System.Collections.IDictionary::Add(object, object) IL_001d: nop IL_001e: ldstr "Throwing" IL_0023: call void [mscorlib]System.Console::WriteLine(string) IL_0028: nop IL_0029: ldloc.0 IL_002a: throw IL_002b: leave.s IL_006b } // end .try filter { IL_002d: isinst [mscorlib]System.Exception IL_0032: dup IL_0033: brtrue.s IL_0039 IL_0035: pop IL_0036: ldc.i4.0 IL_0037: br.s IL_0049 IL_0039: dup IL_003a: stloc.1 IL_003b: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError(class [mscorlib]System.Exception) IL_0040: ldloc.1 IL_0041: call bool FilterSamples.VbNetFilter::Filter(class [mscorlib]System.Exception) IL_0046: ldc.i4.0 IL_0047: cgt.un IL_0049: endfilter } // end filter { // handler IL_004b: pop IL_004c: ldstr "Caught" IL_0051: call void [mscorlib]System.Console::WriteLine(string) IL_0056: nop IL_0057: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::ClearProjectError() IL_005c: leave.s IL_006b } // end handler } // end .try finally { IL_005e: nop IL_005f: ldstr "Finally" IL_0064: call void [mscorlib]System.Console::WriteLine(string) IL_0069: nop IL_006a: endfinally } // end handler IL_006b: nop IL_006c: nop IL_006d: ret } // end of method VbNetFilter::FilterException
filter
block: filter { // , System.Exception: IL_002d: isinst [mscorlib]System.Exception IL_0032: dup IL_0033: brtrue.s IL_0039 IL_0035: pop IL_0036: ldc.i4.0 // - : IL_0037: br.s IL_0049 IL_0039: dup // - : IL_003a: stloc.1 IL_003b: call void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.ProjectData::SetProjectError(class [mscorlib]System.Exception) // , : IL_0040: ldloc.1 IL_0041: call bool FilterSamples.VbNetFilter::Filter(class [mscorlib]System.Exception) IL_0046: ldc.i4.0 IL_0047: cgt.un IL_0049: endfilter } // end filter
1
on the stack, then the catch
block corresponding to this filter will be executed; otherwise not.filter
block, but uses a special CIL construct with a type indication. That is, the C # compiler does not use the filter
mechanism at all. public static void FilterException() { // ISSUE: unable to decompile the method. }
public static void FilterException() { try { Exception exception = new Exception(); exception.Data.Add("foo", "bar"); Console.WriteLine("Throwing"); throw exception; } catch when (?) { Console.WriteLine("Caught"); ProjectData.ClearProjectError(); } finally { Console.WriteLine("Finally"); } }
Public Shared Sub FilterException() Try Dim exception As New Exception exception.Data.Add("foo", "bar") Console.WriteLine("Throwing") Throw exception Catch obj1 As Object When (?) Console.WriteLine("Caught") ProjectData.ClearProjectError Finally Console.WriteLine("Finally") End Try End Sub
ildasm
did a fine job with this).catch
static void FilterException() { try { var exception = new Exception(); exception.Data["foo"] = "bar"; Console.WriteLine("Throwing"); throw exception; } catch (Exception exception) { if (!Filter(exception)) { throw; } Console.WriteLine("Caught"); } } static bool Filter(Exception exception) { return exception.Data["foo"].Equals("bar"); }
throw;
expression throw;
in C # it loses the row number in the stack. If you change the filter so that it returns false
, the application will drop with the message Unhandled Exception: System.Exception: Exception of type 'System.Exception' was thrown. at CSharpFilter.Program.FilterException() in CSharpFilter\Program.cs:line 25 at CSharpFilter.Program.Main(String[] args) in CSharpFilter\Program.cs:line 9
throw;
), and not on the line 19 ( throw exception;
). The code on VB.NET in the same conditions shows the original location of the exception.throw;
loses the whole stack, but in the comments suggested that this is really not at all the case. There is only a minor modification of the line number in the stack. Moreover, on mono this is not reproduced - the exception stack does not change there after throw;
(thanks to kekekeks for these details).finally
, because before the finally
block is executed, exception filters may be called that are located higher in the call stack (and the attacker can get whatever he wants in the code of these filters). Remember - finding the right catch
always done before the finally
block is executed.Source: https://habr.com/ru/post/192144/
All Articles