为什么分段错误?

时间:2011-05-09 13:20:04

标签: c++ linux timer segmentation-fault signals

我有这个程序,知道它为什么会出现分段错误吗?

#include <stdlib.h>
#include <ctime>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <dlfcn.h>

#define LT_SIGACTION (*lt_sigaction) // For handle to actual sigaction in libc

static int (*lt_sigaction)(int, const struct sigaction*, struct sigaction*); // For sigaction wrapper
static void sig_handlerTimer1(int,siginfo_t*,void*);
timer_t timerid;

int main()
{
    int i;
    static struct sigaction sa;

    static struct sigevent sevp;  // argument to timer_create
    static struct itimerspec its; // argument to timer_gettime

    if(!lt_sigaction) {
        lt_sigaction = (int(*)(int, const struct sigaction*, struct sigaction*)) dlsym(RTLD_NEXT, "sigaction");
        if (!lt_sigaction) {
            fprintf(stderr, "Could not resolve 'sigaction' in 'libc.so': %s\n", dlerror());
            exit(1);
        }
    }

    memset (&sevp, 0, sizeof (struct sigevent));
    sevp.sigev_value.sival_ptr = &timerid;
    sevp.sigev_notify = SIGEV_SIGNAL;
    sevp.sigev_notify_attributes = NULL;
    sevp.sigev_signo = SIGUSR1;

    /* Setting timer interval */
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = 0;

    /* Setting timer expiration */
    its.it_value.tv_sec = 2;  // First expiry after 1 sec
    its.it_value.tv_nsec = 0;

    /* Setting the signal handlers before invoking timer*/
    sa.sa_sigaction = sig_handlerTimer1;
    sa.sa_flags = 0;
    LT_SIGACTION(SIGUSR1, &sa, NULL);
    // Even sigaction(SIGUSR1, &sa, NULL); gives SEGV
    if (timer_create(CLOCK_REALTIME, &sevp, &timerid) == -1)
    {
        fprintf(stderr, "LeakTracer (timer_trackStartTime): timer_create failed to create timer. " \
                "Leak measurement will be for entire duration of the execution period:%s \n", strerror(errno));
        return 0;

    }

    if (timer_settime(timerid, 0, &its, NULL) == -1)
    {
        fprintf(stderr, "LeakTracer (timer_trackStartTime): timer_settime failed to set the timer. " \
                "Leak measurement will be for entire duration of execution period:%s \n", strerror(errno));
        return 0;

    }

    for(i=0; i<10; i++)
    {
        printf("%d\n",i);
        sleep(1);
    }
}

void sig_handlerTimer1(int signum,siginfo_t* sf, void* au)
{
    if(sf==NULL)
    {
        printf("sf is NULL\n");
        exit(1);
    }
    if((sf->si_value.sival_ptr)!=&timerid) //SEGV received here
    {
        printf("Stray signal\n");
    }
    else {
        int flag = 1;
        printf("Caught signal: %d\n",signum);
        if (timer_delete(timerid) < 0)
        {
            fprintf(stderr, "timer deletion failed. " \
                    "This may result in some memory leaks (sig_handlerTimer1):%s \n", strerror(errno));
        }
    }
}

以下是GDB回溯:

enter code here
Program received signal SIGUSR1, User defined signal 1.
0x00e52402 in __kernel_vsyscall ()

(gdb) s

Single stepping until exit from function __kernel_vsyscall, 

which has no line number information.
sig_handlerTimer1 (signum=10, sf=0x33, au=0x0) at signalTimer.cc:73
73      void sig_handlerTimer1(int signum,siginfo_t* sf, void* au)

(gdb) s


Breakpoint 1, sig_handlerTimer1 (signum=10, sf=0x33, au=0x0) at signalTimer.cc:75
75              if(sf==NULL)
(gdb) s

80              if((sf->si_value.sival_ptr)!=&timerid)

(gdb) s

Program received signal SIGSEGV, Segmentation fault.

0x08048a9f in sig_handlerTimer1 (signum=10, sf=0x33, au=0x0) at signalTimer.cc:80

80              if((sf->si_value.sival_ptr)!=&timerid)

(gdb) bt
#0  0x08048a9f in sig_handlerTimer1 (signum=10, sf=0x33, au=0x0) at signalTimer.cc:80
#1  <signal handler called>
#2  0x00e52402 in __kernel_vsyscall ()
#3  0x00724970 in __nanosleep_nocancel () from /lib/libc.so.6
#4  0x007247bf in sleep () from /lib/libc.so.6
#5  0x08048a5a in main () at signalTimer.cc:69

(gdb) q
The program is running.  Exit anyway? (y or n) y 

这是一个C ++代码,使用g ++编译,虽然与C的差别很小

1 个答案:

答案 0 :(得分:6)

sigaction手册页中,您应该定义SA_SIGINFO标志:

sa.sa_flags = SA_SIGINFO;

否则,它不是用3个args调用你的函数。不确定lt_sigaction在使用方面是否有任何差异。