// Tests that are inspired by the stack-related and verifier-related bugs in the wasm backend // WITH_STDLIB fun box(): String { if (!test1()) return "Fail 1" if (!test2()) return "Fail 2" if (!test3()) return "Fail 3" if (!test4()) return "Fail 4" if (!test5()) return "Fail 5" if (!test6()) return "Fail 6" if (!test7()) return "Fail 7" if (!test8()) return "Fail 8" return "OK" } open class Foo: Throwable("") {} class Bar: Foo() {} class Baz: Foo() {} class Darb: Throwable("") {} fun ooo() { throw Baz() } fun zoot(): String { return "str" } // Standard exception handling case without finally fun test1(): Boolean { try { ooo() } catch (b: Bar) { throw Darb() return false } catch (b: Baz) { return true } catch (b: Darb) { return false } return false } // Standart case with finally fun test2(): Boolean { var catched = false try { ooo() } catch (b: Bar) { throw Darb() return false } catch (b: Baz) { catched = true return false } catch (b: Darb) { return false } finally { return catched } return false } // Fallthrough with value on the stack (only needs to compile) fun test3(): Boolean { try { 1 } catch (e: Throwable) { 2 } return true } // Fallthrough with value on the stack and finally fun test4(): Boolean { var seenFinally = false try { ooo() 2 } catch (b: Throwable) { 1 } finally { seenFinally = true } return seenFinally } // Try with return value which is used later fun test5(): Boolean { val arg = try { ooo() 1 } catch (b: Baz) { 3 } catch (b: Darb) { 4 } return arg == 3 } // Case where catch uses labeled return which doesn't end the catch fun foo_for_test6(): String { var ret = "" try { ooo() } catch (e: Throwable) { listOf(1, 2, 3, 4, 5).forEach { if (it == 3) return@forEach } ret += "O" } finally { ret += "K" } return ret } fun test6(): Boolean { return foo_for_test6() == "OK" } // Catch is ended with the loop break into outer loop fun test7(): Boolean { var num_exc = 0 var num_breaks = 0 var num_finallies = 0 var num_bodies = 0 loop@ for (i in 1..3) { for (j in 1..5) { try { ooo() } catch (e: Throwable) { ++num_exc if (i == 2 || i == 4) { ++num_breaks break@loop } } finally { ++num_finallies } ++num_bodies } } if (num_exc == 6 && num_breaks == 1 && num_finallies == 6 && num_bodies == 5) return true return false } // Finally throws an exception class Baobab: Throwable() class Zanzibar: Throwable() class Hypo(val catchedBaobab: Boolean, val thrownZanzibar: Boolean, val seenFinally: Boolean): Throwable() fun golb() { throw Baobab() } fun foo(i: Int) { var catchedBaobab = false var thrownZanzibar = false var seenFinally = false try { golb() } catch (b: Baobab) { catchedBaobab = true if (i == 9) { thrownZanzibar = true throw Zanzibar() } } finally { seenFinally = true throw Hypo(catchedBaobab, thrownZanzibar, seenFinally) } } fun test8(): Boolean { try { foo(9) } catch (z: Hypo) { if (z.catchedBaobab && z.seenFinally && z.thrownZanzibar) return true return false } catch (e: Throwable) { return false } return false }