Fix segfault issue

I think we need to keep a reference to the ctypes voidp object that we
pass as userdata alive
This commit is contained in:
2025-05-23 15:46:27 -04:00
parent f2fdcfdf24
commit 5971ad2ef0

View File

@@ -33,52 +33,7 @@ class WeaselJsonStatus(enum.Enum):
OVERFLOW = 3
class WeaselJsonParserBase:
def __init__(
self,
build_dir: Optional[str] = None,
stackSize: int = 1024,
) -> None:
self._lib = None
if build_dir is None:
build_dir = os.path.dirname(__file__) + "/build"
for f in (build_dir + "/" + "libweaseljson.so",):
try:
self._lib = ctypes.cdll.LoadLibrary(f)
except OSError:
print("Could not load " + f)
pass
if self._lib is None:
import sys
print(
"Could not find libweaseljson implementation",
file=sys.stderr,
)
sys.exit(1)
self._lib.WeaselJsonParser_create.argtypes = (
ctypes.c_int,
ctypes.POINTER(WeaselJsonCallbacks),
ctypes.c_void_p,
)
self._lib.WeaselJsonParser_create.restype = ctypes.c_void_p
self._lib.WeaselJsonParser_reset.argtypes = (ctypes.c_void_p,)
self._lib.WeaselJsonParser_destroy.argtypes = (ctypes.c_void_p,)
self._lib.WeaselJsonParser_parse.argtypes = (
ctypes.c_void_p,
ctypes.c_void_p,
ctypes.c_int,
)
self._lib.WeaselJsonParser_parse.restype = WeaselJsonStatus
self.p = self._lib.WeaselJsonParser_create(
stackSize,
callbacks,
ctypes.cast(ctypes.pointer(ctypes.py_object(self)), ctypes.c_void_p),
)
class WeaselJsonCallbacksBase:
def on_begin_object(self):
pass
@@ -118,6 +73,57 @@ class WeaselJsonParserBase:
def on_null_literal(self):
pass
class WeaselJsonParser:
def __init__(
self,
callbacks: WeaselJsonCallbacksBase,
build_dir: Optional[str] = None,
stackSize: int = 1024,
) -> None:
self._lib = None
if build_dir is None:
build_dir = os.path.dirname(__file__) + "/build"
for f in (build_dir + "/" + "libweaseljson.so",):
try:
self._lib = ctypes.cdll.LoadLibrary(f)
except OSError:
print("Could not load " + f)
pass
if self._lib is None:
import sys
print(
"Could not find libweaseljson implementation",
file=sys.stderr,
)
sys.exit(1)
self._lib.WeaselJsonParser_create.argtypes = (
ctypes.c_int,
ctypes.POINTER(WeaselJsonCallbacks),
ctypes.c_void_p,
)
self._lib.WeaselJsonParser_create.restype = ctypes.c_void_p
self._lib.WeaselJsonParser_reset.argtypes = (ctypes.c_void_p,)
self._lib.WeaselJsonParser_destroy.argtypes = (ctypes.c_void_p,)
self._lib.WeaselJsonParser_parse.argtypes = (
ctypes.c_void_p,
ctypes.c_void_p,
ctypes.c_int,
)
self._lib.WeaselJsonParser_parse.restype = WeaselJsonStatus
self.voidp_callbacks = ctypes.cast(
ctypes.pointer(ctypes.py_object(callbacks)), ctypes.c_void_p
)
self.p = self._lib.WeaselJsonParser_create(
stackSize,
c_callbacks,
self.voidp_callbacks,
)
def parse(self, data: bytes) -> WeaselJsonStatus:
buf = (ctypes.c_ubyte * len(data)).from_buffer(bytearray(data))
return self._lib.WeaselJsonParser_parse(self.p, buf, len(data))
@@ -215,7 +221,7 @@ def on_null_literal(p):
self.on_null_literal()
callbacks = WeaselJsonCallbacks(
c_callbacks = WeaselJsonCallbacks(
on_begin_object,
on_end_object,
on_begin_string,
@@ -232,13 +238,13 @@ callbacks = WeaselJsonCallbacks(
)
class JsonParser(WeaselJsonParserBase):
class MyCallbacks(WeaselJsonCallbacksBase):
# override callbacks
def on_string_data(self, data):
print(data)
with JsonParser() as parser:
with WeaselJsonParser(MyCallbacks()) as parser:
raw = json.dumps({"hello": "world", "foo": 42}).encode()
i = 0
stride = 1