Justin Bell
Justin Bell

Reputation: 810

C - Higher Order Function

Signal takes a callback function as one of its arguments. To have variable behaviour I want to create a function within a function. This is my attempt so far:

typedef void (*sighandler_t)(int);
sighandler_t f(int pid) {
    void sigintHandler(int sig) {
        printf("Process %d", pid);
    }
    return sigintHandler
}

int main(void) {
    ...
    if (signal(SIGTSTP, *f(1)) == SIG_ERR) {
        ...
    }
    ...
}

But, every time I send a SIGTSTP (Ctrl-z), I get a seg fault.


As a sidenote: any tips on how to debug seg faults in general would be really appreciated!

Upvotes: 2

Views: 524

Answers (2)

txtechhelp
txtechhelp

Reputation: 6777

Your code compiles because it's syntactically correct and you're using compiler extensions; however, there are some fundamental issues with your code that might be leading to your segfault.

First, your signal handler code:

typedef void (*sighandler_t)(int);
sighandler_t f(int pid) {
    void sigintHandler(int sig) {
        printf("Process %d", pid);
    }
    return sigintHandler;
}

This is not standard C and even requires the -ftrampolines flag be specified on some versions of gcc to actually compile.

Your signal handler function itself has a few issues that need to be resolved:

sigintHandler is a nested function, thus when your signal handler function f returns by return sigintHandler;, you're returning a function pointer.

In your code, this compiles correctly because you have typedef void (*sighandler_t)(int);, which defines a function pointer type that can point to functions that have a void return type and take an int as a parameter, which your sigintHandler is defined as.

Instead, your signal handler function could be written simply as:

void sigintHandler(int sig) {
    printf("Signal %d\n", sig);
}

In your main function, you have the following:

if (signal(SIGTSTP, *f(1)) == SIG_ERR) {
    // ....    
}

Here it should be noted this as well has some issues. First, the signal function takes as its first parameter the signal number (usually a macro defined in the signal.h header) and as it's second argument a pointer to a function defined as void func_name(int sig).

To this, you are calling the function instead of passing it as a pointer.

*f(1) actually makes a call to f passing 1 as its parameter; instead, you would change it to the following:

if (signal(SIGTSTP, f) == SIG_ERR) {
    // ....    
}

But this should emit a warning/error since f is defined as returning a function pointer instead of void.

So to change the code to be compliant, you could just do the following:

#include <stdio.h>
#include <signal.h>

void sigintHandler(int sig) {
    printf("Signal %d", sig);
}

int main(void) {
    // ...
    if (signal(SIGTSTP, sigintHandler) == SIG_ERR) {
        // ...
    }
    // ...
    return 0;
}

You stated however:

To have variable behaviour ...

This depends on what kind of variable nature you're intending, but if it's variable functions based on the signal, you can do something like the following:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void sig_stop(int sig) {
    printf("Process %d stop\n", getpid());
}

void sig_int(int sig) {
    printf("Process %d interrupt\n", getpid());
}

int main(void) {
    // ...
    if (signal(SIGTSTP, sig_stop) == SIG_ERR) {
        // ...
    }
    if (signal(SIGINT, sig_int) == SIG_ERR) {
        // ...
    }
    // ...
    return 0;
}

Or you could use a switch statement:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void sigHandler(int sig) {
    printf("Process %d received %d\n", getpid(), sig);
    switch (sig) {
        case SIGTSTP:
            // do stop code
            break;
        case SIGINT:
            // do interupt code
            break;
    }
}

int main(void) {
    // ...
    if (signal(SIGTSTP, sigHandler) == SIG_ERR) {
        // ...
    }
    if (signal(SIGINT, sigHandler) == SIG_ERR) {
        // ...
    }
    // ...
    return 0;
}

any tips on how to debug seg faults in general would be really appreciated!

First, understand what a segmentation fault is; then you can use a debugger like gdb to step through your code or inspect crash dumps to see where specifically the segfault is happening.

Hope that can help.

Upvotes: 2

Tomer W
Tomer W

Reputation: 3443

aint sure about what you are asking, but i can help you understand your segmentation fault.

when you call a function there are several things that are done.

  1. push function arguments to stack
  2. push return address to stack
  3. jump to function address
  4. function body
  5. pop return address from stack
  6. pop function arguments from stack.

when 1,2, 6 are done by the Calling scope.

As you know, signal is a void arguments hence the call (1) would push 0 arguments to the stack.

while the return (6) would pop your "unexistant" int from the stack and corrupt it.

somewhat solution

you can't have signal function with parameters,
what you can is:

  1. you can read your global variables within the signal function. and therefore read the current state of the program.

  2. you can sys_call to get your process_id, thread_id.

  3. i wouldn't recommend but you can read your stack further to the previous scope and get it's local variables. With BIG Note that it won't be the function you set the signal at... but the function that was running at the moment of the signal.

Upvotes: -1

Related Questions