I'm trying to use an exception handler to catch bad memory access but I'm not entirely sure how to go about doing it. I tried registering it with sigaction but my handler isn't triggering..
Old code
#include <stdio.h>
#include <signal.h>
void handler(int sig)
{
//exception should land here
printf("caught exception");
}
int main(int argc, const char * argv[]) {
struct sigaction act;
act.sa_flags = SA_SIGINFO;
sigemptyset(&act.sa_mask);
act.sa_handler = handler;
if(sigaction(SIGSEGV, &act, NULL)==-1){
printf("Could not register handler");
}else{
printf("handler registered\n");
}
*(int*)0 = 0;//throw exception
return 0;
}
And once inside the handler, how can I read the thread context registers?
I'm also on a MacOS so I'm unsure if there's any OS specific implementations.
Edit: New Code
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#define _XOPEN_SOURCE 600
#include <ucontext.h>
void handler(int sig, siginfo_t *info, void *uc)
{
(void) sig;
write (STDOUT_FILENO, "Caught exception\n", 17);
struct ucontext* mc = (struct ucontext*)uc;
}
int main(int argc, const char * argv[]) {
struct sigaction act;
act.sa_flags = SA_SIGINFO;
sigemptyset(&act.sa_mask);
act.sa_handler = handler;
if(sigaction(SIGSEGV, &act, NULL)==-1){
printf("Could not register handler");
}else{
printf("handler registered\n");
}
raise (SIGSEGV);
return 0;
}
When I included ucontext.h my compiler through this error
#else /* !_XOPEN_SOURCE */
#error The deprecated ucontext routines require _XOPEN_SOURCE to be defined
#endif /* _XOPEN_SOURCE */
Which I resolved by defining _XOPEN_SOURCE
But the compiler still doesn't know what ucontext is because I'm not getting any intellisence.. I might have to define the structure myself
Edit: Since I was on M1 I was compiling form ARM instead of x86_64 and ucontext and mcontext both have to use the 64bit variants..
Undefined behavior is not reliable:
Instead of relying on it, send a signal to the calling process with raise():
raise (SIGSEGV);
So the code becomes:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
static void func (int signo, siginfo_t *info, void *context);
{
write (STDOUT_FILENO, "Caught exception\n", 17);
/* Restores the default handler. This is the only
* portable use of signal().
*/
signal (sig, SIG_DFL);
raise (sig);
}
int main (int argc, char *argv[])
{
struct sigaction act;
act.sa_flags = SA_SIGINFO;
/* Upon successful completion, sigemptyset() shall return 0;
* otherwise, it shall return -1 and set errno to indicate the error.
*/
if (sigemptyset (&act.sa_mask) == -1) {
perror ("sigemptyset()");
return EXIT_FAILURE;
}
act.sa_sigaction = handler;
if (sigaction (SIGSEGV, &act, NULL) == -1) {
fprintf (stderr, "Could not register handler\n");
} else {
fprintf (stderr, "handler registered\n");
}
raise (SIGSEGV);
return EXIT_SUCCESS;
}
Output:
handler registered
caught exception
Print error messages to stderr:
//printf ("Could not register handler\n");
fprintf (stderr, "Could not register handler.\n");
Do not call async-signal-unsafe functions in signal handlers:
Neither the C standard, nor the POSIX standard specifies printf() to be async-signal-safe, which means that it can not be safely called inside a signal handler.
Though,the POSIX standard does specify write() to be async-signal safe. So printf() should be replaced with it.
// printf ("Caught exception\n");
write (STDOUT_FILENO, "Caught exception\n", 17);
Incorrect declaration of handler():
void handler(int sig) is not correct if SA_SIGINFO is set: "If SA_SIGINFO is set and the signal is caught, the signal-catching function shall be entered as: void func(int signo, siginfo_t *info, void *context);" - #AndrewHenle
//void func (int signo);
void func(int signo, siginfo_t *info, void *context);
Assign handler() to the correct member:
The sigaction structure is defined as something like:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
When you use the SA_SIGINFO flag, you need to assign the signal handling function to .sa_sigaction instead of .sa_handler.
// act.sa_handler = handler;
sig.sa_sigaction = handler;
Your first question appears to have been answered so I won't get further into it. As for your second issue, Apple has its own definition of mcontext and ucontext specifically mcontext64 and ucontex64. Additionally, You're compiling for ARM64 instead of x86_64, hence why those registers would no longer exist in your compiled binary.
Go into your Build Settings->Architectures
Remove the standard architecture and replace it with x86_64, your handler should then be able to access the registers.
Related
If I use the pthread_create() call in an infinite while loop in main, does it create multiple threads each time or will it only create the 2 threads that I need?
while(1){
pthread_create(&thread_1...);
pthread_create(&thread_2...);
}
it creates multiple threads each time.
you can use pthread_cancel to cancel any thread from the process.
Below is one of many ways to handle the termination of thread upon some event/timeout etc..
#include <stdio.h>
#include <signal.h> // for sigaction
#include <stdlib.h> // for exit and
#include <pthread.h> // for pthread
#include <string.h> // for memset
#define TIMEOUT 10
pthread_t tid1, tid2;
void* thread_function1(void *arg)
{
while(1)
{
printf(" thread_function1 invoked\n");
sleep(1); //avoid heavy prints
}
}
void* thread_function2(void *arg)
{
while(1)
{
printf(" thread_function2 invoked\n");
sleep(1); //avoid heavy prints
}
}
static void timer_handler(int sig, siginfo_t *siginfo, void *context)
{
printf("Inside handler function timeout happened \n");
if( sig == SIGALRM)
{
pthread_cancel(tid1);
pthread_cancel(tid2);
//exit(0); to exit from main
}
}
int main()
{
int count = 0;
void *status;
struct sigaction act;
memset (&act, '\0', sizeof(act));
sigemptyset(&act.sa_mask);
/* Use the sa_sigaction field because the handles has two additional parameters */
act.sa_sigaction = timer_handler;
/* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGALRM, &act, NULL) < 0)
{
perror ("sigaction SIGALRM");
return 1;
}
alarm (TIMEOUT);
pthread_create(&tid1,NULL,thread_function1,NULL);
pthread_create(&tid2,NULL,thread_function2,NULL);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
printf(" MIAN ENDS ...BYE BYE \n");
return 0;
}
This is not a question about code but theory.
I had this code before:
void handler(int signal){
printf("Handler called\n");
}
struct sigaction act;
act.sa_handler = &handler;
act.sa_flags = 0;
if (sigaction(SIGINT, &act, NULL) < 0){
exit(1);
}
if (sigaction(SIGQUIT, &act, NULL) < 0){
exit(1);
}
When I was pressing ctrl + C, the handler was being called, but the program still exits.
And now, by curiosity, I tried changing the flags to SA_RESTART. Now it does not exit.
Why?
SA_RESTART causes EINTR-interruptible system calls (e.g., read) to be restarted after a handled signal is delivered.
So if you had:
#include <unistd.h>
#include <signal.h>
#include <errno.h>
void handler(int signal)
{
printf("Handler called\n");
}
int main()
{
struct sigaction act;
act.sa_handler = &handler;
act.sa_flags = 0;
if (sigaction(SIGINT, &act, NULL) < 0){ exit(1); }
char ch; ssize_t nr;
nr=read(0,&ch,1);
}
then with SA_RESTART it'll be as if the nr=read(0,&ch,1); line had been replaced with
while(0>(nr=read(0,&ch,1)) && errno==EINTR){}`
Note that you should be calling only async-signal-safe functions in signal handlers. printf in a handler is normally a recipe for undefined behavior, though in this particular case where you're only interrupting code that is async-signal-safe itself (read), it is fairly safe, though the POSIX doesn't explicitly sanction it (AFAIK).
I have a simple code which uses two signal handlers for "Segmentation fault" signal. First one works when signal happens and after longjmp, I do reassigning of handler with second one for that signal. Unfortunately, the flow of code doesn't reach necessary handler and I still get "Segmentation fault".
#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
int i;
int ci;
jmp_buf m_env_buffer;
jmp_buf max_env_buffer;
void handler(int signum){
printf("sigsegv on i:[%d]", i);
ci = (++i);
longjmp(m_env_buffer,1);
}
void top_handler(int signum){
printf("sigsegv on max i:[%d]", i);
longjmp(max_env_buffer,10);
}
int main(void) {
signal(SIGSEGV, handler);
char * pstart = "loremipsum";
int m_cell = 0;
char m_cell_v;
int point;
point = setjmp(m_env_buffer);
if(point == 0){
for(i=0; ;i--){
m_cell_v = pstart[i];
}
}
//this wasn't invoked
signal(SIGSEGV, top_handler);
point = setjmp(max_env_buffer);
if(point == 0){
for(i=ci; ;i++){
char cur = pstart[i];
if(cur==10)
printf("\n");
printf("%c",cur);
}
}
puts("finish");
return 0;
}
signal() should not be used. It has unreliable semantics. On your system the default action (termination) is performed when the second SIGSEGV is received. The second call to signal() has effectively no effect.
You should use sigaction() instead. In your case you can use the following function instead of signal():
void set_signal (int signum, void (*handler)(int))
{
struct sigaction act;
act.sa_handler = handler;
sigemptyset (&act.sa_mask);
act.sa_flags = SA_NODEFER;
act.sa_restorer = NULL;
sigaction (signum, &act, NULL);
}
In the future, read the documentation at your disposal. A good ressource is the glibc manual. It has a good chapter on signal handling.
This question already has answers here:
Meaning of "referencing" and "dereferencing" in C
(7 answers)
Closed 5 years ago.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
void handler (int sig)
{
printf ("Got signal %d\n", sig);
}
int main (int argc, char *argv[])
{
struct sigaction act;
memset (&act, '\0', sizeof(act));
// Use the sa_sigaction field because
// the handler has two additional parameters
act.sa_handler = &handler;
if (sigaction(SIGHUP, &act, NULL) < 0) {
perror ("sigaction");
return EXIT_FAILURE;
}
if (sigaction(SIGTERM, &act, NULL) < 0) {
perror ("sigaction");
return EXIT_FAILURE;
}
while (1) sleep (10);
return EXIT_SUCCESS;
}
I am a bit confused about "&handler" . What does it mean here? I am new to signal and really hope someone can give me a hint on how it works. Any help would be appreciated. Thx
Man page of SIGACTION :
The sigaction structure is defined as something like:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
[...]
`sa_handler` specifies the action to be associated with signum and may
be SIG_DFL for the default action, SIG_IGN to ignore this signal, or
a pointer to a signal handling function. This function receives the
signal number as its only argument.
[...]
Here, sa_handler is a pointer to a function and hold the address of handler() function.
As mentioned here,
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
The sa_handler is a function pointer that must point to a signal handling function.
sa_handler specifies the action to be associated with signum and may
be SIG_DFL for the default action, SIG_IGN to ignore this signal, or
a pointer to a signal handling function. This function receives the
signal number as its only argument.
I have a program where i invoke a signal sigkill(getpid(), SIGUSR1). I wish when the signal comes, instead of the signal handler the thread function should be invoked, or both.
For this i have populated the sigev_notify with SIGEV_THREAD.
But unfortunately, the thread function is not called. Why is it so?
Here is the code below:
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
static void ThreadhandlerTimer1(int);
void sig_handlerTimer1(int);
static void threadFunction(union sigval sv) // Should be invoked on receipt of signal "SIGEV_THREAD"
{
printf("Thread function invoked");
}
int main()
{
int i;
static struct sigaction sa;
static struct sigevent sevp;
memset (&sevp, 0, sizeof (struct sigevent));
sevp.sigev_value.sival_ptr = NULL;
sevp.sigev_notify = SIGEV_THREAD;
sevp.sigev_notify_attributes = NULL;
sevp.sigev_signo = SIGUSR1;
sevp.sigev_notify_function=threadFunction;
/* Setting the signal handlers */
sa.sa_handler = sig_handlerTimer1;
sa.sa_flags = 0;
sigaction(SIGUSR1, &sa, NULL);
for(i=0; i<10; i++)
{
if((i==3) || (i==6)){
kill(getpid(), SIGUSR1);
}
printf("%d\n",i);
sleep(1);
}
}
void sig_handlerTimer1(int signum)
{
printf("Caught signal: %d\n",signum);
}
According to this documentation, the sigevent structure is only supported by "Some signal-generating functions, such as high-resolution timer expiration, asynchronous I/O completion, interprocess message arrival, and the sigqueue() function."
I don't know what your real plan for this code is (maybe you can tell us), but as it is, you are raising the signal directly which probably is not one of the supported cases for using SIGEV. If this code is fairly close to what you want in production you could simply call sigqueue() instead of kill() and it may just work.
From your code, it seems you have just assigned values to sigevent, instead of using any where in code.
static struct sigevent sevp;
memset (&sevp, 0, sizeof (struct sigevent));
sevp.sigev_value.sival_ptr = NULL;
sevp.sigev_notify = SIGEV_THREAD;
sevp.sigev_notify_attributes = NULL;
sevp.sigev_signo = SIGUSR1;
sevp.sigev_notify_function=threadFunction;
To invoke threadFunction, call this from your signal handler.
> void sig_handlerTimer1(int signum)
> {
> printf("Caught signal: %d\n",signum);
> threadFunction(signum);
> }
If you want to use sevp, use something like timer_create() and timer_settime().
Check this link:
http://ptgmedia.pearsoncmg.com/images/0201633922/sourcecode/sigev_thread.c