Skip to content

C-message reader keep-alive (follow-up to #676) #1433

Description

@robotrocketscience

Follow-up to #676 (PR #1432).

#676 / PR #1432 fixed the garbage-collection use-after-free for C++ readers
(ReadFunctor<T>) subscribing to either a C++ Message<T> or a C Msg_C source: the
subscription now keeps the Python source object alive via an opaque keep-alive bridge whose
release is driven by ReadFunctor's C++ destructor.

That mechanism does not cover the other direction: a C-module input message
(Msg_C reader)
subscribing to a stand-alone source. For example a C module's dataInMsg:

mod = cModuleTemplate.cModuleTemplate()
inMsg = messaging.CModuleTemplateMsg().write(payload)   # created in a helper scope
mod.dataInMsg.subscribeTo(inMsg)                          # mod.dataInMsg is a Msg_C reader
# inMsg can still be garbage collected here -> mod reads freed memory

Why it was deferred: Msg_C is a plain C struct (msg_C.h.in) with no destructor and no
reader/writer distinction — the "reader" state is raw pointers stored in the struct itself.
There is no C++ destructor to hook a Py_DECREF onto, and SWIG only deletes a Msg_C when
Python owns it (module-embedded Msg_C is never deleted by SWIG), so a struct-stored release
callback would either never fire (leak) or fire at the wrong time.

Current workaround (still required for this case): retain the source message in a
persistent Python scope (e.g. on the simulation object), as documented in bskKnownIssues.rst
and previously in #1107.

Suggested approach for a fix: a side-table keyed by the Msg_C* (e.g. a C++
std::unordered_map<void*, PyObject*>) populated by the SWIG subscribeTo wrapper for
Msg_C, with the reference dropped by *_C_unsubscribe and by a SWIG __del__/tp_dealloc
extension on the Msg_C proxy. This needs its own design pass; out of scope for #1432.

Relevant files: src/architecture/messaging/cMsgCInterface/msg_C.h.in, msg_C.cpp.in,
src/architecture/messaging/msgAutoSource/cMsgCInterfacePy.i.in.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions