Thread overview | |||||||||
---|---|---|---|---|---|---|---|---|---|
|
June 05, 2018 Can anyone explain this? | ||||
---|---|---|---|---|
| ||||
I set up to find out what happens if the assert string throws. I have to admit I did not expect the result: $ cat test.d import std.stdio; import core.exception; void main() { scope(failure) { writeln("Not gonna happen"); } try { static string throwingFunc() { throw new Exception("An exception"); } assert(0==1, throwingFunc()); } catch(Exception ex) { writeln("Exception"); } catch(AssertError ex) { writeln("Assert"); } } $ ldc2 --version LDC - the LLVM D compiler (1.8.0): based on DMD v2.078.3 and LLVM 5.0.1 ... $ ./test Not gonna happen object.Exception@test.d(11): An exception ---------------- ??:? [0x3728941e] ??:? [0x372903aa] ??:? [0x3727b15c] ??:? [0x3724991d] ??:? [0x372496c9] ??:? [0x3727aecf] ??:? [0x3727addb] ??:? [0x3724a124] ??:? __libc_start_main [0xed8b01c0] ??:? [0x372495c9] $ dmd --version DMD64 D Compiler v2.080.0 Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved written by Walter Bright $ ./test Not gonna happen object.Exception@test.d(11): An exception ---------------- ??:? pure @safe immutable(char)[] test.main().throwingFunc() [0xe9b1c2b3] ??:? _Dmain [0xe9b1c1ad] |
June 05, 2018 Re: Can anyone explain this? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Shachar Shemesh | On Tuesday, 5 June 2018 at 08:12:54 UTC, Shachar Shemesh wrote: > I set up to find out what happens if the assert string throws. I have to admit I did not expect the result: > > $ cat test.d > import std.stdio; > import core.exception; > > void main() { > scope(failure) { > writeln("Not gonna happen"); > } > > try { > static string throwingFunc() { > throw new Exception("An exception"); > } > assert(0==1, throwingFunc()); > } catch(Exception ex) { > writeln("Exception"); > } catch(AssertError ex) { > writeln("Assert"); > } > } > > $ ldc2 --version > LDC - the LLVM D compiler (1.8.0): > based on DMD v2.078.3 and LLVM 5.0.1 > ... > > $ ./test > Not gonna happen > object.Exception@test.d(11): An exception applying a bit of lowering int Dmain (int arc, const char** argv) { try return main(); catch (...) dumpThrowable(); // 3 dumps exception } void main() { try { try { static string throwingFunc() { throw new Exception("An exception"); } __assert_fail(throwingFunc(),...); // 1 throws before assert throws } catch(Exception ex) { writeln("Exception"); // Why is this not caught? I've no idea } catch(AssertError ex) { writeln("Assert"); // this is not caught because the thrown throwable is not an exception } } catch(...) { writeln("Not gonna happen"); // 2 scope failure is run throw; } } |
June 05, 2018 Re: Can anyone explain this? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Shachar Shemesh | On Tuesday, 5 June 2018 at 08:12:54 UTC, Shachar Shemesh wrote: > I set up to find out what happens if the assert string throws. From here: https://dlang.org/spec/expression.html#assert_expressions [...] 8. Undefined Behavior: Once in an Invalid State the behavior of the continuing execution of the program is undefined. [...] [...] Best Practices: - Do not have side effects in either AssignExpression that subsequent code depends on. - AssertExpressions are intended to detect bugs in the program, do not use for detecting input or environmental errors. - Do not attempt to resume normal execution after an Assert Failure. [...] Anyway you can try to catch "Throwable" to understand what is going to happen (but it's not a good idea at all to keep it in a program) Andrea |
June 05, 2018 Re: Can anyone explain this? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nicholas Wilson | On 05/06/18 11:26, Nicholas Wilson wrote:
> writeln("Exception"); // Why is this not caught? I've no idea
That's the part I was referring to.
|
June 05, 2018 Re: Can anyone explain this? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nicholas Wilson | On Tuesday, 5 June 2018 at 08:26:22 UTC, Nicholas Wilson wrote: > writeln("Assert"); // this is not caught because the thrown throwable is not an exception Now that's plain false - If you replace the call to throwingFunc() with a string literal, you'll see it's properly caught. Also, the catch clause explicitly specifies AssertError, which as the name implies, is an Error, not an Exception. This might just be a case of undefined behavior. According to https://dlang.org/spec/contracts.html: "As a contract, an assert represents a guarantee that the code must uphold. Any failure of this expression represents a logic error in the code that must be fixed in the source code. A program for which the assert contract is false is, by definition, invalid, and therefore has undefined behaviour." In short, what you're doing is UB, and the nasal demons are printing 'not gonna happen' to your console. That also makes some sense with Andrea Fontana's comments: > - Do not have side effects in either AssignExpression that subsequent code depends on. > - Do not attempt to resume normal execution after an Assert Failure. However, if we add catch (Throwable ex) to the list of catch statements, that *does* catch a regular object.Exception. Moving the catch (Exception) statement down the list does nothing. Adding another layer of try-catch also catches it (even with just catch (Exception ex)): import std.stdio; import core.exception; unittest { scope(failure) { writeln("Not gonna happen"); } try { try { static string throwingFunc() { throw new Exception("An exception"); } assert(0==1, throwingFunc()); } catch(AssertError ex) { writeln("Assert"); } catch(Exception ex) { writeln("Exception A"); } } catch(Exception ex) { writeln("Exception B"); } } So I'm stumped. It seems the exception handling is simply not setup correctly. This could be because of UB I guess, but I'd hope the AssertError would be thrown first in such a case. -- Simen |
June 05, 2018 Re: Can anyone explain this? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | On Tuesday, 5 June 2018 at 09:03:03 UTC, Simen Kjærås wrote: > On Tuesday, 5 June 2018 at 08:26:22 UTC, Nicholas Wilson wrote: >> writeln("Assert"); // this is not caught because the thrown throwable is not an exception > > Now that's plain false - If you replace the call to throwingFunc() with a string literal, you'll see it's properly caught. Also, the catch clause explicitly specifies AssertError, which as the name implies, is an Error, not an Exception. > Whoops I meant _is_. > However, if we add catch (Throwable ex) to the list of catch statements, that *does* catch a regular object.Exception. Moving the catch (Exception) statement down the list does nothing. Adding another layer of try-catch also catches it (even with just catch (Exception ex)): That does seem odd but is consistent with the implicit "try" surrounding Dmain inserted by the runtime. > import std.stdio; > import core.exception; > > unittest { > scope(failure) { > writeln("Not gonna happen"); > } > > try { > try { > static string throwingFunc() { > throw new Exception("An exception"); > } > assert(0==1, throwingFunc()); > } catch(AssertError ex) { > writeln("Assert"); > } catch(Exception ex) { > writeln("Exception A"); > } > } catch(Exception ex) { > writeln("Exception B"); > } > } > > So I'm stumped. It seems the exception handling is simply not setup correctly. This could be because of UB I guess, but I'd hope the AssertError would be thrown first in such a case. The assert error will never be thrown because one of the parameters to the __assert_fail throws. Its like as if you had written. if (0==1) { string tmp = throwingFunc(); // throws __assert_fail(tmp,__LINE__,...); // dead code. } Actually it may be the compiler doing something funky with assert(0, msg); being special (assert(0,...) since the spec says for assert any compile time expression == 0 has the effect of assert(0). i.e. assert(0==1); is the same as assert(0);). Proof import std.stdio; import core.exception; bool foo() { return false;} // mess with the compiler's reasoning about the truthiness of the assert void main() { scope(failure) { writeln("Not gonna happen"); } try { static string throwingFunc() { throw new Exception("An exception"); } assert(foo(), throwingFunc()); } catch(Exception ex) { writeln("Exception"); } catch(AssertError ex) { writeln("Assert"); } } prints Exception |
June 05, 2018 Re: Can anyone explain this? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nicholas Wilson | On Tuesday, 5 June 2018 at 09:58:43 UTC, Nicholas Wilson wrote: > prints > > Exception https://issues.dlang.org/show_bug.cgi?id=18946 |
Copyright © 1999-2021 by the D Language Foundation