[Linux] Try/Catch

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
IchMagBier
Posts: 52
Joined: Jan 13, 2018 8:47
Location: Germany
Contact:

[Linux] Try/Catch

Post by IchMagBier »

Hello :)

I wrote this simple exception handler for Linux, which can catch segmentation faults and user defined exceptions, without terminating the program:

Code: Select all

#include "trycatch.bi"

try ' // segmentation fault
	dim as long ptr bla
	*bla = 42
catch(e as Exception)
	if e = SEGMENTATION_FAULT then
		print "Fix your pointer!"
	else
		print "Unknown exception: "+str(e)
	end if
endtry

try ' // illegal machine code
	asm ud2
catch(e as Exception)
	if e = ILLEGAL_INSTRUCTION then
		print "Fix your code!"
	else
		print "Unknown exception: "+str(e)
	end if
endtry

try ' // user defined exceptions
	throw(42)
catch(e as Exception)
	print "Unknown exception: "+str(e)
endtry
trycatch.bi:

Code: Select all

#include "crt/setjmp.bi"

#define ILLEGAL_INSTRUCTION 4
#define BUS_ERROR 7
#define SEGMENTATION_FAULT 11

type sigaction
	sa_sigaction as sub(signal as long) ' void (*sa_sigaction) (int, siginfo_t *, void *)
	as uinteger sa_mask(1024 / (8*8))
	as long sa_flags
	sa_restorer as sub()
end type

extern "C"
	declare sub sigaction(signal as long, __act as sigaction ptr, __oact as sigaction ptr)
end extern

dim shared as jmp_buf __signal_jmp_buf
dim shared as long __sa_signal, __fault

sub __sigsegv(signal as long)
	__sa_signal = signal
	longjmp(@__signal_jmp_buf, 1)
end sub

dim shared as sigaction __sa
for i as ulong = 0 to 1024/(8*8)
	__sa.sa_mask(i) = 0
next
__sa.sa_restorer = 0
__sa.sa_flags = 0
__sa.sa_sigaction = @__sigsegv()
sigaction(ILLEGAL_INSTRUCTION, @__sa, 0)
sigaction(BUS_ERROR, @__sa, 0)
sigaction(SEGMENTATION_FAULT, @__sa, 0)

#macro try
	__fault = setjmp(@__signal_jmp_buf)
	if __fault = 0 then
#endmacro

#macro catch(signal)
	else
		dim signal = __sa_signal
#endmacro

sub throw(signal as long)
	__sa_signal = signal
	longjmp(@__signal_jmp_buf, signal)
end sub

#define endtry end if
type Exception as long
This isn't limited to exceptions, you can catch other POSIX-signals aswell like this:

Code: Select all

try
catch(e as Exception)
	if e = 1 then ' SIGHUP
endtry
Xusinboy Bekchanov
Posts: 793
Joined: Jul 26, 2018 18:28

Re: [Linux] Try/Catch

Post by Xusinboy Bekchanov »

Such things can be entered into keywords, thank you.
In my opinion, these keywords are already in vb.net.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: [Linux] Try/Catch

Post by Tourist Trap »

Xusinboy Bekchanov wrote: these keywords are already in vb.net
Yes they are used all the time. Don't know if it's always good, but at least this prevents crashes.
If we could have the same also for windows that would be really a feature I think.
caseih
Posts: 2158
Joined: Feb 26, 2007 5:32

Re: [Linux] Try/Catch

Post by caseih »

Be careful handling SIGSEGV. Usually a segfault is a sure sign of memory corruption and the only safe thing to do is to write out your memory state for future debugging and crash. Of course there are reasons for handling that signal, such as managing child processes.
Tourist Trap wrote:
Xusinboy Bekchanov wrote: these keywords are already in vb.net
Yes they are used all the time. Don't know if it's always good, but at least this prevents crashes.
If we could have the same also for windows that would be really a feature I think.
What do you mean by "prevent crashes?" Exception handling should not prevent crashes. As I said about segfaults, crashes are often the only sensible thing to do. A program cannot recover from memory corruption generally; rather the bug must be fixed in the source code that caused the memory corruption.

I think a good rule of thumb with exceptions is to not catch them. They are, after all, by definition exceptional events. Unless your program is expecting them and has explicitly been designed to mitigate them, you shouldn't catch them, but let them bubble up to another layer that is prepared to deal with them, or to crash out. Opening a file for reading that doesn't exist could cause an exception that a program can easily deal with. Other situations are more complex. I think this is why most programmers cringe at exception handling. That's why I like the way Python does exceptions. 99% of the time you don't worry about them and they work as designed.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: [Linux] Try/Catch

Post by Tourist Trap »

caseih wrote:]What do you mean by "prevent crashes?" Exception handling should not prevent crashes. As I said about segfaults, crashes are often the only sensible thing to do.
I agree with all you say here, but my focus was on the TRY. We try, this goes wrong, so we make a step back and and finally do otherwise. My feeling however is that, 1) a programmer should not just try to execute things that he knows are prone to crash, but rather avoid them. And 2) I was never sure if we really can "step back".

The other point is that in .net, you are often expected to be selling your programs to any potential user. So you don't want it to crash in a hard way. This is what customers really hate.

All this said, again I think that we should use this with parcimony, and yet it would be a valuable feature in the case you are sharing your program with others that hate crashes, and for development purpose also, and so on.

I don't see how Python *specifically* handle the exception. I use it only in the interpreted environnement, so it doesn't compare to my eyes to when the executable is left walking alone.
caseih
Posts: 2158
Joined: Feb 26, 2007 5:32

Re: [Linux] Try/Catch

Post by caseih »

I guess my point is that if something has gone so wrong that it's going to lead to a segfault (IE the program will blow up), then catching that is just hiding the problem and allowing it to become much worse and potentially lose a lot more of the user's data. I'm not talking about trying to read from a file that doesn't exist. I'm talking about the segfault here. In Unix operating systems you should very rarely handle SIGSEGV. I'm specifically talking about @IchMagBier's post. Catching segmentation faults is very bad usually, except to do emergency bail out. Ultimately after a segfault, the only appropriate course of action is to abort the program. Because all bets are off.

More generally for exception handling, any exception that you haven't explicitly planned for should be allowed to ultimately crash the program (hopefully gracefully) and generate a debug trace or whatever. That's honestly the only way you'll ever find and solve the problems that caused the exceptions. Yes I'm talking about commercial software here too. Silent failure is far worse than a user's bug report. Some commercial programs deal with crashing by logging the error and quickly restarting the crashed part. Probably a good strategy for making robust software.

You describe two possibilities with regards to error handling that are worth discussing. Put in another way, what you described can be summarized by the more common phrases in computer programming:
- look before you leap
- better to ask forgiveness than permission.

The first is very common, however there are circumstances where this can be a bad idea. For example, programmers sometimes check for the existence of a file before operating on it. This sounds logical, but in a multi-user, multi-core system, this can lead to failure. Files can disappear between the time you check for the file's existence, and the time the file operation is commenced. This is why often it's better to just blindly try the file operation and catch the common errors there (asking permission instead of forgiveness).
marcov
Posts: 3462
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: [Linux] Try/Catch

Post by marcov »

The trick of try catch and try finally is nested use. This is where macro based workarounds usually fail.
IchMagBier
Posts: 52
Joined: Jan 13, 2018 8:47
Location: Germany
Contact:

Re: [Linux] Try/Catch

Post by IchMagBier »

caseih wrote:I'm specifically talking about @IchMagBier's post. Catching segmentation faults is very bad usually, except to do emergency bail out. Ultimately after a segfault, the only appropriate course of action is to abort the program. Because all bets are off.
Well, I was in need for a "try catch" for my program, where an in-memory compiler compiles and executes some user-written code and I didn't want the whole program to crash when a segfault occurs in there, but instead exit the function, log the error and jump back to the main program.

Handling segfaults may also be useful to crash more "gracefully". Like displaying a proper error-message, maybe graphically, instead of showing a simple "Segmentation fault" in the terminal. By inspecting the "rip"-value from where the crash occured, you could tell the user, what exactly went wrong and how he could fix it. Maybe some corrupted file caused the crash, or a shared memory buffer wasn't correctly initialized or whatever. You could also include some register dumps or values from the stack to show more useful debug info.
Post Reply