Skip to content

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

Merged
jamadden merged 1 commit into
python-greenlet:masterfrom
dynapx:fix-test-extension-npd
Jul 21, 2026
Merged

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

Conversation

@dynapx

@dynapx dynapx commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

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.

@jamadden

Copy link
Copy Markdown
Contributor

This is test code, so it doesn't really matter, but it's always better to be safe than sorry. Thanks.

@jamadden
jamadden merged commit 847fb82 into python-greenlet:master Jul 21, 2026
39 checks passed
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