digitalmars.D.learn - BetterC + Windows + setjmp longjmp
- SrMordred (4/4) Sep 17 2018 Its possible to use setjmp/longjmp on windows?
- Diederik de Groot (21/25) Sep 17 2018 You can use core.stdc.signal
- SrMordred (6/14) Sep 17 2018 Yes, i'm using signal(SIGSEGV, sigfn_t func), it catches
- Diederik de Groot (10/26) Sep 17 2018 Aah ok. I think signal() and sigaction() are equivalent. Don't
- Mike Parker (11/15) Sep 17 2018 setjmp/longjmp are available on windows (image loaders using
- SrMordred (32/48) Sep 18 2018 I think this may be going beyond my knowledge ;/
- SrMordred (1/1) Sep 18 2018 longjmp is crashing so may be related to the struct declaration.
- SrMordred (4/5) Sep 18 2018 Well just found a thread of the same problem, just that in my
- Diederik de Groot (56/96) Sep 19 2018 I think your definition should look more like this:
- Diederik de Groot (10/14) Sep 19 2018 I don't own any windows machines so had to use these references
- SrMordred (4/18) Sep 19 2018 g++ and clang give me sizeof = 256. dmc give me 64. I tried all
- SrMordred (8/8) Sep 20 2018 Ok, after a better look at the sources I finally got it:
- Diederik de Groot (25/33) Sep 20 2018 Nice to see you managed to figure it all out, congrats!
- Lobachevsky (101/101) May 22 2019 I have been experimenting with setjmp / longjmp under Windows as
- kinke (4/13) May 22 2019 I don't think breaking out of a loop this way can work. The
Its possible to use setjmp/longjmp on windows? Or, to be straight to my problem: its possible to continue execution after a SIGSEGV(or any other failure/signal) with betterC and windows?
Sep 17 2018
On Monday, 17 September 2018 at 23:44:41 UTC, SrMordred wrote:Its possible to use setjmp/longjmp on windows? Or, to be straight to my problem: its possible to continue execution after a SIGSEGV(or any other failure/signal) with betterC and windows?You can use core.stdc.signal nothrow nogc system sigfn_t signal(SIGSEGV, sigfn_t func) To catch the signal With a handler signature of: enum void function(int) nothrow nogc system SIG_ERR; However continuing execution after catching a SIGSEGV is normally considered undefined (at least to POSIX). Quote: According to POSIX, the behavior of a process is undefined after it ignores a SIGFPE, SIGILL, or SIGSEGV signal that was not generated by kill(2) or raise(3). Integer division by zero has undefined result. On some architectures it will generate a SIGFPE signal. (Also dividing the most negative integer by -1 may generate SIGFPE.) Ignoring this signal might lead to an endless loop. From: https://stackoverflow.com/questions/14233464/can-a-c-program-continue-execution-after-a-signal-is-handled#14233912 I am not sure if this is any different on Windows. They handle SIGSEGV differently (ie: as an exception). You would have to read the windows manual, try and test (heavily).
Sep 17 2018
On Tuesday, 18 September 2018 at 00:12:35 UTC, Diederik de Groot wrote:On Monday, 17 September 2018 at 23:44:41 UTC, SrMordred wrote:Yes, i'm using signal(SIGSEGV, sigfn_t func), it catches correctly, but end the execution after. I find the alternatives of setjmp/longjmp and sigaction, but none are avaliable on windows afaik.[...]You can use core.stdc.signal nothrow nogc system sigfn_t signal(SIGSEGV, sigfn_t func) To catch the signal With a handler signature of: enum void function(int) nothrow nogc system SIG_ERR; [...]
Sep 17 2018
On Tuesday, 18 September 2018 at 00:24:23 UTC, SrMordred wrote:On Tuesday, 18 September 2018 at 00:12:35 UTC, Diederik de Groot wrote:Aah ok. I think signal() and sigaction() are equivalent. Don't know about setjmp/longjmp not being available on D-windows. They are defined in core.sys.posix, so not directly available on windows per definition. They might be available under mingw. If you think this is an oversight (as they are part of libc in general) and see a definite need, it should not be too hard to add them, i would think. You would have to ask someone with knowledge and access to windows to help you out though (A druntime PR would be welcome).On Monday, 17 September 2018 at 23:44:41 UTC, SrMordred wrote:Yes, i'm using signal(SIGSEGV, sigfn_t func), it catches correctly, but end the execution after. I find the alternatives of setjmp/longjmp and sigaction, but none are avaliable on windows afaik.[...]You can use core.stdc.signal nothrow nogc system sigfn_t signal(SIGSEGV, sigfn_t func) To catch the signal With a handler signature of: enum void function(int) nothrow nogc system SIG_ERR; [...]
Sep 17 2018
On Tuesday, 18 September 2018 at 00:24:23 UTC, SrMordred wrote:Yes, i'm using signal(SIGSEGV, sigfn_t func), it catches correctly, but end the execution after. I find the alternatives of setjmp/longjmp and sigaction, but none are avaliable on windows afaik.setjmp/longjmp are available on windows (image loaders using libpng, lua, quake3, and lots of old C code make use of them): https://msdn.microsoft.com/en-us/library/xe7acxfb.aspx?f=255&MSPPError=-2147217396 https://msdn.microsoft.com/en-us/library/3ye15wsy.aspx You can declare the functions in your own code and they should link just fine. It would be helpful if you also submit a PR to add them to DRuntime for Windows. As for sigaction, a quick search suggests it isn't available (and it doesn't show up in MSDN): https://stackoverflow.com/questions/32389905/sigaction-and-porting-linux-code-to-windows
Sep 17 2018
On Tuesday, 18 September 2018 at 03:09:18 UTC, Mike Parker wrote:On Tuesday, 18 September 2018 at 00:24:23 UTC, SrMordred wrote:I think this may be going beyond my knowledge ;/ (Trying to follow setjmp.h, don´t have experience doing this) enum _SIGSET_NWORDS = (1024 / (8 * (ulong.sizeof))); struct __sigset_t { ulong[_SIGSET_NWORDS] __val; } struct __jmp_buf_tag { long[8] __jmpbuf; int __mask_was_saved; __sigset_t __saved_mask; }; alias __jmp_buf_tag[1] jmp_buf; extern (C) nogc nothrow int setjmp(ref jmp_buf) ; extern (C) nogc nothrow void longjmp(ref jmp_buf, int); OK, things linked fine. I´m trying to escape a sigfault with signal + set/longjmp: jmp_buf buf; extern(C) nothrow nogc void h1(int code) { longjmp(buf, 1); } //main signal(SIGSEGV, &h1); auto x = setjmp(buf); if(x == 1) ... (go elsewhere) else //forcing some sigfault There are no compilation errors. But my program still just crashes after sigfault. So maybe setjmp/longjmp are not working properly. Or is not possible to escape a crash. Or i completely misunderstood everything :PYes, i'm using signal(SIGSEGV, sigfn_t func), it catches correctly, but end the execution after. I find the alternatives of setjmp/longjmp and sigaction, but none are avaliable on windows afaik.setjmp/longjmp are available on windows (image loaders using libpng, lua, quake3, and lots of old C code make use of them): https://msdn.microsoft.com/en-us/library/xe7acxfb.aspx?f=255&MSPPError=-2147217396 https://msdn.microsoft.com/en-us/library/3ye15wsy.aspx You can declare the functions in your own code and they should link just fine. It would be helpful if you also submit a PR to add them to DRuntime for Windows. As for sigaction, a quick search suggests it isn't available (and it doesn't show up in MSDN): https://stackoverflow.com/questions/32389905/sigaction-and-porting-linux-code-to-windows
Sep 18 2018
longjmp is crashing so may be related to the struct declaration.
Sep 18 2018
On Tuesday, 18 September 2018 at 20:01:48 UTC, SrMordred wrote:longjmp is crashing so may be related to the struct declaration.Well just found a thread of the same problem, just that in my case with 64x crashes too. https://forum.dlang.org/post/mmxwhdypncaeikknlpyq forum.dlang.org
Sep 18 2018
On Tuesday, 18 September 2018 at 19:45:18 UTC, SrMordred wrote:On Tuesday, 18 September 2018 at 03:09:18 UTC, Mike Parker wrote:I think your definition should look more like this: Notes: - modulename using druntime path. - Not 100% sure about all the sizes (lifted from winsdk10). - long/c_long - JBLEN or JBLEN+1 - Compatible with MARS setjmp.h x86 sizes ------ module core.sys.windows.setjmp; extern (C): system: nothrow: nogc: private import core.sys.windows.config; import core.stdc.signal; version ( Windows ): version( X86 ) { enum _JBLEN 16 struct _jmp_buf { int[_JBLEN + 1] _ssjb; } } else version( X86_64) { enum _JBLEN 16 struct { long[2] part; // c_long ? } float128; struct _jmp_buf { float128[_JBLEN] _sjb; } else version (AArch64) { enum _JBLEN 28 struct _jmp_buf { int[_JBLEN] _sjb; } } /* else version (IA64) { enum _JBLEN 33 struct { long _high; long _low; } float128; struct _jmp_buf { float128[_JBLEN] _sjb; } */ else static assert(0, "Not implemented for platforms other than X86, yet"); alias _jmp_buf[_JBLEN] jmp_buf; int setjmp(ref jmp_buf); void longjmp(ref jmp_buf, int); -------- Only the exact size of the jmp_buf is important (not the details about the content). We only call a function with it, we never look inside.On Tuesday, 18 September 2018 at 00:24:23 UTC, SrMordred wrote:I think this may be going beyond my knowledge ;/ (Trying to follow setjmp.h, don´t have experience doing this) enum _SIGSET_NWORDS = (1024 / (8 * (ulong.sizeof))); struct __sigset_t { ulong[_SIGSET_NWORDS] __val; } struct __jmp_buf_tag { long[8] __jmpbuf; int __mask_was_saved; __sigset_t __saved_mask; }; alias __jmp_buf_tag[1] jmp_buf; extern (C) nogc nothrow int setjmp(ref jmp_buf) ; extern (C) nogc nothrow void longjmp(ref jmp_buf, int);Yes, i'm using signal(SIGSEGV, sigfn_t func), it catches correctly, but end the execution after. I find the alternatives of setjmp/longjmp and sigaction, but none are avaliable on windows afaik.setjmp/longjmp are available on windows (image loaders using libpng, lua, quake3, and lots of old C code make use of them): https://msdn.microsoft.com/en-us/library/xe7acxfb.aspx?f=255&MSPPError=-2147217396 https://msdn.microsoft.com/en-us/library/3ye15wsy.aspx You can declare the functions in your own code and they should link just fine. It would be helpful if you also submit a PR to add them to DRuntime for Windows. As for sigaction, a quick search suggests it isn't available (and it doesn't show up in MSDN): https://stackoverflow.com/questions/32389905/sigaction-and-porting-linux-code-to-windows
Sep 19 2018
On Wednesday, 19 September 2018 at 11:06:23 UTC, Diederik de Groot wrote:On Tuesday, 18 September 2018 at 19:45:18 UTC, SrMordred wrote:Only the exact size of the jmp_buf is important (not the details about the content). We only call a function with it, we never look inside.I don't own any windows machines so had to use these references (and could not test anything): - WinSDK10: goo.gl/m9DjZt - MARS: goo.gl/Qoc6g2 Code above does not yet cover the Mars case, but the i386 sizes should be the same. Please Note: setjmp/longjmp should only be used in " system + nogc + nothrow / -betterC" code.
Sep 19 2018
On Wednesday, 19 September 2018 at 11:12:41 UTC, Diederik de Groot wrote:On Wednesday, 19 September 2018 at 11:06:23 UTC, Diederik de Groot wrote:g++ and clang give me sizeof = 256. dmc give me 64. I tried all this sizes and other, but still crashes.On Tuesday, 18 September 2018 at 19:45:18 UTC, SrMordred wrote:Only the exact size of the jmp_buf is important (not the details about the content). We only call a function with it, we never look inside.I don't own any windows machines so had to use these references (and could not test anything): - WinSDK10: goo.gl/m9DjZt - MARS: goo.gl/Qoc6g2 Code above does not yet cover the Mars case, but the i386 sizes should be the same. Please Note: setjmp/longjmp should only be used in " system + nogc + nothrow / -betterC" code.
Sep 19 2018
Ok, after a better look at the sources I finally got it: setjmp is a macro. the true function signature is "int _setjmp(jmp_buf, void*)" the void* is the current function address which in mingw sources are capture by "__builtin_frame_address(0)". And I did´t look yet to see if Dlang have an equivalent. but calling _setjmp(jmp_buf, null); the simple examples are working :)
Sep 20 2018
On Thursday, 20 September 2018 at 12:11:55 UTC, SrMordred wrote:Ok, after a better look at the sources I finally got it: setjmp is a macro. the true function signature is "int _setjmp(jmp_buf, void*)" the void* is the current function address which in mingw sources are capture by "__builtin_frame_address(0)". And I did´t look yet to see if Dlang have an equivalent. but calling _setjmp(jmp_buf, null); the simple examples are working :)Nice to see you managed to figure it all out, congrats! So it now looks something like this ?: version(Windows) { version(X86) enum _JBLEN = 64; else version(X86_64) enum _JBLEN = 256; else version(IA64) enum _JBLEN = 528; alias ubyte[_JBLEN] jmp_buf; extern (C) { int _setjmp(ref jmp_buf, null); void longjmp(ref jmp_buf, int); } alias _setjmp setjmp; } Hopefully you will be able to merge the two examples and create a nice druntime PR out of it. The https://forum.dlang.org/post/mmxwhdypncaeikknlpyq forum.dlang.org version does look a lot cleaner (but also a little more cryptic). Might be wise to follow the core.sys.posix.setjmp.d implementation. If available, maybe also add the sigsetjmp / siglonggmp and sigaction versions (if available on windows). Good luck !
Sep 20 2018
I have been experimenting with setjmp / longjmp under Windows as a way to break out of an endless loop. With my experiments, longjmp appears to silently exit the process, no stack trace, nothing. Black emptiness. I stared with the C program described in https://docs.microsoft.com/en-us/windows/console/setconsolectrlhandler and added the setjmp and longjmp code fragments. When I try this, the CtrlHandler is successfully loaded and it even beeps accordingly when cntl-C and cntl-break are pressed. Of course, the Microsoft documentation warns against using setjmp / longjump from callbacks: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/longjmp?view=vs-2019 Here is the companion Microsoft setjmp documentation: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setjmp?view=vs-2019 I'm using DMD 2.084, VS 2017, not using BetterC Compiler arguments: -boundscheck=on -dw -c -gf -debug -g -m64 -wi Linker: /OUT:"C:\Users\...\Test.exe" /MANIFEST /NXCOMPAT /PDB:"C:\Users\...\Test.pdb" /DEBUG /MACHINE:X64 /INCREMENTAL /PGD:"C:\Users\...\Test.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"x64\Debug\Testexe.intermediate.manifest" /ERRORREPORT:PROMPT /VERBOSE:Lib /TLBID:1 Suggestions welcome. ---------------------------------------------------------------------------- // CtrlHandler.d : This file contains the 'main' function. Program execution begins and ends there. // See https://docs.microsoft.com/en-us/windows/console/setconsolectrlhandler module CtrlHandler; import core.sys.posix.setjmp; import std.conv; import core.sys.windows.windows; import std.stdio; // #include <windows.h> // #include <stdio.h> alias ubyte[1024] jmp_buf; extern(C) { int _setjmp(ref jmp_buf) nothrow; void longjmp(ref jmp_buf, int) nothrow; } alias _setjmp setjmp; public static jmp_buf buf; extern (Windows) private static int CtrlHandler(uint fdwCtrlType) nothrow { switch (fdwCtrlType) { // Handle the CTRL-C signal. case CTRL_C_EVENT: // writeln("Ctrl-C event\n\n"); Beep(750, 300); longjmp(buf, 42); break; // CTRL-CLOSE: confirm that the user wants to exit. case CTRL_CLOSE_EVENT: Beep(600, 200); // writeln("Ctrl-Close event\n\n"); longjmp(buf, 39); break; // Pass other signals to the next handler. case CTRL_BREAK_EVENT: Beep(900, 200); // writeln("Ctrl-Break event\n\n"); longjmp(buf, 13); break; case CTRL_LOGOFF_EVENT: Beep(1000, 200); // writeln("Ctrl-Logoff event\n\n"); return 0; case CTRL_SHUTDOWN_EVENT: Beep(750, 500); // writeln("Ctrl-Shutdown event\n\n"); return 0; default: return 0; } return 0; } int main(string[] args) { int sj; sj = setjmp(buf); writeln("sj = " ~ to!string(sj)); readln(); if (sj != 0) goto breakout; if (SetConsoleCtrlHandler(&CtrlHandler, 1)) { writeln("\nThe Control Handler is installed.\n"); writeln("\n -- Now try pressing Ctrl+C or Ctrl+Break, or"); writeln("\n try logging off or closing the console...\n"); writeln("\n(...waiting in a loop for events...)\n\n"); while (1) {} } else { writeln("\nERROR: Could not set control handler"); return 1; } breakout: writeln("\nSuccessfully broke out of endless loop - sj = " ~ to!string(sj)); return 0; }
May 22 2019
On Wednesday, 22 May 2019 at 16:37:36 UTC, Lobachevsky wrote:I have been experimenting with setjmp / longjmp under Windows as a way to break out of an endless loop. With my experiments, longjmp appears to silently exit the process, no stack trace, nothing. Black emptiness.I don't think breaking out of a loop this way can work. The CtrlHandler is called by another thread. Quoting from https://docs.microsoft.com/en-us/windows/console/handlerroutine:An application-defined function used with the SetConsoleCtrlHandler function. A console process uses this function to handle control signals received by the process. When the signal is received, the system creates a new thread in the process to execute the function.
May 22 2019