www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - nothrow in druntime win32 C bindings

reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
All contents in the core.sys.windows.windows module in 2.061 are
marked as nothrow.

nothrow means exceptions derived from the Exception class are not
allowed to propagate. In other words now that the WNDPROC function
pointer is expected to be nothrow you have to wrap any statements
which might throw Exception objects in a try/catch block.

SEH[1] is implemented in D for x86 (x64 not yet, but maybe some day),
therefore exceptions can propagate, and they do as this sample will
show you if you compile it with 2.060:
https://github.com/AndrejMitrovic/dmd/blob/662db08ce9dd27d2c79d04ab4ccea9823f6142a1/test/win32/testthrow.d#L23

Are there problems with the SEH implementation which forces us to use
nothrow on win32? If there are then this should be documented.
Dec 26 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/26/2012 2:12 PM, Andrej Mitrovic wrote:
 All contents in the core.sys.windows.windows module in 2.061 are
 marked as nothrow.

 nothrow means exceptions derived from the Exception class are not
 allowed to propagate. In other words now that the WNDPROC function
 pointer is expected to be nothrow you have to wrap any statements
 which might throw Exception objects in a try/catch block.

 SEH[1] is implemented in D for x86 (x64 not yet, but maybe some day),
 therefore exceptions can propagate, and they do as this sample will
 show you if you compile it with 2.060:
 https://github.com/AndrejMitrovic/dmd/blob/662db08ce9dd27d2c79d04ab4ccea9823f6142a1/test/win32/testthrow.d#L23

 Are there problems with the SEH implementation which forces us to use
 nothrow on win32? If there are then this should be documented.

The operating system calls WNDPROC directly. That means that you (the user) need to set up / tear down the D runtime yourself, much like what C main() does in druntime. Windows has no knowledge of D Exceptions, and it makes no sense to me to try to pass them on to Windows. WNDPROC should deal with them.
Dec 26 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/26/2012 2:47 PM, Andrej Mitrovic wrote:
 On 12/26/12, Walter Bright <newshound2 digitalmars.com> wrote:
 The operating system calls WNDPROC directly. That means that you (the user)
 need to set up / tear down the D runtime yourself

But we already do this in WinMain, which is called first:

You're right. But the whole reason to declare functions as being of type WNDPROC is they are called by Windows. Windows knows nothing about D exceptions, and I think that it's courting disaster for a function to hand them off to Windows. This applies to any attempt to throw D exceptions in code called by non-D code.
Dec 26 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/26/2012 6:26 PM, Andrej Mitrovic wrote:
 On 12/27/12, Walter Bright <newshound2 digitalmars.com> wrote:
 Windows knows nothing about D exceptions

Then why does my code sample work?

A lot of code can appear to work, but that doesn't mean it is correct and robust and will work on future versions of Windows. Code should not impute things into an ABI spec. The Windows ABI spec says nothing at all about accepting D exceptions, therefore none should be presented to it.
 If Windows really knows nothing about D exceptions why are we letting
 Error and Throwable through, shouldn't we also catch those and then
 call core.stdc.exit() or ExitProcess()?

Take a look at druntime\src\rt\dmain2.d. It catches all Throwable's and swallows them - it does not expect the C runtime to handle D exceptions. This is why Throwable is still catchable.
Dec 26 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/27/2012 7:32 AM, Andrej Mitrovic wrote:
 So then `nothrow` on the headers isn't enough since it only guarantees
 we're catching Exception types and letting Nothrow types through to
 Windows functions. It sounds to me like we need even stricter
 enforcement on the headers which the language doesn't provide right
 now (in hindsight maybe 'nothrow' should have been called 'noexcept').

 For example people have problems throwing on x64 in C++ inside a
 WNDPROC: http://stackoverflow.com/questions/2631452/64bit-exceptions-in-wndproc-silently-fail

 I wonder if D has the same problem if an Error or Throwable escapes a WNDPROC?

Probably. Is it an issue as you describe? Yes. Is it a big enough issue to merit a language change? I doubt it.
Dec 27 2012
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/27/2012 10:16 AM, Andrej Mitrovic wrote:
 Ok, but we should at least document it. Currently we only have a small
 remark in the docs saying exceptions in D are not compatible with C++
 exceptions, but we should clarify and maybe add how to work around
 this, whether to catch Throwable, and what to do when its caught.

Yes.
Dec 27 2012
prev sibling next sibling parent Stewart Gordon <smjg_1998 yahoo.com> writes:
On 27/12/2012 18:16, Andrej Mitrovic wrote:
 On 12/27/12, Walter Bright <newshound2 digitalmars.com> wrote:
 Is it an issue as you describe? Yes. Is it a big enough issue to merit a
 language change? I doubt it.

Ok, but we should at least document it. Currently we only have a small remark in the docs saying exceptions in D are not compatible with C++ exceptions, but we should clarify and maybe add how to work around this, whether to catch Throwable, and what to do when its caught.

The WNDPROC defined by SDWF catches exceptions and displays a message box that gives the exception's toString and offers the user the choice of trying to continue or aborting the program. Stewart.
Dec 28 2012
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/28/2012 5:29 AM, Phil Lavoie wrote:
 So, if I got this right, doing this is not ideal:
 extern( Windows ) nothrow LRESULT WndProc( HWND hwnd, UINT message, WPARAM
 wParam, LPARAM lParam ) {
 try {
 ...
 } catch( Exception e ) { ... }
 }

 And should be changed to :
 catch( Throwable t ) { ... }
 ?

Yes.
Dec 28 2012
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/27/2012 12:52 AM, deadalnix wrote:
 On Thursday, 27 December 2012 at 01:39:11 UTC, Walter Bright wrote:
 This applies to any attempt to throw D exceptions in code called by non-D code.

BTW, Why D isn't using the system defined exception ABI if one exists (like on windows) ? Is-it intentional, or lack of documentation/manpower ?

D does use Windows SEH for win32, but not for win64. But still, you gotta ask yourself, what do expect Windows to do with a D exception?
Dec 27 2012
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/27/2012 1:52 AM, deadalnix wrote:
 On Thursday, 27 December 2012 at 09:29:08 UTC, Walter Bright wrote:
 D does use Windows SEH for win32, but not for win64. But still, you gotta ask
 yourself, what do expect Windows to do with a D exception?

I think it has several advantages to use the same ABI : - Exception cal bubble from D to C++ then back to D to be handled. C++ will run RAII code properly, even if it can't do anything useful with the D exception. This is common when using function pointer or virtual methods. - The same thing goes the other way around : C++ Exception can go throw D code, unwinding stack cleanly. Even if D program cannot do anything really ith the C++ exception, it can at least fail safely and with a stack trace. In many cases, exception are more about exit cleanly than actually catch them and recover. For such a case, common ABI is useful.

There is some merit to your argument, and that was the original idea behind building D exceptions out of Win32 SEH. I did the same for the Digital Mars C++ compiler. But in practice, and I include a decade with DMC++, I've just never seen a useful application of it.
Dec 27 2012
prev sibling parent Brad Roberts <braddr slice-2.puremagic.com> writes:
On Thu, 27 Dec 2012, Walter Bright wrote:

 On 12/27/2012 1:52 AM, deadalnix wrote:
 On Thursday, 27 December 2012 at 09:29:08 UTC, Walter Bright wrote:
 D does use Windows SEH for win32, but not for win64. But still, you gotta
 ask
 yourself, what do expect Windows to do with a D exception?

I think it has several advantages to use the same ABI : - Exception cal bubble from D to C++ then back to D to be handled. C++ will run RAII code properly, even if it can't do anything useful with the D exception. This is common when using function pointer or virtual methods. - The same thing goes the other way around : C++ Exception can go throw D code, unwinding stack cleanly. Even if D program cannot do anything really ith the C++ exception, it can at least fail safely and with a stack trace. In many cases, exception are more about exit cleanly than actually catch them and recover. For such a case, common ABI is useful.

There is some merit to your argument, and that was the original idea behind building D exceptions out of Win32 SEH. I did the same for the Digital Mars C++ compiler. But in practice, and I include a decade with DMC++, I've just never seen a useful application of it.

It doesn't matter if you can see the utility in it or not. What matters is some combination of user expectations and general usability, both of which are fairly subjective. Additionally, for most of that decade, mixing languages was fairly rare. These days it's becoming increasingly common. Presenting c++ libraries with c wrappers is much more common now. Using call backs and registration hooks for plugins and other extensibility mechanisms is WAY more common now than it was 10 years ago. In short, the landscape has and continues to change, so past history is a poor measuring stick for future code bases. IMHO, having the unwinders NOT be common and uniform in behavior is a major usage problem. It might not be important enough to hit the top of the todo list right now, but at some point it's going to be. Either way, not being interoperable is a bug in my mind (and I include all the platform here, not just windows) and will need to be addressed. It's roughly in the same category as supporting shared libraries. They're not important at small scale, but at large scale they start to become critical. If I can't rely on proper unwinding, there's going to be problems. I'm not familiar with the windows side, but on the posix side, the c++ world developed a fairly sane, multi-language, unwinding system. There's little reason NOT to use it, other than that it takes a little time to understand and hook into it, and going off on your own path is potentially simpler. My 2 cents, Brad
Dec 27 2012
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/27/2012 12:50 AM, Vladimir Panteleev wrote:
 On Thursday, 27 December 2012 at 02:26:11 UTC, Andrej Mitrovic wrote:
 On 12/27/12, Walter Bright <newshound2 digitalmars.com> wrote:
 Windows knows nothing about D exceptions

Then why does my code sample work?

Have a look at the "Remarks" section of the WNDPROC documentation: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633573(v=vs.85).aspx It looks like the behavior will vary greatly on 64-bit Windows OSes (for both 32-bit and 64-bit apps).

That pretty much confirms to me that you shouldn't generate SEH exceptions and send them to Windows unless you have studied the issue carefully. Just throwing D exceptions and assuming Windows will do the right thing, whatever that is, with them is a mistake.
Dec 27 2012
prev sibling parent Stewart Gordon <smjg_1998 yahoo.com> writes:
On 26/12/2012 22:47, Andrej Mitrovic wrote:
 On 12/26/12, Walter Bright <newshound2 digitalmars.com> wrote:
 The operating system calls WNDPROC directly. That means that you (the user)
 need to set up / tear down the D runtime yourself

But we already do this in WinMain, which is called first:

But on top of what Walter has said: - Is it even guaranteed that the WNDPROC will be called only in the program's own call stack? - Just looking at how SendMessage works across threads, can we rely on it to properly notify the calling thread that the message has been processed if the WNDPROC throws? - Chances are you'll want to avoid just letting exceptions abort the entire program. Stewart.
Dec 27 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 12/26/12, Walter Bright <newshound2 digitalmars.com> wrote:
 The operating system calls WNDPROC directly. That means that you (the user)
 need to set up / tear down the D runtime yourself

But we already do this in WinMain, which is called first: extern (Windows) int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) { int result; void exceptionHandler(Throwable e) { throw e; } try { Runtime.initialize(&exceptionHandler); result = myWinMain(hInstance, hPrevInstance, lpCmdLine, iCmdShow); Runtime.terminate(&exceptionHandler); } catch (Throwable o) { MessageBox(null, o.toString().toUTF16z, "Error", MB_OK | MB_ICONEXCLAMATION); result = 0; } return result; } This is the top-level exception handler where exceptions from within a WNDPROC propagate to if they're not caught.
Dec 26 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 12/27/12, Walter Bright <newshound2 digitalmars.com> wrote:
 Windows knows nothing about D exceptions

Then why does my code sample work? If Windows really knows nothing about D exceptions why are we letting Error and Throwable through, shouldn't we also catch those and then call core.stdc.exit() or ExitProcess()?
Dec 26 2012
prev sibling next sibling parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Thursday, 27 December 2012 at 02:26:11 UTC, Andrej Mitrovic 
wrote:
 On 12/27/12, Walter Bright <newshound2 digitalmars.com> wrote:
 Windows knows nothing about D exceptions

Then why does my code sample work?

Have a look at the "Remarks" section of the WNDPROC documentation: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633573(v=vs.85).aspx It looks like the behavior will vary greatly on 64-bit Windows OSes (for both 32-bit and 64-bit apps).
Dec 27 2012
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 27 December 2012 at 01:39:11 UTC, Walter Bright 
wrote:
 This applies to any attempt to throw D exceptions in code 
 called by non-D code.

BTW, Why D isn't using the system defined exception ABI if one exists (like on windows) ? Is-it intentional, or lack of documentation/manpower ?
Dec 27 2012
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 27 December 2012 at 09:29:08 UTC, Walter Bright 
wrote:
 On 12/27/2012 12:52 AM, deadalnix wrote:
 On Thursday, 27 December 2012 at 01:39:11 UTC, Walter Bright 
 wrote:
 This applies to any attempt to throw D exceptions in code 
 called by non-D code.

BTW, Why D isn't using the system defined exception ABI if one exists (like on windows) ? Is-it intentional, or lack of documentation/manpower ?

D does use Windows SEH for win32, but not for win64. But still, you gotta ask yourself, what do expect Windows to do with a D exception?

I think it has several advantages to use the same ABI : - Exception cal bubble from D to C++ then back to D to be handled. C++ will run RAII code properly, even if it can't do anything useful with the D exception. This is common when using function pointer or virtual methods. - The same thing goes the other way around : C++ Exception can go throw D code, unwinding stack cleanly. Even if D program cannot do anything really ith the C++ exception, it can at least fail safely and with a stack trace. In many cases, exception are more about exit cleanly than actually catch them and recover. For such a case, common ABI is useful.
Dec 27 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 12/27/12, Walter Bright <newshound2 digitalmars.com> wrote:
 Take a look at druntime\src\rt\dmain2.d. It catches all Throwable's and
 swallows
 them - it does not expect the C runtime to handle D exceptions. This is why
 Throwable is still catchable.

So then `nothrow` on the headers isn't enough since it only guarantees we're catching Exception types and letting Nothrow types through to Windows functions. It sounds to me like we need even stricter enforcement on the headers which the language doesn't provide right now (in hindsight maybe 'nothrow' should have been called 'noexcept'). For example people have problems throwing on x64 in C++ inside a WNDPROC: http://stackoverflow.com/questions/2631452/64bit-exceptions-in-wndproc-silently-fail I wonder if D has the same problem if an Error or Throwable escapes a WNDPROC?
Dec 27 2012
prev sibling next sibling parent Johannes Pfau <nospam example.com> writes:
Am Thu, 27 Dec 2012 16:32:41 +0100
schrieb Andrej Mitrovic <andrej.mitrovich gmail.com>:

 On 12/27/12, Walter Bright <newshound2 digitalmars.com> wrote:
 Take a look at druntime\src\rt\dmain2.d. It catches all Throwable's
 and swallows
 them - it does not expect the C runtime to handle D exceptions.
 This is why Throwable is still catchable.

So then `nothrow` on the headers isn't enough since it only guarantees we're catching Exception types and letting Nothrow types through to Windows functions. It sounds to me like we need even stricter enforcement on the headers

That would probably be useful but I fear it's too late / would make the language too complicated. There's a similar problem in GDC: http://gdcproject.org/bugzilla/show_bug.cgi?id=10 Right now we can't really use nothrow for optimization / we can't simply map it to the gcc nothrow attribute. To the GCC backend it doesn't matter if we throw an exception or an error, __attribute__(nothrow) means the function won't throw anything. We could of course do some advanced conservative analysis on the function (does it call other functions, ...) but that could be done on all functions, nothrow doesn't help there.
Dec 27 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 12/27/12, Walter Bright <newshound2 digitalmars.com> wrote:
 Is it an issue as you describe? Yes. Is it a big enough issue to merit a
 language change? I doubt it.

Ok, but we should at least document it. Currently we only have a small remark in the docs saying exceptions in D are not compatible with C++ exceptions, but we should clarify and maybe add how to work around this, whether to catch Throwable, and what to do when its caught.
Dec 27 2012
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 27 December 2012 at 18:04:45 UTC, Walter Bright 
wrote:
 There is some merit to your argument, and that was the original 
 idea behind building D exceptions out of Win32 SEH. I did the 
 same for the Digital Mars C++ compiler.

 But in practice, and I include a decade with DMC++, I've just 
 never seen a useful application of it.

I don't really know how things are on windows, but I found myself wish it worked on linux or OSX more than once.
Dec 27 2012
prev sibling next sibling parent "Phil Lavoie" <maidenphil hotmail.com> writes:
On Thursday, 27 December 2012 at 18:16:35 UTC, Andrej Mitrovic 
wrote:
 On 12/27/12, Walter Bright <newshound2 digitalmars.com> wrote:
 Is it an issue as you describe? Yes. Is it a big enough issue 
 to merit a
 language change? I doubt it.

Ok, but we should at least document it. Currently we only have a small remark in the docs saying exceptions in D are not compatible with C++ exceptions, but we should clarify and maybe add how to work around this, whether to catch Throwable, and what to do when its caught.

So, if I got this right, doing this is not ideal: extern( Windows ) nothrow LRESULT WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { try { ... } catch( Exception e ) { ... } } And should be changed to : catch( Throwable t ) { ... } ? Thanks, Phil
Dec 28 2012
prev sibling parent Sean Kelly <sean invisibleduck.org> writes:
On Dec 27, 2012, at 5:46 PM, Brad Roberts <braddr puremagic.com> wrote:

 On Thu, 27 Dec 2012, Walter Bright wrote:
=20
 On 12/27/2012 1:52 AM, deadalnix wrote:
 On Thursday, 27 December 2012 at 09:29:08 UTC, Walter Bright wrote:
 D does use Windows SEH for win32, but not for win64. But still, you got=




 ask
 yourself, what do expect Windows to do with a D exception?

I think it has several advantages to use the same ABI : - Exception cal bubble from D to C++ then back to D to be handled. C++ will run RAII code properly, even if it can't do anything useful with the D exception. This is common when using function pointer or virtual methods=



  - The same thing goes the other way around : C++ Exception can go throw=



 code, unwinding stack cleanly. Even if D program cannot do anything real=



 ith
 the C++ exception, it can at least fail safely and with a stack trace.
=20
 In many cases, exception are more about exit cleanly than actually catch=



 them
 and recover. For such a case, common ABI is useful.

There is some merit to your argument, and that was the original idea behi=


 building D exceptions out of Win32 SEH. I did the same for the Digital Ma=


 C++ compiler.
=20
 But in practice, and I include a decade with DMC++, I've just never seen a=


 useful application of it.

It doesn't matter if you can see the utility in it or not. What matters=20=

 is some combination of user expectations and general usability, both of=20=

 which are fairly subjective.  Additionally, for most of that decade,=20
 mixing languages was fairly rare.  These days it's becoming increasingly=20=

 common.  Presenting c++ libraries with c wrappers is much more common now.=

 Using call backs and registration hooks for plugins and other=20
 extensibility mechanisms is WAY more common now than it was 10 years ago. =

 In short, the landscape has and continues to change, so past history is a=20=

 poor measuring stick for future code bases.
=20
 IMHO, having the unwinders NOT be common and uniform in behavior is a=20
 major usage problem.  It might not be important enough to hit the top of=20=

 the todo list right now, but at some point it's going to be.  Either way,=20=

 not being interoperable is a bug in my mind (and I include all the=20
 platform here, not just windows) and will need to be addressed.  It's=20
 roughly in the same category as supporting shared libraries.  They're not=20=

 important at small scale, but at large scale they start to become=20
 critical.  If I can't rely on proper unwinding, there's going to be=20
 problems.
=20
 I'm not familiar with the windows side, but on the posix side, the c++=20
 world developed a fairly sane, multi-language, unwinding system.  There's=20=

 little reason NOT to use it, other than that it takes a little time to=20
 understand and hook into it, and going off on your own path is potentially=

 simpler.

This. Is there some reason we really need a different unwinding mechanism?=20=
Dec 28 2012