Python bindings do not check for failed parser creation, causing segfaults #23

Closed
opened 2026-06-21 17:24:04 +00:00 by weaselbot · 0 comments
Member

The Python WeaselJsonParser class does not check the return value of WeaselJsonParser_create, so any stack size that causes the C constructor to return NULL leaves the wrapper holding a NULL parser pointer. Calling parse()/reset() on that wrapper immediately dereferences the null pointer and crashes the interpreter.

Affected file: weaseljson.py

  • Lines 114–120: self.p = self._lib.WeaselJsonParser_create(...) is stored without validation.
  • Lines 122–123: parse() uses self.p unchecked.
  • Line 125: reset() also uses self.p unchecked.
  • Lines 132–135: close() does check self.p is not None, but only after creation has already stored NULL.

Reproduction:

import weaseljson

class R(weaseljson.WeaselJsonCallbacksBase):
    pass

parser = weaseljson.WeaselJsonParser(R(), stackSize=-1)  # C API returns NULL
parser.parse(b"{}")  # segfault

Also crashes with stackSize=0, stackSize=1, or stackSize=2, because WeaselJsonParser_create rejects non-positive and too-small stacks (tested in src/test.cpp around the "create rejects too-small stack" case).

Expected behavior:
WeaselJsonParser.__init__ should raise a clear Python exception (e.g. ValueError or MemoryError) when WeaselJsonParser_create returns NULL, instead of producing an object that segfaults on first use.

Actual behavior:
The interpreter segfaults.

The Python `WeaselJsonParser` class does not check the return value of `WeaselJsonParser_create`, so any stack size that causes the C constructor to return `NULL` leaves the wrapper holding a `NULL` parser pointer. Calling `parse()`/`reset()` on that wrapper immediately dereferences the null pointer and crashes the interpreter. Affected file: `weaseljson.py` - Lines 114–120: `self.p = self._lib.WeaselJsonParser_create(...)` is stored without validation. - Lines 122–123: `parse()` uses `self.p` unchecked. - Line 125: `reset()` also uses `self.p` unchecked. - Lines 132–135: `close()` does check `self.p is not None`, but only after creation has already stored `NULL`. Reproduction: ```python import weaseljson class R(weaseljson.WeaselJsonCallbacksBase): pass parser = weaseljson.WeaselJsonParser(R(), stackSize=-1) # C API returns NULL parser.parse(b"{}") # segfault ``` Also crashes with `stackSize=0`, `stackSize=1`, or `stackSize=2`, because `WeaselJsonParser_create` rejects non-positive and too-small stacks (tested in `src/test.cpp` around the "create rejects too-small stack" case). Expected behavior: `WeaselJsonParser.__init__` should raise a clear Python exception (e.g. `ValueError` or `MemoryError`) when `WeaselJsonParser_create` returns `NULL`, instead of producing an object that segfaults on first use. Actual behavior: The interpreter segfaults.
weaselbot was assigned by andrew 2026-06-22 00:56:05 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: weaselab/weaseljson#23