core_unreal.c: Fix memory leak in ast_unreal_new_channels()

When the channel tech is multistream capable, the reference to
chan_topology was passed to the new channel.  When the channel tech
isn't multistream capable, the reference to chan_topology was never
released.  "Local" channels are multistream capable so it didn't
affect them but the confbridge "CBAnn" and the bridge_media
"Recorder" channels are not so they caused a leak every time one
of them was created.

Also added tracing to ast_stream_topology_alloc() and
stream_topology_destroy() to assist with debugging.

Resolves: #938
(cherry picked from commit eecc0469c1)
releases/certified-18.9
George Joseph 12 months ago committed by Asterisk Development Team
parent eecce274d8
commit eb8c55d3e2

@ -1168,7 +1168,7 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
struct ast_assigned_ids id1 = {NULL, NULL}; struct ast_assigned_ids id1 = {NULL, NULL};
struct ast_assigned_ids id2 = {NULL, NULL}; struct ast_assigned_ids id2 = {NULL, NULL};
int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1); int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1);
struct ast_stream_topology *topology; RAII_VAR(struct ast_stream_topology *, topology, NULL, ast_stream_topology_free);
/* set unique ids for the two channels */ /* set unique ids for the two channels */
if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) { if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) {
@ -1186,14 +1186,6 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
id2.uniqueid = uniqueid2; id2.uniqueid = uniqueid2;
} }
/* We need to create a topology to place on the first channel, as we can't
* share a single one between both.
*/
topology = ast_stream_topology_clone(p->reqtopology);
if (!topology) {
return NULL;
}
/* /*
* Allocate two new Asterisk channels * Allocate two new Asterisk channels
* *
@ -1206,7 +1198,6 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
"%s/%s-%08x;1", tech->type, p->name, (unsigned)generated_seqno); "%s/%s-%08x;1", tech->type, p->name, (unsigned)generated_seqno);
if (!owner) { if (!owner) {
ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n"); ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n");
ast_stream_topology_free(topology);
return NULL; return NULL;
} }
@ -1221,7 +1212,15 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
ast_channel_nativeformats_set(owner, p->reqcap); ast_channel_nativeformats_set(owner, p->reqcap);
if (ast_channel_is_multistream(owner)) { if (ast_channel_is_multistream(owner)) {
ast_channel_set_stream_topology(owner, topology); /*
* We need to create a topology to place on the first channel, as we can't
* share a single one between both.
*/
topology = ast_stream_topology_clone(p->reqtopology);
if (!topology) {
return NULL;
}
ast_channel_set_stream_topology(owner, ao2_bump(topology));
} }
/* Determine our read/write format and set it on each channel */ /* Determine our read/write format and set it on each channel */

@ -641,27 +641,30 @@ struct ast_stream *ast_stream_create_resolved(struct ast_stream *pending_stream,
static void stream_topology_destroy(void *data) static void stream_topology_destroy(void *data)
{ {
struct ast_stream_topology *topology = data; struct ast_stream_topology *topology = data;
SCOPE_ENTER(4, "Topology: %p: %s\n", topology, ast_str_tmp(128, ast_stream_topology_to_str(topology, &STR_TMP)));
AST_VECTOR_CALLBACK_VOID(&topology->streams, ast_stream_free); AST_VECTOR_CALLBACK_VOID(&topology->streams, ast_stream_free);
AST_VECTOR_FREE(&topology->streams); AST_VECTOR_FREE(&topology->streams);
SCOPE_EXIT_RTN("Destroyed: %p\n", topology);
} }
#define TOPOLOGY_INITIAL_STREAM_COUNT 2 #define TOPOLOGY_INITIAL_STREAM_COUNT 2
struct ast_stream_topology *ast_stream_topology_alloc(void) struct ast_stream_topology *ast_stream_topology_alloc(void)
{ {
struct ast_stream_topology *topology; struct ast_stream_topology *topology;
SCOPE_ENTER(4, "Topology Create\n");
topology = ao2_alloc_options(sizeof(*topology), stream_topology_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); topology = ao2_alloc_options(sizeof(*topology), stream_topology_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
if (!topology) { if (!topology) {
return NULL; SCOPE_EXIT_RTN_VALUE(NULL, "Allocation failed\n");
} }
if (AST_VECTOR_INIT(&topology->streams, TOPOLOGY_INITIAL_STREAM_COUNT)) { if (AST_VECTOR_INIT(&topology->streams, TOPOLOGY_INITIAL_STREAM_COUNT)) {
ao2_ref(topology, -1); ao2_ref(topology, -1);
topology = NULL; SCOPE_EXIT_RTN_VALUE(NULL, "Vector init failed\n");
} }
return topology; SCOPE_EXIT_RTN_VALUE(topology, "Created: %p\n", topology);
} }
struct ast_stream_topology *ast_stream_topology_clone( struct ast_stream_topology *ast_stream_topology_clone(

Loading…
Cancel
Save