C function segfault named Python ctypes

I am getting a very weird crash when using ctypes in Python, but I'm not sure if the problem is Python or C.

Here is the C source (at test.c

):

#include <stdio.h>

void compress(char *a, int b) {
  printf("inside\n");
}

void run() {
  printf("before\n");
  compress("hi", 2);
  printf("after\n");
}

      

Then what happens when I call run()

with ctypes:

$ python -c 'import ctypes; ctypes.cdll.LoadLibrary("./test.so").run()'
before
Segmentation fault (core dumped)

      

The strangest thing is that the crash doesn't happen when I rename compress()

to everything else.

Other things that prevent it from crashing:

  • Call compress()

    directly
  • Call to run()

    or compress()

    from C directly (if I add main()

    , compile and run)
  • Removing any argument from the signature compress()

    (but then the function doesn't seem to be executed, depending on the lack of a printable " inside

    ".

I'm new to C, so I'm guessing I'm missing something here. What could be causing this?

System info:
Python 2.7.6
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1 ~ 14.04)
Ubuntu 14.04
uname -r

: 3.13.0-58-generic

+3


source to share


2 answers


While @falsetru diagnosed the problem, his solution won't work in the general case when you have a lot of files to statically link them (because the whole point of declaring static things shouldn't be visible from other files).

And while @eryksun posted a solution, when you want to declare a function with the same name as another, in general, you might have a lot of C functions that you don't want to export, and you don't want to worry about do they come across any random function in some library that Python does to import and you don't want to prefix each of your internal functions with an attribute.

(GCC maintains documentation on function attributes , including this function visibility function.)

A more general solution to avoid namespace conflicts is to tell the linker not to export any default symbols, and then mark only the functions you want to export, such as run (), as visible.



There is probably a standard way to define a macro to do this, but my C is so outdated I don't know it. This will work anyway:

#include <stdio.h>

#define EXPORT __attribute__((visibility("protected")))

void compress(char *a, int b) {
  printf("inside\n");
}

EXPORT void run() {
  printf("before\n");
  compress("hi", 2);
  printf("after\n");
}

      

You can link and run it like this:

$ gcc -x c test.c --shared -fvisibility=hidden -o test.so
$ python -c 'import ctypes; ctypes.cdll.LoadLibrary("./test.so").run()'
before
inside
after

      

+4


source


According to debugging, the program tries to call compress

in libz.so.1

.

$ gdb python -c core
...
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `python -c import ctypes; ctypes.cdll.LoadLibrary("./test.so").run()'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007f9ddea18bff in compress2 () from /lib/x86_64-linux-gnu/libz.so.1

      

which takes different parameters ( zlib.h

):



ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
                                 const Bytef *source, uLong sourceLen));

ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
                                  const Bytef *source, uLong sourceLen,
                                  int level));
/*

      

You can change the function compress

like static

to work around the problem:

static void compress(char *a, int b)
{
    printf("inside\n");
}

      

+5


source







All Articles