Skip to content

Avoid leaking module object on numpy C-API import failure - #263

Open
antonwolfy wants to merge 1 commit into
mainfrom
fix-ufuncs-module-leak
Open

Avoid leaking module object on numpy C-API import failure#263
antonwolfy wants to merge 1 commit into
mainfrom
fix-ufuncs-module-leak

Conversation

@antonwolfy

Copy link
Copy Markdown
Collaborator

Summary

import_array() and import_umath() are macros that expand to return NULL; on failure. In PyInit__ufuncs they were called after PyModule_Create(), so a failing numpy C-API import returned directly out of the init function without releasing the module object — leaking the strong reference created by PyModule_Create().

This moves the imports before the module is created, so there is no owned reference to leak when an import fails. This is the pattern documented for the numpy import macros, which are designed to be called from a context where a bare return NULL; is valid.

Notes

Latent, pre-existing bug; only triggers on the (rare, usually fatal) failure of numpy's C-API import at module init. No behavior change on the success path.

import_array() and import_umath() are macros that expand to `return NULL;`
on failure. When they were called after PyModule_Create(), a failing import
would return directly out of PyInit__ufuncs without releasing the module
object, leaking the strong reference created by PyModule_Create().

Move the imports before the module is created so there is no owned
reference to leak when an import fails.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment on lines +43 to +44
/* import_array()/import_umath() expand to `return NULL;` on failure, so
* call them before creating the module object to avoid leaking it. */

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if these return NULL, why would the module object leak? It's not clear to me, we don't check if the imports are NULL anywhere either

@antonwolfy antonwolfy Aug 31, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There will be leak (if any import_array()/import_umath() failed and call return NULL) if calls placed after m = PyModule_Create(&_ufuncs_module); since no Py_XDECREF(m)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, these functions are macros internally in NumPy which expand to 'return NULL' or 'return' respectively, so it actually crashes later or unexpectedly

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assumed it was using PyImport_ImportModule. In that case, maybe make the comment a bit clearer for future reference

@ndgrigorian ndgrigorian left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

other than nit LGTM

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