Skip to content

Fix C-API exception handling issues (lock OOM, signed char -1, exception preservation) - #257

Draft
dynapx wants to merge 1 commit into
python-cffi:mainfrom
dynapx:fix/cffi-exception-handling
Draft

Fix C-API exception handling issues (lock OOM, signed char -1, exception preservation)#257
dynapx wants to merge 1 commit into
python-cffi:mainfrom
dynapx:fix/cffi-exception-handling

Conversation

@dynapx

@dynapx dynapx commented Jul 14, 2026

Copy link
Copy Markdown

Title: Fix C-API exception handling issues (lock OOM, signed char -1)


Description

Hi maintainers,

This PR is a follow-up to #256 (which fixed unchecked PyUnicode_AsUTF8 returns). It addresses additional C-API exception handling issues identified during the same robustness audit of the _cffi_backend C extension.


1. PyThread_allocate_lock failure does not set exception

Location: ffi_obj.c:ffi_init_once

PyThread_allocate_lock() returns NULL on failure but does not set a Python exception. The code currently returns NULL without setting an exception, leading to SystemError.

Fix: Add PyErr_SetString() with a descriptive error message before returning.

-        if (lock == NULL)
+        if (lock == NULL)
+        {
+            PyErr_SetString(PyExc_RuntimeError,
+                    "failed to allocate thread lock for init_once");
             return NULL;
+        }

2. ctypedescr_new OOM does not set exception

Location: _cffi_backend.c:new_struct_or_union_type

ctypedescr_new() returns NULL on OOM but does not set an exception. The caller returns NULL without setting an exception.

Fix: Add PyErr_NoMemory().

-    if (td == NULL)
+    if (td == NULL) {
+        PyErr_NoMemory();
         return NULL;
+    }

3. Signed char -1 false negative detection

Location: _cffi_backend.c:convert_from_object

_convert_to_char(init) returns -1 on error, but -1 is also a valid signed char value (representing 0xFF). The current code treats both as error, causing valid \xFF input to fail without setting exception.

Fix: Check PyErr_Occurred() to distinguish between error and valid -1.

-            if (res < 0)
+            if (res < 0 && PyErr_Occurred())
                 return -1;

Impact

These issues can cause:

  • SystemError when PyThread_allocate_lock fails
  • SystemError when ctypedescr_new hits OOM
  • Rejection of valid \xFF byte values
- Add PyErr_SetString for PyThread_allocate_lock failure
  (ffi_init_once: lock allocation failure does not set exception)

- Add PyErr_NoMemory for ctypedescr_new OOM
  (new_struct_or_union_type: ctypedescr_new does not set exception on OOM)

- Fix signed char -1 false negative detection
  (convert_from_object: -1 is valid signed char value, check PyErr_Occurred)

- Preserve exceptions in _convert_to_char16_t/_convert_to_char32_t
  (avoid overwriting existing exception from _my_PyUnicode_AsSingleChar*)
@mattip

mattip commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Please move to draft status until the issue is discussed.

@mattip
mattip marked this pull request as draft July 26, 2026 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants