digitalmars.D - Can anyone explain this?
- Shachar Shemesh (48/48) Jun 05 2018 I set up to find out what happens if the assert string throws. I have to...
- Nicholas Wilson (29/56) Jun 05 2018 applying a bit of lowering
- Shachar Shemesh (2/4) Jun 05 2018 That's the part I was referring to.
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (46/52) Jun 05 2018 Now that's plain false - If you replace the call to
- Nicholas Wilson (38/75) Jun 05 2018 That does seem odd but is consistent with the implicit "try"
- Nicholas Wilson (2/4) Jun 05 2018 https://issues.dlang.org/show_bug.cgi?id=18946
- Andrea Fontana (20/21) Jun 05 2018 From here:
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]
Jun 05 2018
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 exceptionapplying 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; } }
Jun 05 2018
On 05/06/18 11:26, Nicholas Wilson wrote:writeln("Exception"); // Why is this not caught? I've no ideaThat's the part I was referring to.
Jun 05 2018
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 exceptionNow 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
Jun 05 2018
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:Whoops I meant _is_.writeln("Assert"); // this is not caught because the thrown throwable is not an exceptionNow 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.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
Jun 05 2018
On Tuesday, 5 June 2018 at 09:58:43 UTC, Nicholas Wilson wrote:prints Exceptionhttps://issues.dlang.org/show_bug.cgi?id=18946
Jun 05 2018
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
Jun 05 2018