SIGSEGV recovery? - c

I ve got some SSE procedure which zeroes memory in loop,
When pointer is unaligned it raises SIGSEGV which goes
into my handler. Can I get more info here in such handler
routine, Now I got no info where it was done, can I also
react in some predictible way from it? When I chose to
ignore it It seemd to me that it should go back and becouse
it was in loop raise SIGSEGV again, (got such behaviour with
division by zero when where I ignore it it just goes on
further) but it does not work here such way but sadly just
crashes after ignoring. Can I do some more eleborate recovery here?
EDIT - ADD
in my signal.h (some very old win32 compiler but I use it)
I have such stuff
/* _SIGCONTEXT contains exception info for WIN32 exceptions that were caught
and turned into signals. There will always be three 32-bit parameters
passed to the user's signal handler. Unused parameters will be 0. The
_PSIGCONTEXT parameter will always be the last (third) parameter.
*/
typedef struct
{
struct _EXCEPTION_RECORD * _pexecptionrecord; /* defined in WINNT.H */
struct _CONTEXT * _pcontext; /* defined in WINNT.H */
unsigned long _result; /* return value for the SEH */
} _SIGCONTEXT, *_PSIGCONTEXT;
typedef int sig_atomic_t; /* Atomic entity type (ANSI) */
typedef void (*_CatcherPTR)(int);
#define SIG_DFL ((_CatcherPTR)0) /* Default action */
#define SIG_IGN ((_CatcherPTR)1) /* Ignore action */
#define SIG_ERR ((_CatcherPTR)-1) /* Error return */
//////////////////////////////////
//skipped #define SIGABRT 22
// #define SIGFPE 8 .... constants block here
int raise(int __sig);
void (*signal(int __sig, void (*__func)(int) )) (int);
Signal Raise are understood for me but how to get to data of SIGCONTEXT or use 'catcher' ?

While it is possible on some operating systems under certain circumstances to catch and handle SIGSEGV, SIGBUS, SIGILL and SIGFPE it's a really bad idea to do anything other than crashing. They indicate a bug in your program that you need to fix, not something you just sweep under the rug.
But in case you really enjoy shooting yourself in the foot and leaving horrible undebuggable and unmaintainable messes that others will have to clean up after you while cursing you and your ancestors while wishing that voodoo worked, have a peek at the documentation for sigaction() and how siginfo_t. They contain at least some parts of what you need.

Related

How to trigger a memory range access exception?

How can a program signal itself when it does a write access to a configurable memory region?
This would be something similar to the data-breakpoint feature found in some debuggers. POSIX compliance is desired but not required as long as it works on Linux.
Here there is an illustrative code of what I would like:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void configure_trap(void *FROM, void *TO){
/*
Set a trap on write access to any memory location from
address FROM to address TO.
When the trap is triggered, send SIGTRAP to the process.
There is no need for an answer to have the full code, just
an indication on how to proceed.
*/
}
char *ptr;
void trap_signal_handler(int signum){
if(ptr[123] == 'x'){
printf("Invalid value in ptr[123] !!!\n");
/*
Print a backtrace using libunwind. (Not part of this question.)
*/
}
}
void some_function(){
ptr[123] = 'x';
/*
This write access could be performed directly in this function or
another function called directly or indirectly by this one and it
could reside in this program or in an external library or could even
be performed in a system call.
trap_signal_handler should be called at this point.
After the signal handler has been executed, program should resume
normal operation.
*/
}
int main(){
struct sigaction sa = { .sa_handler = trap_signal_handler };
sigaction(SIGTRAP, &sa, NULL);
ptr = malloc(1024);
configure_trap(&ptr[123], &ptr[123]);
some_function();
return(0);
}
Thanks!
First, use mprotect() to mark a page read-only. Then when it is written, SIGSEGV will be raised. You will have installed a signal handler for this, and if it is done using sigaction you can know what address was accessed by inspecting si_addr. For more on this, see: C SIGSEGV Handler & Mprotect
Note that mprotect() has a granularity of one page, meaning if you try to protect a single byte, you will actually have protected 4 KB (if that's your page size).
Use the https://github.com/vicencb/qdbp project.
It first mprotects the memory page as read-only.
When a SIGSEGV is raised it single steps your program one instruction at a time until the one that caused the write to the read-only memory.
Then it calls your callback.

Don't understand signal

Could someone tell me what this line does:
if(signal(SIGUSR1, handler) == (sighandler_t)-1)
It is a line I copied from an exercise, which made it work, but I don't really understand it. Could someone explain this to me? (It is actually the second part I don't understand: what is the value of (sighandler_t)-1?)
Thank you :)
edit: the sighandler_t comes from
typedef void (*sighandler_t)(int);
First of all, it is a bad style and probably non-portable code, (sighandler_t)-1 should be replaced with one of the predefined signal dispositions. On my system they are declared in next way
/* Fake signal functions. */
#define SIG_ERR ((__sighandler_t) -1) /* Error return. */
#define SIG_DFL ((__sighandler_t) 0) /* Default action. */
#define SIG_IGN ((__sighandler_t) 1) /* Ignore signal. */
Other systems may use another values, so assuming that your uses the same definitions, we get next code:
if(signal(SIGUSR1, handler) == SIG_ERR) {
/* got problem */
} else {
/* handler installed */
}
This code installs function handler as handler for signal SIGUSR1 and checks returned value to ensure that it was done successfully. handler must be declared as void handler(int signo);
(sighandler_t)-1 is the minus one digit, cast it into sighandler_t type. You must check to see if the signal call has failed.

Can interrupts be handled in standard C?

Is there a method of servicing hardware interrupts in standard C (ANSI/ISO)? All the implementations Ive seen so far either use compiler specific language extensions or pre-processor directives.
I just came across the standard C library 'signals' feature, but wikipedia is very light on its use and I dont think it serves the purpose.
POSIX signals can allow a user program written in C to catch and handle some types of interrupts and/or exceptions. It's the most standard approach I know about.
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
int a,b,*p;
jmp_buf jump_destination;
void exception_handler (int sg)
{
printf ("Error dereferencing pointer\n");
p=&b; /* pointer quick fix. */
longjmp(jump_destination,1); /* long GOTO... */
}
void main (void)
{
int i;
signal (SIGSEGV, exception_handler);
b=0; p=NULL;
setjmp(jump_destination); /* ...to this position */
printf ("Trying to dereference pointer p with value %08.8X... ",p);
printf ("After dereferencing pointer, its value is: %d\n", *p);
}
For hardware interrupts, C has no explicit semantics, mainly because it is not needed. For example, a Linux device driver can install its own interrupt handler for a hardware device. All you need is to call request_irq() function with the address of the function that will be in charge of handling the interrupt.
For example, this will install an interrupt handler for the RTC chip (assumming it's present and activated in your hardware)
...
...
res=request_irq (8, /* que IRQ queremos */
interrupt_handler, /* address of handler */
IRQF_DISABLED, /* this is not a shared IRQ */
“mydriver", /* to be shown at /proc/interrupts */
NULL);
if (res!=0)
{
printk ("Can't request IRQ 8\n");
}
...
...
Your handler is just a regular C function:
static irqreturn_t gestor_interrupcion (int irq, void *dev_id, struct pt_regs *regs)
{
/* do stuff with your device, like read time or whatever */
...
...
...
return IRQ_HANDLED; /* notify the kernel we have handled this interrupt */
}
This is possible (to use a regular C function to handle a hardware interrupt) because the handler itself is called from another kernel function, that has taken care of preserving the current context so the interrupted process won't notice anything. If you are dealing with interrupts in a "naked" computer and you want to keep your C code from deviating from the standard, then you will need to use some assembler to call your function.
No.
Signals (from POSIX) aren't for handling hardware interrupts, though they can be connected to them. They're for handling higher level system events.
You'll have to do something like the implementations you've seen, with specific code for each hardware platform you want to support.
At some point your implementation will have to interface with some standard outside of the C spec, whether that's Linux's family of types and function signatures that define interrupt handlers, a similar body of C code built up for another operating system, or maybe the hardware spec for an embedded platform that would allow you to implement your own. If you can clarify your goal, it might be possible to give a more specific answer.

Can a C program continue execution after a signal is handled?

I'm new at signal handling in Unix through C and I have been looking at some tutorials on it (out of pure interest).
My questions is, is it possible to continue execution of a program past the point where a signal is handled?
I understand that the signal handling function does the cleanup but in the spirit of exception handling (such as in C++), is it possible for that signal to be handled in the same fashion and for the program to continue running normally?
At the moment catch goes in an infinite loop (presumably a way to quit would be to call exit(1) ).
My intention would be for b to be assigned 1 and for the program to finish gracefully (if that is possible of course).
Here's my code:
#include <signal.h>
#include <stdio.h>
int a = 5;
int b = 0;
void catch(int sig)
{
printf("Caught the signal, will handle it now\n");
b = 1;
}
int main(void)
{
signal(SIGFPE, catch);
int c = a / b;
return 0;
}
Also, as C is procedural, how come the signal handler declared before the offending statement is actually called after the latter has executed?
And finally, in order for the handling function to do its clean up properly, all the variables than need to be cleaned up in the event of an exception need to be declared prior to the function, right?
Thanks in advance for your answers and apologies if some of the above is very obvious.
Yes, that's what signal handlers are for. But some signals need to be handled specially in order to allow the program to continue (e.g. SIGSEGV, SIGFPE, …).
See the manpage of sigaction:
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.
Right now, you are ignoring the signal, by not doing anything to prevent it from happening (again). You need the execution context in the signal handler and fix it up manually, which involves overwriting some registers.
If SA_SIGINFO is specified in sa_flags, then sa_sigaction (instead of
sa_handler) specifies the signal-handling function for signum. This
function receives the signal number as its first argument, a pointer
to a siginfo_t as its second argument and a pointer to a ucontext_t
(cast to void *) as its third argument. (Commonly, the handler
function doesn't make any use of the third argument. See
getcontext(2) for further information about ucontext_t.)
The context allows access to the registers at the time of fault and needs to be changed to allow your program to continue. See this lkml post. As mentioned there, siglongjmp might also be an option. The post also offers a rather reusable solution for handling the error, without having to make variables global etc.:
And because you handle it youself, you have any flexibility you want
to with error handling. For example, you can make the fault handler
jump to some specified point in your function with something like
this:
__label__ error_handler;
__asm__("divl %2"
:"=a" (low), "=d" (high)
:"g" (divisor), "c" (&&error_handler))
... do normal cases ...
error_handler:
... check against zero division or overflow, so whatever you want to ..
Then, your handler for SIGFPE needs only to do something like
context.eip = context.ecx;
If you know what you are doing, you can set the instruction pointer to point right after the offending instruction. Below is my example for x86 (32bit and 64bit). Don't try at home or in real products !!!
#define _GNU_SOURCE /* Bring REG_XXX names from /usr/include/sys/ucontext.h */
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ucontext.h>
static void sigaction_segv(int signal, siginfo_t *si, void *arg)
{
ucontext_t *ctx = (ucontext_t *)arg;
/* We are on linux x86, the returning IP is stored in RIP (64bit) or EIP (32bit).
In this example, the length of the offending instruction is 6 bytes.
So we skip the offender ! */
#if __WORDSIZE == 64
printf("Caught SIGSEGV, addr %p, RIP 0x%lx\n", si->si_addr, ctx->uc_mcontext.gregs[REG_RIP]);
ctx->uc_mcontext.gregs[REG_RIP] += 6;
#else
printf("Caught SIGSEGV, addr %p, EIP 0x%x\n", si->si_addr, ctx->uc_mcontext.gregs[REG_EIP]);
ctx->uc_mcontext.gregs[REG_EIP] += 6;
#endif
}
int main(void)
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = sigaction_segv;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
/* Generate a seg fault */
*(int *)NULL = 0;
printf("Back to normal execution.\n");
return 0;
}
In general, yes, execution continues after the handler returns. But if the signal was caused by a hardware error (such as a floating point exception or a segmentation fault), you have no way of undoing that error, and so your program will be terminated regardless.
In other words, you have to distinguish between signals and things that cause signals. Signals by themselves are perfectly fine and handlable, but they don't always let you fix errors that cause signals.
(Some signals are special, such as ABRT and STOP, in the sense that even if you just raise such a signal manually with kill, you still can't "prevent its effects". And of course KILL cannot even be handled at all.)

Coming back to life after Segmentation Violation

Is it possible to restore the normal execution flow of a C program, after the Segmentation Fault error?
struct A {
int x;
};
A* a = 0;
a->x = 123; // this is where segmentation violation occurs
// after handling the error I want to get back here:
printf("normal execution");
// the rest of my source code....
I want a mechanism similar to NullPointerException that is present in Java, C# etc.
Note: Please, don't tell me that there is an exception handling mechanism in C++ because I know that, dont' tell me I should check every pointer before assignment etc.
What I really want to achieve is to get back to normal execution flow as in the example above. I know some actions can be undertaken using POSIX signals. How should it look like? Other ideas?
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <signal.h>
#include <stdlib.h>
#include <ucontext.h>
void safe_func(void)
{
puts("Safe now ?");
exit(0); //can't return to main, it's where the segfault occured.
}
void
handler (int cause, siginfo_t * info, void *uap)
{
//For test. Never ever call stdio functions in a signal handler otherwise*/
printf ("SIGSEGV raised at address %p\n", info->si_addr);
ucontext_t *context = uap;
/*On my particular system, compiled with gcc -O2, the offending instruction
generated for "*f = 16;" is 6 bytes. Lets try to set the instruction
pointer to the next instruction (general register 14 is EIP, on linux x86) */
context->uc_mcontext.gregs[14] += 6;
//alternativly, try to jump to a "safe place"
//context->uc_mcontext.gregs[14] = (unsigned int)safe_func;
}
int
main (int argc, char *argv[])
{
struct sigaction sa;
sa.sa_sigaction = handler;
int *f = NULL;
sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
if (sigaction (SIGSEGV, &sa, 0)) {
perror ("sigaction");
exit(1);
}
//cause a segfault
*f = 16;
puts("Still Alive");
return 0;
}
$ ./a.out
SIGSEGV raised at address (nil)
Still Alive
I would beat someone with a bat if I saw something like this in production code though, it's an ugly, for-fun hack. You'll have no idea if the segfault have corrupted some of your data, you'll have no sane way of recovering and know that everything is Ok now, there's no portable way of doing this. The only mildly sane thing you could do is try to log an error (use write() directly, not any of the stdio functions - they're not signal safe) and perhaps restart the program. For those cases you're much better off writing a superwisor process that monitors a child process exit, logs it and starts a new child process.
You can catch segmentation faults using a signal handler, and decide to continue the excecution of the program (at your own risks).
The signal name is SIGSEGV.
You will have to use the sigaction() function, from the signal.h header.
Basically, it works the following way:
struct sigaction sa1;
struct sigaction sa2;
sa1.sa_handler = your_handler_func;
sa1.sa_flags = 0;
sigemptyset( &sa1.sa_mask );
sigaction( SIGSEGV, &sa1, &sa2 );
Here's the prototype of the handler function:
void your_handler_func( int id );
As you can see, you don't need to return. The program's execution will continue, unless you decide to stop it by yourself from the handler.
"All things are permissible, but not all are beneficial" - typically a segfault is game over for a good reason... A better idea than picking up where it was would be to keep your data persisted (database, or at least a file system) and enable it to pick up where it left off that way. This will give you much better data reliability all around.
See R.'s comment to MacMade answer.
Expanding on what he said, (after handling SIGSEV, or, for that case, SIGFPE, the CPU+OS can return you to the offending insn) here is a test I have for division by zero handling:
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
static jmp_buf context;
static void sig_handler(int signo)
{
/* XXX: don't do this, not reentrant */
printf("Got SIGFPE\n");
/* avoid infinite loop */
longjmp(context, 1);
}
int main()
{
int a;
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = sig_handler;
sa.sa_flags = SA_RESTART;
sigaction(SIGFPE, &sa, NULL);
if (setjmp(context)) {
/* If this one was on setjmp's block,
* it would need to be volatile, to
* make sure the compiler reloads it.
*/
sigset_t ss;
/* Make sure to unblock SIGFPE, according to POSIX it
* gets blocked when calling its signal handler.
* sigsetjmp()/siglongjmp would make this unnecessary.
*/
sigemptyset(&ss);
sigaddset(&ss, SIGFPE);
sigprocmask(SIG_UNBLOCK, &ss, NULL);
goto skip;
}
a = 10 / 0;
skip:
printf("Exiting\n");
return 0;
}
No, it's not possible, in any logical sense, to restore normal execution following a segmentation fault. Your program just tried to dereference a null pointer. How are you going to carry on as normal if something your program expects to be there isn't? It's a programming bug, the only safe thing to do is to exit.
Consider some of the possible causes of a segmentation fault:
you forgot to assign a legitimate value to a pointer
a pointer has been overwritten possibly because you are accessing heap memory you have freed
a bug has corrupted the heap
a bug has corrupted the stack
a malicious third party is attempting a buffer overflow exploit
malloc returned null because you have run out of memory
Only in the first case is there any kind of reasonable expectation that you might be able to carry on
If you have a pointer that you want to dereference but it might legitimately be null, you must test it before attempting the dereference. I know you don't want me to tell you that, but it's the right answer, so tough.
Edit: here's an example to show why you definitely do not want to carry on with the next instruction after dereferencing a null pointer:
void foobarMyProcess(struct SomeStruct* structPtr)
{
char* aBuffer = structPtr->aBigBufferWithLotsOfSpace; // if structPtr is NULL, will SIGSEGV
//
// if you SIGSEGV and come back to here, at this point aBuffer contains whatever garbage was in memory at the point
// where the stack frame was created
//
strcpy(aBuffer, "Some longish string"); // You've just written the string to some random location in your address space
// good luck with that!
}
Call this, and when a segfault will occur, your code will execute segv_handler and then continue back to where it was.
void segv_handler(int)
{
// Do what you want here
}
signal(SIGSEGV, segv_handler);
There is no meaningful way to recover from a SIGSEGV unless you know EXACTLY what caused it, and there's no way to do that in standard C. It may be possible (conceivably) in an instrumented environment, like a C-VM (?). The same is true for all program error signals; if you try to block/ignore them, or establish handlers that return normally, your program will probably break horribly when they happen unless perhaps they're generated by raise or kill.
Just do yourself a favour and take error cases into account.
In POSIX, your process will get sent SIGSEGV when you do that. The default handler just crashes your program. You can add your own handler using the signal() call. You can implement whatever behaviour you like by handling the signal yourself.
You can use the SetUnhandledExceptionFilter() function (in windows), but even to be able to skip the "illegal" instruction you will need to be able to decode some assembler opcodes. And, as glowcoder said, even if it would "comment out" in runtime the instructions that generates segfaults, what will be left from the original program logic (if it may be called so)?
Everything is possible, but it doesn't mean that it has to be done.
Unfortunately, you can't in this case. The buggy function has undefined behavior and could have corrupted your program's state.
What you CAN do is run the functions in a new process. If this process dies with a return code that indicates SIGSEGV, you know it has failed.
You could also rewrite the functions yourself.
I can see at case for recovering from a Segmentation Violation, if your handling events in a loop and one of these events causes a Segmentation Violation then you would only want to skip over this event, continue processing the remaining events. In my eyes Segmentation Violation are much the same as NullPointerExceptions in Java. Yes the state will be inconsistent and unknown after either of these, however in some cases you would like to handle the situation and carry on. For instance in Algo trading you would pause the execution of an order and allow a trader to manually take over, with out crashing the entire system and ruining all other orders.
the best solution is to inbox each unsafe access this way :
#include <iostream>
#include <signal.h>
#include <setjmp.h>
static jmp_buf buf;
int counter = 0;
void signal_handler(int)
{
longjmp(buf,0);
}
int main()
{
signal(SIGSEGV,signal_handler);
setjmp(buf);
if(counter++ == 0){ // if we did'nt try before
*(int*)(0x1215) = 10; // access an other process's memory
}
std::cout<<"i am alive !!"<<std::endl; // we will get into here in any case
system("pause");
return 0;
}
you program will never crash in almost all os
This glib manual gives you a clear picture of how to write signal handlers.
A signal handler is just a function that you compile together with the rest
of the program. Instead of directly invoking the function, you use signal
or sigaction to tell the operating system to call it when a signal arrives.
This is known as establishing the handler.
In your case you will have to wait for the SIGSEGV indicating a segmentation fault. The list of other signals can be found here.
Signal handlers are broadly classified into tow categories
You can have the handler function note that the signal arrived by tweaking some
global data structures, and then return normally.
You can have the handler function terminate the program or transfer
control to a point where it can recover from the situation that caused the signal.
SIGSEGV comes under program error signals

Resources