Skip to content

Commit 071c655

Browse files
committed
DISPATCH-1962 Fix leak of qdr_core_subscribe
undo the python undo fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym fixup dbgpkg Revert "DISPATCH-1942 Use findPython when on CMake3.15+" This reverts commit f486435 fixup too many decrefs fixup travis yml; this is the best way ;DDDD fixup travis yml? fixup try -fno-omit-frame-pointer fixup try -fno-omit-frame-pointer fixup try -fno-omit-frame-pointer fixup try -fno-omit-frame-pointer fixup try -fno-omit-frame-pointer try -fno-omit-frame-pointer WIP: attempt at improving situation around DISPATCH-1962 WIP: attempt at improving situation around DISPATCH-1962 undo the python undo fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym fixup dbgpkg Revert "DISPATCH-1942 Use findPython when on CMake3.15+" This reverts commit f486435 fixup too many decrefs fixup travis yml; this is the best way ;DDDD fixup travis yml? fixup try -fno-omit-frame-pointer fixup try -fno-omit-frame-pointer fixup try -fno-omit-frame-pointer fixup try -fno-omit-frame-pointer fixup try -fno-omit-frame-pointer try -fno-omit-frame-pointer WIP: attempt at improving situation around DISPATCH-1962 WIP: attempt at improving situation around DISPATCH-1962 undo the python undo fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym? fixup dbgsym fixup dbgpkg Revert "DISPATCH-1942 Use findPython when on CMake3.15+" This reverts commit f486435 fixup too many decrefs fixup travis yml; this is the best way ;DDDD fixup travis yml? fixup try -fno-omit-frame-pointer fixup try -fno-omit-frame-pointer fixup try -fno-omit-frame-pointer fixup try -fno-omit-frame-pointer fixup try -fno-omit-frame-pointer try -fno-omit-frame-pointer WIP: attempt at improving situation around DISPATCH-1962 WIP: attempt at improving situation around DISPATCH-1962
1 parent ad53d67 commit 071c655

File tree

7 files changed

+87
-21
lines changed

7 files changed

+87
-21
lines changed

.github/workflows/build.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ jobs:
121121
"-DCMAKE_INSTALL_PREFIX=${InstallPrefix}" \
122122
"-DCMAKE_BUILD_TYPE=${BuildType}" \
123123
"-GNinja" \
124-
${ProtonCMakeExtraArgs}
124+
${{env.ProtonCMakeExtraArgs}}
125125
126126
- name: qpid-proton cmake build/install
127127
run: cmake --build "${ProtonBuildDir}" --config ${BuildType} -t install
@@ -137,7 +137,7 @@ jobs:
137137
"-DCMAKE_BUILD_TYPE=${BuildType}" \
138138
"-DPYTHON_TEST_COMMAND='-m;pytest;-vs;--junit-prefix=pytest.\${py_test_module};--junit-xml=junitxmls/\${py_test_module}.xml;--pyargs;\${py_test_module}'" \
139139
"-GNinja" \
140-
${DispatchCMakeExtraArgs}
140+
${{env.DispatchCMakeExtraArgs}}
141141
142142
- name: qpid-dispatch cmake build/install
143143
run: cmake --build "${DispatchBuildDir}" --config ${BuildType} -t install

src/dispatch.c

+9-2
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ qd_error_t qd_dispatch_prepare(qd_dispatch_t *qd)
340340
void qd_dispatch_set_agent(qd_dispatch_t *qd, void *agent) {
341341
assert(agent);
342342
assert(!qd->agent);
343+
Py_IncRef(agent); // TODO: why not incref here? actually probably needed, I get a leak in test 9 without this, strange...
343344
qd->agent = agent;
344345
}
345346

@@ -371,12 +372,18 @@ void qd_dispatch_free(qd_dispatch_t *qd)
371372
qd_connection_manager_free(qd->connection_manager);
372373
qd_policy_free(qd->policy);
373374
Py_XDECREF((PyObject*) qd->agent);
375+
// Py_XDECREF(qd_python_module()); // hack
376+
PyGC_Collect(); // run destructors while we still have the router around
377+
// int ret = PyRun_SimpleString("import objgraph; import gc; gc.collect(); from qpid_dispatch_internal.management import config");
378+
// assert(ret == 0);
379+
380+
// qd_python_finalize();
381+
374382
qd_router_free(qd->router);
375383
qd_container_free(qd->container);
376384
qd_server_free(qd->server);
377385
qd_log_finalize();
378-
qd_alloc_finalize();
379-
qd_python_finalize();
386+
qd_alloc_finalize(); // python objects may use alloc pool objects during finalization? TODO: they do that now // actually, no, too late to do real work now
380387
qd_dispatch_set_router_id(qd, NULL);
381388
qd_dispatch_set_router_area(qd, NULL);
382389
qd_iterator_finalize();

src/python_embedded.c

+22-6
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,8 @@ static PyTypeObject LogAdapterType = {
565565
.tp_dealloc = (destructor)LogAdapter_dealloc,
566566
.tp_flags = Py_TPFLAGS_DEFAULT,
567567
.tp_methods = LogAdapter_methods,
568-
.tp_init = (initproc)LogAdapter_init
568+
.tp_init = (initproc)LogAdapter_init,
569+
.tp_new = PyType_GenericNew,
569570
};
570571

571572

@@ -719,10 +720,24 @@ static int IoAdapter_init(IoAdapter *self, PyObject *args, PyObject *kwds)
719720
return 0;
720721
}
721722

723+
// visit all members which may conceivably participate in reference cycles
724+
static int IoAdapter_traverse(IoAdapter* self, visitproc visit, void *arg)
725+
{
726+
Py_VISIT(self->handler);
727+
return 0;
728+
}
729+
730+
static int IoAdapter_clear(IoAdapter* self)
731+
{
732+
Py_CLEAR(self->handler);
733+
return 0;
734+
}
735+
722736
static void IoAdapter_dealloc(IoAdapter* self)
723737
{
724738
qdr_core_unsubscribe(self->sub);
725-
Py_DECREF(self->handler);
739+
PyObject_GC_UnTrack(self);
740+
IoAdapter_clear(self);
726741
Py_TYPE(self)->tp_free((PyObject*)self);
727742
}
728743

@@ -802,10 +817,13 @@ static PyTypeObject IoAdapterType = {
802817
.tp_name = DISPATCH_MODULE ".IoAdapter",
803818
.tp_doc = "Dispatch IO Adapter",
804819
.tp_basicsize = sizeof(IoAdapter),
820+
.tp_traverse = (traverseproc)IoAdapter_traverse,
821+
.tp_clear = (inquiry)IoAdapter_clear,
805822
.tp_dealloc = (destructor)IoAdapter_dealloc,
806-
.tp_flags = Py_TPFLAGS_DEFAULT,
823+
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
807824
.tp_methods = IoAdapter_methods,
808825
.tp_init = (initproc)IoAdapter_init,
826+
.tp_new = PyType_GenericNew,
809827
};
810828

811829

@@ -821,8 +839,6 @@ static void qd_register_constant(PyObject *module, const char *name, uint32_t va
821839

822840
static void qd_python_setup(void)
823841
{
824-
LogAdapterType.tp_new = PyType_GenericNew;
825-
IoAdapterType.tp_new = PyType_GenericNew;
826842
if ((PyType_Ready(&LogAdapterType) < 0) || (PyType_Ready(&IoAdapterType) < 0)) {
827843
qd_error_py();
828844
qd_log(log_source, QD_LOG_CRITICAL, "Unable to initialize Adapters");
@@ -866,7 +882,7 @@ static void qd_python_setup(void)
866882
qd_register_constant(m, "TREATMENT_ANYCAST_CLOSEST", QD_TREATMENT_ANYCAST_CLOSEST);
867883
qd_register_constant(m, "TREATMENT_ANYCAST_BALANCED", QD_TREATMENT_ANYCAST_BALANCED);
868884

869-
Py_INCREF(m);
885+
// Py_INCREF(m); // PyImport_ImportModule does the increment already
870886
dispatch_module = m;
871887
}
872888

src/router_core/router_core.c

+40
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ void qdr_core_free(qdr_core_t *core)
161161
}
162162
}
163163

164+
// I have to first run qdrc_endpoint_do_cleanup_CT src/router_core/core_link_endpoint.c:241
165+
// and only then qcm_edge_router_final_CT src/router_core/modules/edge_router/module.c:59
166+
164167
qdr_link_route_t *link_route = 0;
165168
while ( (link_route = DEQ_HEAD(core->link_routes))) {
166169
DEQ_REMOVE_HEAD(core->link_routes);
@@ -323,17 +326,54 @@ void qdr_core_free(qdr_core_t *core)
323326
}
324327
assert(DEQ_SIZE(core->streaming_connections) == 0);
325328

329+
// this now adds unsubscribe actions, so have to do before the discard next
330+
// plus I need to run it before core mutexes are freed
331+
332+
qdr_modules_finalize(core);
333+
334+
// discard any left over actions
335+
336+
qdr_action_list_t action_list;
337+
DEQ_MOVE(core->action_list, action_list);
338+
DEQ_APPEND(action_list, core->action_list_background);
339+
qdr_action_t *action = DEQ_HEAD(action_list);
340+
while (action) {
341+
DEQ_REMOVE_HEAD(action_list);
342+
action->action_handler(core, action, true);
343+
free_qdr_action_t(action);
344+
action = DEQ_HEAD(action_list);
345+
}
346+
347+
// Drain the general work lists
348+
qdr_general_handler(core);
349+
326350
// at this point all the conn identifiers have been freed
327351
qd_hash_free(core->conn_id_hash);
328352

329353
qdr_agent_free(core->mgmt_agent);
330354

355+
//
356+
// Free the core resources
357+
//
331358
if (core->routers_by_mask_bit) free(core->routers_by_mask_bit);
332359
if (core->control_links_by_mask_bit) free(core->control_links_by_mask_bit);
333360
if (core->data_links_by_mask_bit) free(core->data_links_by_mask_bit);
334361
if (core->neighbor_free_mask) qd_bitmask_free(core->neighbor_free_mask);
335362
if (core->rnode_conns_by_mask_bit) free(core->rnode_conns_by_mask_bit);
336363

364+
sys_thread_free(core->thread);
365+
sys_cond_free(core->action_cond);
366+
sys_mutex_free(core->action_lock);
367+
sys_mutex_free(core->work_lock);
368+
sys_mutex_free(core->id_lock);
369+
qd_timer_free(core->work_timer);
370+
371+
for (int i = 0; i <= QD_TREATMENT_LINK_BALANCED; ++i) {
372+
if (core->forwarders[i]) {
373+
free(core->forwarders[i]);
374+
}
375+
}
376+
337377
free(core);
338378
}
339379

src/router_node.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2169,12 +2169,12 @@ void qd_router_free(qd_router_t *router)
21692169

21702170
qd_container_set_default_node_type(router->qd, 0, 0, QD_DIST_BOTH);
21712171

2172+
qd_router_python_free(router);
21722173
qdr_core_free(router->router_core);
21732174
qd_tracemask_free(router->tracemask);
21742175
qd_timer_free(router->timer);
21752176
sys_mutex_free(router->lock);
21762177
qd_router_configure_free(router);
2177-
qd_router_python_free(router);
21782178

21792179
free(router);
21802180
qd_router_id_finalize();

src/router_pynode.c

+13-7
Original file line numberDiff line numberDiff line change
@@ -308,11 +308,12 @@ static PyMethodDef RouterAdapter_methods[] = {
308308

309309
static PyTypeObject RouterAdapterType = {
310310
PyVarObject_HEAD_INIT(NULL, 0)
311-
.tp_name = "dispatch.RouterAdapter", /* tp_name*/
312-
.tp_basicsize = sizeof(RouterAdapter), /* tp_basicsize*/
313-
.tp_flags = Py_TPFLAGS_DEFAULT, /* tp_flags*/
314-
.tp_doc = "Dispatch Router Adapter", /* tp_doc */
315-
.tp_methods = RouterAdapter_methods, /* tp_methods */
311+
.tp_name = "dispatch.RouterAdapter",
312+
.tp_basicsize = sizeof(RouterAdapter),
313+
.tp_flags = Py_TPFLAGS_DEFAULT,
314+
.tp_doc = "Dispatch Router Adapter",
315+
.tp_methods = RouterAdapter_methods,
316+
.tp_new = PyType_GenericNew,
316317
};
317318

318319

@@ -393,7 +394,6 @@ qd_error_t qd_router_python_setup(qd_router_t *router)
393394
return QD_ERROR_NONE;
394395

395396
PyObject *pDispatchModule = qd_python_module();
396-
RouterAdapterType.tp_new = PyType_GenericNew;
397397
PyType_Ready(&RouterAdapterType);
398398
QD_ERROR_PY_RET();
399399

@@ -443,6 +443,7 @@ qd_error_t qd_router_python_setup(qd_router_t *router)
443443
// Instantiate the router
444444
//
445445
pyRouter = PyObject_CallObject(pClass, pArgs);
446+
Py_DECREF(pClass);
446447
Py_DECREF(pArgs);
447448
Py_DECREF(adapterType);
448449
QD_ERROR_PY_RET();
@@ -455,7 +456,12 @@ qd_error_t qd_router_python_setup(qd_router_t *router)
455456
}
456457

457458
void qd_router_python_free(qd_router_t *router) {
458-
// empty
459+
Py_XDECREF(pyRouter);
460+
Py_XDECREF(pyTick);
461+
Py_XDECREF(pySetMobileSeq);
462+
Py_XDECREF(pySetMyMobileSeq);
463+
Py_XDECREF(pyLinkLost);
464+
// qd_python_finalize();
459465
}
460466

461467

tests/lsan.supp

-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
# found by AddressSanitizer (ASAN)
33
#
44

5-
# to be triaged; pretty much all tests
6-
leak:^IoAdapter_init$
7-
85
# to be triaged; pretty much all tests
96
leak:^load_server_config$
107

0 commit comments

Comments
 (0)