www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - BetterC + Windows + setjmp longjmp

reply SrMordred <patric.dexheimer gmail.com> writes:
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
parent reply Diederik de Groot <ddegroot talon.nl> writes:
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
parent reply SrMordred <patric.dexheimer gmail.com> writes:
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:
 [...]
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; [...]
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.
Sep 17 2018
next sibling parent Diederik de Groot <ddegroot talon.nl> writes:
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:
 On Monday, 17 September 2018 at 23:44:41 UTC, SrMordred wrote:
 [...]
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; [...]
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.
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).
Sep 17 2018
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
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
parent reply SrMordred <patric.dexheimer gmail.com> writes:
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:

 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
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 :P
Sep 18 2018
next sibling parent reply SrMordred <patric.dexheimer gmail.com> writes:
longjmp is crashing so may be related to the struct declaration.
Sep 18 2018
parent SrMordred <patric.dexheimer gmail.com> writes:
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
prev sibling parent reply Diederik de Groot <ddegroot talon.nl> writes:
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:
 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
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);
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.
Sep 19 2018
parent reply Diederik de Groot <ddegroot talon.nl> writes:
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
parent reply SrMordred <patric.dexheimer gmail.com> writes:
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:
 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.
g++ and clang give me sizeof = 256. dmc give me 64. I tried all this sizes and other, but still crashes.
Sep 19 2018
parent reply SrMordred <patric.dexheimer gmail.com> writes:
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
parent reply Diederik de Groot <ddegroot talon.nl> writes:
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
parent reply Lobachevsky <ibeam2000 gmail.com> writes:
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
parent kinke <noone nowhere.com> writes:
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