Dmitry Dmitry - 3 months ago 19
C Question

signal's "siginfo_t* info" causes segmentation fault

I am making a program containing a "Server.c" which waits a client to send it a SIGUSR1 msg 10 times, then dies, and a "client.c" which sends a SIGUSR1 msg to the server.

The problem is that if I try to access the siginfo_t* info, I get a segmentation fault.

Note that this is being tested on a Debian ssh server on which I do not have high permissions.
Node that this code works fine on Ubuntu.

Can siginfo_t *info fail due to permission issues? Or is there another issue causing this portability problem. As far as I know libc should be fairly standard throughout any linux distro, possibly unix.

Any Ideas?

Thanks

server.c

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

int counter = 0;
pid_t *clients = 0;

void on_signal(int signo, siginfo_t *info, void * context)
{
puts("SIGNAL RECEIVED");
assert(clients);
clients[counter] = info->si_pid;
++counter;
}

int main()
{
struct sigaction action;
sigset_t set;
int recieveflag = 0;

clients = (pid_t*)malloc(10 * sizeof(pid_t));

sigemptyset(&set);
sigaddset(&set, SA_SIGINFO);

memset(&action, 0, sizeof(struct sigaction));
action.sa_sigaction = on_signal;
sigaction(SIGUSR1, &action, 0);

while (counter < 10) {
//sigprocmask(SIG_BLOCK, &set, 0);
sigsuspend(&set);
}

puts("I'm done!");

return 0;
}


client.c:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

int main(int argc, const char** argv)
{
int server_id;

assert(argc == 2);

server_id = atoi(argv[1]);
assert(server_id > 0);

kill(server_id, SIGUSR1);

return 0;
}


I tried editing server.c to:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

int counter = 0;
pid_t *clients = 0;

void on_signal(int sig)
{
puts("SIGNAL RECEIVED");
}

int main()
{
struct sigaction action;
sigset_t set;
int recieveflag = 0;

clients = (pid_t*)malloc(10 * sizeof(pid_t));

sigemptyset(&set);
sigaddset(&set, SIGUSR1);

memset(&action, 0, sizeof(struct sigaction));
action.sa_flags = SA_SIGINFO;
action.sa_handler = on_signal;
sigaction(SIGUSR1, &action, 0);

while (counter < 10) {
sigprocmask(SIG_BLOCK, &set, 0);
sigsuspend(&set);
++counter;
}

puts("I'm done!");

return 0;
}


now it no longer receives the SIGUSR1 event at all.

Answer

The basic behavior of sigaction is to call a simple callback like : void (*sa_handler)(int);. So if you want to use the sigaction handle with 3 parameters void (*sa_sigaction)(int, siginfo_t *, void *);, you must set the sa_flags field of your struct sigaction with the flag SA_SIGINFO. Take a look of the man page : http://www.kernel.org/doc/man-pages/online/pages/man2/sigaction.2.html who is clear.

Comments