Python wrapper declares void-returning C functions with default c_int restype #46

Closed
opened 2026-06-21 11:19:19 +00:00 by weaselbot · 0 comments
Member

conflict_set.py configures argtypes for the C API functions but only sets restype for ConflictSet_create and ConflictSet_getBytes. The remaining functions—ConflictSet_check, ConflictSet_addWrites, ConflictSet_setOldestVersion, and ConflictSet_destroy—return void in C, but the wrapper leaves them with ctypes' default restype of c_int.

File: conflict_set.py
Lines: 85–104 (ConflictSet_check, ConflictSet_addWrites, ConflictSet_setOldestVersion, ConflictSet_destroy setup)

Expected behavior: For C functions that return void, the wrapper should set restype = None so ctypes does not try to interpret the return register.

Actual behavior: The wrapper reads an unspecified c_int from the return register for each call. The return value is discarded, so it usually appears to work, but it is technically undefined behavior and a mismatch with the C API contract. On ABIs where a void-returning function leaves unrelated values in the return register, this can produce garbage return values and could mask future calling-convention issues.

Fix: After each argtypes assignment for the four void functions, add the corresponding restype = None line:

self._lib.ConflictSet_check.restype = None
self._lib.ConflictSet_addWrites.restype = None
self._lib.ConflictSet_setOldestVersion.restype = None
self._lib.ConflictSet_destroy.restype = None

Reproduced by loading the wrapper and printing cs._lib.ConflictSet_check.restype, which is <class 'ctypes.c_int'> instead of None.

`conflict_set.py` configures `argtypes` for the C API functions but only sets `restype` for `ConflictSet_create` and `ConflictSet_getBytes`. The remaining functions—`ConflictSet_check`, `ConflictSet_addWrites`, `ConflictSet_setOldestVersion`, and `ConflictSet_destroy`—return `void` in C, but the wrapper leaves them with ctypes' default `restype` of `c_int`. File: `conflict_set.py` Lines: 85–104 (`ConflictSet_check`, `ConflictSet_addWrites`, `ConflictSet_setOldestVersion`, `ConflictSet_destroy` setup) Expected behavior: For C functions that return `void`, the wrapper should set `restype = None` so ctypes does not try to interpret the return register. Actual behavior: The wrapper reads an unspecified `c_int` from the return register for each call. The return value is discarded, so it usually appears to work, but it is technically undefined behavior and a mismatch with the C API contract. On ABIs where a void-returning function leaves unrelated values in the return register, this can produce garbage return values and could mask future calling-convention issues. Fix: After each `argtypes` assignment for the four void functions, add the corresponding `restype = None` line: ```python self._lib.ConflictSet_check.restype = None self._lib.ConflictSet_addWrites.restype = None self._lib.ConflictSet_setOldestVersion.restype = None self._lib.ConflictSet_destroy.restype = None ``` Reproduced by loading the wrapper and printing `cs._lib.ConflictSet_check.restype`, which is `<class 'ctypes.c_int'>` instead of `None`.
weaselbot was assigned by andrew 2026-06-21 15:02:52 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: weaselab/conflict-set#46