I'm running into a curious segfault when trying to interface to a library using Python CTypes. I'm running Python 3.4.0-0ubuntu2 on Kubuntu Trusty 64 bit.
The segfault occurs when I use 4 anonymous struct
s within a union
but not when I use 3 or less, which is most curious. It also occurs only when I try to return
a union
back to Python in fn2
but not when I just send it from Python in fn1
.
The code with 3 struct
s which does not segfault:
lib.c:
#include <stdio.h>
typedef union {
int data[3];
struct { int r, g, b; };
struct { int x, y, z; };
struct { int l, a, B; }; // cap B to silence error
} Triplet;
void fn1(Triplet t)
{
fprintf(stderr, "%d, %d, %d\n", t.r, t.g, t.b);
}
Triplet fn2(Triplet t)
{
Triplet temp = {{t.r + 1, t.g + 1, t.b + 1}};
return temp;
}
main.py:
from ctypes import *
def _makeFields(s):
return tuple([(c, c_int) for c in s])
Array3 = c_int * 3
class _RGB(Structure): _fields_ = _makeFields("rgb")
class _XYZ(Structure): _fields_ = _makeFields("xyz")
class _LAB(Structure): _fields_ = _makeFields("laB") # cap B to silence error
class Triplet(Union):
_anonymous_ = ["rgb", "xyz", "laB"]
_fields_ = [("data", Array3),
("rgb", _RGB),
("xyz", _XYZ),
("laB", _LAB)]
_lib = CDLL("libuniontest.so")
_lib.fn1.argtypes = [Triplet]
_lib.fn2.restype = Triplet
_lib.fn2.argtypes = [Triplet]
t = Triplet(Array3(99, 129, 39))
_lib.fn1(t)
tt = _lib.fn2(t)
print(tuple(tt.data))
Makefile:
test:
$(CC) -fPIC -shared -o libuniontest.so lib.c
sudo cp libuniontest.so /usr/local/lib/
sudo ldconfig
python3 main.py
Decreasing the number of struct
members also is not a problem. (Totally removing the struct
members leads to another problem, though.) Now to demonstrate the segfault just add one more anonymous struct
:
in lib.c:
typedef union {
int data[3];
struct { int r, g, b; };
struct { int x, y, z; };
struct { int l, a, B; }; // cap B to silence error
struct { int L, c, h; }; // cap L to silence error
} Triplet;
in main.py:
class _RGB(Structure): _fields_ = _makeFields("rgb")
class _XYZ(Structure): _fields_ = _makeFields("xyz")
class _LAB(Structure): _fields_ = _makeFields("laB") # cap B to silence error
class _LCH(Structure): _fields_ = _makeFields("Lch") # cap L to silence error
class Triplet(Union):
_anonymous_ = ["rgb", "xyz", "laB", "Lch"]
_fields_ = [("data", Array3),
("rgb", _RGB),
("xyz", _XYZ),
("laB", _LAB),
("Lch", _LCH)]
What is the reason for this segfault and how can I fix it? Thanks.