Skip to content

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

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

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants