Thread overview
Dlang structured exception handling on Windows
Mar 19, 2018
KytoDragon
Mar 19, 2018
Adam D. Ruppe
Mar 20, 2018
KytoDragon
Mar 20, 2018
KytoDragon
Mar 20, 2018
Adam D. Ruppe
March 19, 2018
I currently have a problem i don't know how to fix:

Programms compiled in D (either compiler) have the annoying property that they absorb all windows seh-exceptions, print the error code and terminate the process.

For example, the following programm will print "Program exited with code -1073741819" and exit:

module test.Test;

void main() {
    *cast(int*)cast(void*)0 = 1;
}

But what I expected was the following:

https://imgur.com/LH8gUtt (translated for your language)

The problem with this is, that this "feature" somehow even manages to catch windows fail-fast exceptions, which are supossed to bypass all exception handling (and debuggers!) and go directly to WER (Windows Error Reporting). This makes it impossible to debug these types of exceptions, as D nearly silently swallows them. My questions are now:

What exactly causes this behaviour? (e.q. which part of druntime/phobos/dmd/ldc2)
Is there a way to disable that?
Has anybody an other solution?
March 19, 2018
On Monday, 19 March 2018 at 18:39:30 UTC, KytoDragon wrote:
> What exactly causes this behaviour? (e.q. which part of druntime/phobos/dmd/ldc2)

Look in druntime src/rt/dmain2.d for "trapExceptions". It is set to true except "IsDebuggerPresent". That catches everything.

You can't reset it to false since it makes a copy of the global var before any user code is run! And the command line switch to disable it that I'm sure I saw the PR for apparently never got in, since I can't find that code in live. So we have to hack around it.

> Is there a way to disable that?
> Has anybody an other solution?

Behold:

---
import core.runtime;
import std.stdio;
extern(C) int _d_run_main(int argc, char** argv) {
	Runtime.initialize();
	scope(exit) Runtime.terminate();

	writeln("here");

	int* n = null;
	*n = 1;
	writeln("there");
	return 0;
}

// a dummy to trick the compiler into actually linking in the runtime
void main() {}
---


_d_run_main is an internal function that does a bunch of setup work. This defines our own to override the one in dmain2 and duplicates a bit of its work (though not all, there may be some things that are broken with this!)

With this overridden we can get some code running without the exception catch wrapper. Works on 32 bit windows at least.


Ideally, we'd just get the commandline/envvar switch to disable... and the PR stalled for ages then the author moved on https://github.com/dlang/druntime/pull/1538 we just should revive that and get it up ASAP. Much better solution than the filthy hack above.
March 19, 2018
On Monday, 19 March 2018 at 18:39:30 UTC, KytoDragon wrote:
> I currently have a problem i don't know how to fix:
>
> Programms compiled in D (either compiler) have the annoying property that they absorb all windows seh-exceptions, print the error code and terminate the process.
>
> For example, the following programm will print "Program exited with code -1073741819" and exit:
>
> module test.Test;
>
> void main() {
>     *cast(int*)cast(void*)0 = 1;
> }
>
> But what I expected was the following:
>
> https://imgur.com/LH8gUtt (translated for your language)
>
> The problem with this is, that this "feature" somehow even manages to catch windows fail-fast exceptions, which are supossed to bypass all exception handling (and debuggers!) and go directly to WER (Windows Error Reporting). This makes it impossible to debug these types of exceptions, as D nearly silently swallows them. My questions are now:
>
> What exactly causes this behaviour? (e.q. which part of druntime/phobos/dmd/ldc2)
> Is there a way to disable that?
> Has anybody an other solution?

I'm not familiar with the neither the implementation details nor why it swallows all SEH exceptions, but anyway here's a few starting points:
* most (all?) of the exception handling support code is in the druntime 'src/rt/' folder - look for files starting with 'deh', e.g. https://github.com/dlang/druntime/blob/master/src/rt/deh_win32.d for dmd -m32 (Digital Mars C runtime) and https://github.com/dlang/druntime/blob/master/src/rt/deh_win64_posix.d  for the rest of the dmd platform support
* additionally, LDC has a modified or completely reworked version of this:
https://github.com/ldc-developers/druntime/tree/ldc/src/rt
  * for example, for 1.7 LDC release there was significant work in this area, which among other things added C++ exception handling support: https://github.com/ldc-developers/ldc/pull/2405/files
  * If you see differences between the DMD and LDC behavior, the quickest way to get an answer is to post in their forums: https://forum.dlang.org/group/ldc, or on their issue tracker: https://github.com/ldc-developers/ldc/issues
March 20, 2018
On Monday, 19 March 2018 at 19:09:01 UTC, Adam D. Ruppe wrote:
> Look in druntime src/rt/dmain2.d for "trapExceptions". It is set to true except "IsDebuggerPresent". That catches everything.
>
> With this overridden we can get some code running without the exception catch wrapper. Works on 32 bit windows at least.
>
>
> Ideally, we'd just get the commandline/envvar switch to disable... and the PR stalled for ages then the author moved on https://github.com/dlang/druntime/pull/1538 we just should revive that and get it up ASAP. Much better solution than the filthy hack above.

I think you missunderstood my problem. I don't mean D-Exceptions, I mean Windows SEH-Exceptions. These are not caught by D's try ... catch and even your example shows the exact same behaviour. (on DMD at least, LDC complains about the redefined symbol "_d_run_main")

EDIT: Ignore everything. It was my IDE that was swallowing exceptions not the compiler.
March 20, 2018
> EDIT: Ignore everything. It was my IDE that was swallowing exceptions not the compiler.

EDIT 2: Its not my IDE, it is DUB.
dub/generators/build.d, line 532:

------------
auto prg_pid = spawnProcess(exe_path_string ~ run_args);
auto result = prg_pid.wait();
enforce(result == 0, "Program exited with code "~to!string(result));
------------

and std.procedd.PID.wait only gets the exit code, ignoring anything else.
March 20, 2018
On Tuesday, 20 March 2018 at 17:14:02 UTC, KytoDragon wrote:
> I think you missunderstood my problem. I don't mean D-Exceptions, I mean Windows SEH-Exceptions. These are not caught by D's try ... catch and even your example shows the exact same behaviour.

On 32 bit, D exceptions ARE seh exceptions and try/catch works on both.

But if you are on 64 bit, the implementation is different anyway...