Home > OS >  Segfault when passing pthread a function pointer that takes another function pointer as a parameter
Segfault when passing pthread a function pointer that takes another function pointer as a parameter

Time:06-08

I'm using bog-standard x86-64 Ubuntu gcc, and obviously there are no compile problems since I can get a segfault.

I'm trying to create a pthread that invokes a function that takes another function based on some previously determined condition. That is, I'm trying to modify the function invoked in the thread by partially applying its input function.

Code

#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <stdlib.h>
#include <stdint.h>

void * (*foo)(void*);
void * (*bar(void (*outputFun)(uint8_t a, short unsigned int b)))(void *);

void baz(u_int8_t a, short unsigned int b) {
    printf("a - b is %d - %d\n", a, b);
}

void bay(u_int8_t a, short unsigned int b) {
    printf("b - a is %d - %d\n", b, a);
}

int main() {
    srand(time(NULL));
    unsigned int random = 1   rand() % 2;
    printf("Our random number is: %d\n", random);

    foo = bar(random > 1 ? *baz : *bay);

    pthread_t thread;
    pthread_create(&thread, NULL,  foo  , NULL);
    // DO SOME STUFF
    pthread_join(thread, NULL);
}

void * (*bar(void (*outputFun)(uint8_t a, short unsigned int b)))(void *) {
    // DO OTHER STUFF
    outputFun(1, 2);
    return NULL;
}

valgrind Error Output

Our random number is: 2
a - b is 1 - 2
--15699-- REDIR: 0x4914b10 (libc.so.6:calloc) redirected to 0x483dce0 (calloc)
==15699== Thread 2:
==15699== Jump to the invalid address stated on the next line
==15699==    at 0x0: ???
==15699==    by 0x485E608: start_thread (pthread_create.c:477)
==15699==    by 0x4998132: clone (clone.S:95)
==15699==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==15699==
==15699==
==15699== Process terminating with default action of signal 11 (SIGSEGV)
==15699==  Bad permissions for mapped region at address 0x0
==15699==    at 0x0: ???
==15699==    by 0x485E608: start_thread (pthread_create.c:477)
==15699==    by 0x4998132: clone (clone.S:95)
--15699-- REDIR: 0x49136d0 (libc.so.6:free) redirected to 0x483c9d0 (free)
==15699==
==15699== HEAP SUMMARY:
==15699==     in use at exit: 272 bytes in 1 blocks
==15699==   total heap usage: 2 allocs, 1 frees, 1,296 bytes allocated
==15699==
==15699== Searching for pointers to 1 not-freed blocks
==15699== Checked 8,476,712 bytes
==15699==
==15699== LEAK SUMMARY:
==15699==    definitely lost: 0 bytes in 0 blocks
==15699==    indirectly lost: 0 bytes in 0 blocks
==15699==      possibly lost: 272 bytes in 1 blocks
==15699==    still reachable: 0 bytes in 0 blocks
==15699==         suppressed: 0 bytes in 0 blocks
==15699== Rerun with --leak-check=full to see details of leaked memory
==15699==
==15699== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==15699==
==15699== 1 errors in context 1 of 1:
==15699== Jump to the invalid address stated on the next line
==15699==    at 0x0: ???
==15699==    by 0x485E608: start_thread (pthread_create.c:477)
==15699==    by 0x4998132: clone (clone.S:95)
==15699==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==15699==
==15699== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

Fwiw, I'm a Java developer. So, I need all the help I can get, and it will be greatly appreciated. Thanks.

EDIT Apparently, I can't make C bend to my will.

CodePudding user response:

You can do what you want, just not exactly the way you want.

Some issues:

  1. With foo = bar(random > 1 ? *baz : *bay); you're trying to create a "closure" which C doesn't have
  2. You can't call a function with (e.g. *baz). You'd need baz()
  3. But, I think you just want the address of the function which is (e.g.) baz

For threads, the last argument to pthread_create is a pointer that gets passed to the thread function. You can create a struct that has all the information/arguments you require. You pass the address of that struct and the thread function can access it.


Here is a refactoring to do the equivalent in a more standard way:

#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <stdlib.h>
#include <stdint.h>

typedef void (*outputFun) (uint8_t a, short unsigned int b);

typedef struct {
    u_int8_t a;
    unsigned int b;
    outputFun foo;
} args_t;

void
baz(u_int8_t a, short unsigned int b)
{
    printf("a - b is %d - %d\n", a, b);
}

void
bay(u_int8_t a, short unsigned int b)
{
    printf("b - a is %d - %d\n", b, a);
}

void *
bar(void *vp)
{
    args_t *arg = vp;

    // DO OTHER STUFF

    arg->foo(arg->a,arg->b);

    return NULL;
}

int
main(void)
{
    srand(time(NULL));
    unsigned int random = 1   rand() % 2;

    printf("Our random number is: %d\n", random);

    args_t arg;
    arg.foo = (random > 1) ? baz : bay;
    arg.a = 23;
    arg.b = 37;

    pthread_t thread;

    pthread_create(&thread, NULL, bar, &arg);

    // DO SOME STUFF

    pthread_join(thread, NULL);

    return 0;
}
  • Related