For Linux C programming, I have this handler and main method:
void handler(int number, signinfo_t, void *ignore){
printf("Signaling %d\n", si->si_pid);
}
int main(){
struct sigaction sig;
sig.sa_flags = SA_SIGINFO;
sigemptyset(&sig.sa_mask);
sig.sa_handler = handler // This line has error
If I make the handler with just 1 parameter void handler(int num)
it works fine; however, I will not be able to use si->si_pid. The warning I am getting is :
warning: assignment to __sighandler_t from an incompatible pointer type
-Wincompatible-pointer-types
sig.sa_handler = handler;
Do I make it sig.sa_action instead? I want to fix the warning
You're assigning the handler function to the wrong member of sig. The declaration of struct sigaction is:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
sig.sa_handler is a function with only one argument, the signal number. When you use the SA_SIGINFO flag, you need to assign the 3-argument function to sig.sa_sigaction instead.
int main(){
struct sigaction sig;
sig.sa_flags = SA_SIGINFO;
sigemptyset(&sig.sa_mask);
sig.sa_sigaction = handler;
Related
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.
I am currently learning about signals in C and have a small program, that is supposed to not terminate upon receiving the SIGINT signal using sigaction().
The code written below however does terminate, even though it looks fine to me. Maybe I am something missing. Does someone see, why it still terminates?
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void handle() { printf("%s%d%s", "I won't die....: ", getpid(), "\n"); }
int main() {
struct sigaction sa;
sa.sa_handler = handle;
int k = 0;
sigaction(SIGINT, &sa, NULL);
// signal(SIGINT, handle); //signal works just fine
while (k < 60) {
printf("%s", "sleeping... \n");
sleep(1);
k = k + 1;
}
}
Additional info: My OS is Windows, however I compile and execute the program in the Bash of a Linux subsystem.
Open the manual page of sigaction() and understand all the members of struct sigaction and fill all the members of struct sigaction.
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
Here
struct sigaction sa;
As pointed by #AnttiHaapala here sa is a variable of automatic storage duration and you didn't initialize its members, it invokes undefined behavior as all the other fields contain garbage except sa.sa_handler
So you need to fill the other members of struct sigaction like
sa.sa_handler = handle;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
Or initialize sa itself like
struct sigaction sa = {0};
Also it's not a good practice to write printf() statement inside signal handler, read here How to avoid using printf in a signal handler? .
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.
When sending a signal from one process to another, I also want to send a value of type long. Is that possible? I am using SIGUSR1.
Sure you can, but you'll have to send it with sigqueue(2) instead of kill(2). And you can send an int or a sival_ptr.
union sigval {
int sival_int;
void *sival_ptr;
};
Establish the handler
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = handler;
sa.sa_flags = SA_SIGINFO; /* Important. */
sigaction(SIGUSR1, &sa, NULL);
The handler for a signal established using SA_SIGINFO
static void
handler(int sig, siginfo_t *si, void *ucontext)
{
si->si_value; /* This is what you're looking for. */
}
Sending an integer
union sigval sv;
sv.sival_int = 42;
sigqueue(pid, SIGUSR1, sv);
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