[Bugfix] sfVector2f_to_PyObject crashes on NULL from PyObject_GetAttrString #268

Closed
opened 2026-03-07 23:20:49 +00:00 by john · 0 comments
Owner

Summary

sfVector2f_to_PyObject() and sfVector2i_to_PyObject() call PyObject_GetAttrString() to look up the Vector type, then immediately dereference the result via type->tp_alloc() without checking for NULL. If the module is in a bad state (e.g., during interpreter shutdown or if the module hasn't been fully initialized), this is a NULL pointer dereference → segfault.

Root Cause

UIEntity.cpp:297-303:

PyObject* sfVector2f_to_PyObject(sf::Vector2f vec) {
    auto type = (PyTypeObject*)PyObject_GetAttrString(McRFPy_API::mcrf_module, "Vector");
    auto obj = (PyVectorObject*)type->tp_alloc(type, 0);  // NULL deref if type is NULL
    if (obj) {
        obj->data = vec;
    }
    return (PyObject*)obj;
}

Same issue in sfVector2i_to_PyObject at line 306.

Note: type is also never Py_DECREF'd (see PyObject_GetAttrString leak issue).

Reproduction

This is hard to trigger in normal operation since McRFPy_API::mcrf_module is initialized early. But it can happen:

  • During interpreter finalization
  • If an entity property getter is called during module teardown
  • If mcrf_module is somehow NULL

Fix

Use the inline type declaration directly:

PyObject* sfVector2f_to_PyObject(sf::Vector2f vec) {
    auto type = &mcrfpydef::PyVectorType;
    auto obj = (PyVectorObject*)type->tp_alloc(type, 0);
    if (obj) {
        obj->data = vec;
    }
    return (PyObject*)obj;
}

This eliminates both the NULL risk and the reference leak.

Severity

High — potential segfault. Low probability in normal operation but catastrophic when triggered.

## Summary `sfVector2f_to_PyObject()` and `sfVector2i_to_PyObject()` call `PyObject_GetAttrString()` to look up the `Vector` type, then immediately dereference the result via `type->tp_alloc()` without checking for NULL. If the module is in a bad state (e.g., during interpreter shutdown or if the module hasn't been fully initialized), this is a NULL pointer dereference → segfault. ## Root Cause `UIEntity.cpp:297-303`: ```cpp PyObject* sfVector2f_to_PyObject(sf::Vector2f vec) { auto type = (PyTypeObject*)PyObject_GetAttrString(McRFPy_API::mcrf_module, "Vector"); auto obj = (PyVectorObject*)type->tp_alloc(type, 0); // NULL deref if type is NULL if (obj) { obj->data = vec; } return (PyObject*)obj; } ``` Same issue in `sfVector2i_to_PyObject` at line 306. Note: `type` is also never `Py_DECREF`'d (see PyObject_GetAttrString leak issue). ## Reproduction This is hard to trigger in normal operation since `McRFPy_API::mcrf_module` is initialized early. But it can happen: - During interpreter finalization - If an entity property getter is called during module teardown - If `mcrf_module` is somehow NULL ## Fix Use the inline type declaration directly: ```cpp PyObject* sfVector2f_to_PyObject(sf::Vector2f vec) { auto type = &mcrfpydef::PyVectorType; auto obj = (PyVectorObject*)type->tp_alloc(type, 0); if (obj) { obj->data = vec; } return (PyObject*)obj; } ``` This eliminates both the NULL risk and the reference leak. ## Severity **High** — potential segfault. Low probability in normal operation but catastrophic when triggered.
john closed this issue 2026-03-14 06:25:16 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
john/McRogueFace#268
No description provided.