Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I ignore SIGSEGV signal?

Tags:

Here is my code,

#include<signal.h> #include<stdio.h>  int main(int argc,char ** argv)    {      char *p=NULL;      signal(SIGSEGV,SIG_IGN); //Ignoring the Signal      printf("%d",*p);      printf("Stack Overflow"); //This has to be printed. Right?    return 0;     } 

While executing the code, i'm getting segmentation fault. I ignored the signal using SIG_IGN. So I shouldn't get Segmentation fault. Right? Then, the printf() statement after printing '*p' value must executed too. Right?

like image 696
Dinesh Avatar asked Dec 10 '11 11:12

Dinesh


People also ask

Can I ignore SIGSEGV?

SIGSEGV means the guest Java or Javascript code took an array out-of-bounds exception, not that the JVM itself is buggy. But yes, outside of planned cases like this, it's a bug and should not be ignored.

What is signal SIGSEGV?

On a Unix operating system such as Linux, a "segmentation violation" (also known as "signal 11", "SIGSEGV", "segmentation fault" or, abbreviated, "sig11" or "segfault") is a signal sent by the kernel to a process when the system has detected that the process was attempting to access a memory address that does not ...

What does it mean when a program receives a SIGSEGV?

1) Segmentation Fault (also known as SIGSEGV and is usually signal 11) occur when the program tries to write/read outside the memory allocated for it or when writing memory which can only be read.In other words when the program tries to access the memory to which it doesn't have access to.

Why is my code not catching SIGSEGV?

Your code is ignoring SIGSEGV instead of catching it. Recall that the instruction that triggered the signal is restarted after handling the signal. In your case, handling the signal didn't change anything so the next time round the offending instruction is tried, it fails the same way. You should probably also use sigaction () instead of signal ().

Is it possible to ignore a SIGSEGV?

You can ignore the signal but you have to do something about it. I believe what you are doing in the code posted (ignoring SIGSEGV via SIG_IGN) won't work at all for reasons which will become obvious after reading the bold bullet. When you do something that causes the kernel to send you a SIGSEGV:

What is segmentation fault (SIGSEGV)?

1) Segmentation Fault (also known as SIGSEGV and is usually signal 11) occur when the program tries to write/read outside the memory allocated for it or when writing memory which can only be read.In other words when the program tries to access the memory to which it doesn’t have access to. SIGSEGV is abbreviation for “Segmentation Violation”.

What happens when a SIGSEGV occurs?

This includes a SIGSEGV when executing in VM code, JNI code, or native code. In these cases the signal is unexpected, so fatal error handling is invoked to create the error log and terminate the process.


2 Answers

Your code is ignoring SIGSEGV instead of catching it. Recall that the instruction that triggered the signal is restarted after handling the signal. In your case, handling the signal didn't change anything so the next time round the offending instruction is tried, it fails the same way.

If you intend to catch the signal change this

signal(SIGSEGV, SIG_IGN); 

to this

signal(SIGSEGV, sighandler); 

You should probably also use sigaction() instead of signal(). See relevant man pages.

In your case the offending instruction is the one which tries to dereference the NULL pointer.

printf("%d", *p); 

What follows is entirely dependent on your platform.

You can use gdb to establish what particular assembly instruction triggers the signal. If your platform is anything like mine, you'll find the instruction is

movl    (%rax), %esi 

with rax register holding value 0, i.e. NULL. One (non-portable!) way to fix this in your signal handler is to use the third argument signal your handler gets, i.e. the user context. Here is an example:

#include <signal.h> #include <stdio.h>  #define __USE_GNU #include <ucontext.h>  int *p = NULL; int n = 100;  void sighandler(int signo, siginfo_t *si, ucontext_t* context) {   printf("Handler executed for signal %d\n", signo);   context->uc_mcontext.gregs[REG_RAX] = &n; }  int main(int argc,char ** argv) {   signal(SIGSEGV, sighandler);   printf("%d\n", *p); // ... movl (%rax), %esi ...   return 0; } 

This program displays:

Handler executed for signal 11 100 

It first causes the handler to be executed by attempting to dereference a NULL address. Then the handler fixes the issue by setting rax to the address of variable n. Once the handler returns the system retries the offending instruction and this time succeeds. printf() receives 100 as its second argument.

I strongly recommend against using such non-portable solutions in your programs, though.

like image 117
Adam Zalcman Avatar answered Dec 16 '22 17:12

Adam Zalcman


You can ignore the signal but you have to do something about it. I believe what you are doing in the code posted (ignoring SIGSEGV via SIG_IGN) won't work at all for reasons which will become obvious after reading the bold bullet.

When you do something that causes the kernel to send you a SIGSEGV:

  • If you don't have a signal handler, the kernel kills the process and that's that
  • If you do have a signal handler
    • Your handler gets called
    • The kernel restarts the offending operation

So if you don't do anything abut it, it will just loop continuously. If you do catch SIGSEGV and you don't exit, thereby interfering with the normal flow, you must:

  • fix things such that the offending operation doesn't restart or
  • fix the memory layout such that what was offending will be ok on the next run
like image 23
cnicutar Avatar answered Dec 16 '22 16:12

cnicutar