Skip to content

fix(c-api): add missing NULL check after Py_BuildValue in _test_exten…#520

Open
dynapx wants to merge 1 commit into
python-greenlet:masterfrom
dynapx:fix-test-extension-npd
Open

fix(c-api): add missing NULL check after Py_BuildValue in _test_exten…#520
dynapx wants to merge 1 commit into
python-greenlet:masterfrom
dynapx:fix-test-extension-npd

Conversation

@dynapx

@dynapx dynapx commented Jul 4, 2026

Copy link
Copy Markdown

Description

During a security and robustness audit of C-API usage using our static analysis tool, we identified a potential Null Pointer Dereference (NPD) in src/greenlet/tests/_test_extension.c.

In the test_throw function, Py_BuildValue("s", msg) is called to create a string object. According to the Python C-API contract, if memory allocation fails (OOM), it returns NULL and sets a MemoryError. However, the return value msg_obj is currently not checked before being used.

If msg_obj is NULL, it leads to a double crash hazard:

  1. Capsule Pointer Propagation: msg_obj is passed to PyGreenlet_Throw. Since PyGreenlet_Throw is a macro that dereferences a function pointer from _PyGreenlet_API, injecting an unvalidated NULL pointer across the API boundary can lead to undefined behavior inside the core logic.
  2. Deterministic Macro Crash: Immediately after, Py_DECREF(msg_obj) is called. Unlike Py_XDECREF, the Py_DECREF macro lacks a NULL check. It will attempt to access msg_obj->ob_refcnt, resulting in a deterministic Segmentation Fault.

This hard crash truncates the exception lifecycle, destroying the original MemoryError state and preventing graceful failure.

Proposed Fix

We added a standard NULL check immediately after Py_BuildValue. If allocation fails, the function now safely returns NULL to propagate the exception properly.

// Change made:
    PyObject* msg_obj = Py_BuildValue("s", msg);
+   if (msg_obj == NULL) {
+       return NULL;
+   }
    PyGreenlet_Throw(g, PyExc_ValueError, msg_obj, NULL);

Impact

This PR improves the robustness of the test extension, ensuring that extreme memory exhaustion scenarios are handled gracefully without taking down the entire interpreter process.

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.

1 participant