[PATCH 0/5] MR4359: dmime: Fix port leaks in performance channel blocks.
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/dmime/performance.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 94d7d8aeea3..3f40ecd5549 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -32,7 +32,8 @@ enum dmus_internal_message_type DMUS_PMSGT_INTERNAL_SEGMENT_TICK, }; -struct pchannel_block { +struct channel_block +{ DWORD block_num; /* Block 0 is PChannels 0-15, Block 1 is PChannels 16-31, etc */ struct { DWORD channel; /* MIDI channel */ @@ -56,7 +57,7 @@ struct performance float fMasterTempo; long lMasterVolume; /* performance channels */ - struct wine_rb_tree pchannels; + struct wine_rb_tree channel_blocks; BOOL audio_paths_enabled; IDirectMusicAudioPath *pDefaultPath; @@ -233,30 +234,28 @@ static HRESULT performance_send_notification_pmsg(struct performance *This, MUSI return hr; } -static int pchannel_block_compare(const void *key, const struct wine_rb_entry *entry) +static int channel_block_compare(const void *key, const struct wine_rb_entry *entry) { - const struct pchannel_block *b = WINE_RB_ENTRY_VALUE(entry, const struct pchannel_block, entry); - + const struct channel_block *b = WINE_RB_ENTRY_VALUE(entry, const struct channel_block, entry); return *(DWORD *)key - b->block_num; } -static void pchannel_block_free(struct wine_rb_entry *entry, void *context) +static void channel_block_free(struct wine_rb_entry *entry, void *context) { - struct pchannel_block *b = WINE_RB_ENTRY_VALUE(entry, struct pchannel_block, entry); - + struct channel_block *b = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); free(b); } -static struct pchannel_block *pchannel_block_set(struct wine_rb_tree *tree, DWORD block_num, +static struct channel_block *channel_block_set(struct wine_rb_tree *tree, DWORD block_num, IDirectMusicPort *port, DWORD group, BOOL only_set_new) { - struct pchannel_block *block; + struct channel_block *block; struct wine_rb_entry *entry; unsigned int i; entry = wine_rb_get(tree, &block_num); if (entry) { - block = WINE_RB_ENTRY_VALUE(entry, struct pchannel_block, entry); + block = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); if (only_set_new) return block; } else { @@ -408,7 +407,7 @@ static ULONG WINAPI performance_Release(IDirectMusicPerformance8 *iface) TRACE("(%p): ref=%ld\n", This, ref); if (ref == 0) { - wine_rb_destroy(&This->pchannels, pchannel_block_free, NULL); + wine_rb_destroy(&This->channel_blocks, channel_block_free, NULL); This->safe.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->safe); free(This); @@ -984,7 +983,7 @@ static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *par } for (i = 0; i < params->dwChannelGroups; i++) - pchannel_block_set(&perf->pchannels, i, port, i + 1, FALSE); + channel_block_set(&perf->channel_blocks, i, port, i + 1, FALSE); performance_update_latency_time(perf, port, NULL); return S_OK; @@ -1041,7 +1040,7 @@ static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 * if (block_num > MAXDWORD / 16) return E_INVALIDARG; if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; - pchannel_block_set(&This->pchannels, block_num, port, group, FALSE); + channel_block_set(&This->channel_blocks, block_num, port, group, FALSE); return S_OK; } @@ -1050,14 +1049,14 @@ static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface IDirectMusicPort *port, DWORD group, DWORD channel) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - struct pchannel_block *block; + struct channel_block *block; FIXME("(%p)->(%ld, %p, %ld, %ld) semi-stub\n", This, pchannel, port, group, channel); if (!port) return E_POINTER; if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; - block = pchannel_block_set(&This->pchannels, pchannel / 16, port, 0, TRUE); + block = channel_block_set(&This->channel_blocks, pchannel / 16, port, 0, TRUE); if (block) { block->pchannel[pchannel % 16].group = group; block->pchannel[pchannel % 16].channel = channel; @@ -1070,17 +1069,17 @@ static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, IDirectMusicPort **port, DWORD *group, DWORD *channel) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - struct pchannel_block *block; + struct channel_block *block; struct wine_rb_entry *entry; DWORD block_num = pchannel / 16; unsigned int index = pchannel % 16; TRACE("(%p)->(%ld, %p, %p, %p)\n", This, pchannel, port, group, channel); - entry = wine_rb_get(&This->pchannels, &block_num); + entry = wine_rb_get(&This->channel_blocks, &block_num); if (!entry) return E_INVALIDARG; - block = WINE_RB_ENTRY_VALUE(entry, struct pchannel_block, entry); + block = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); if (port) { *port = block->pchannel[index].port; @@ -2080,7 +2079,7 @@ HRESULT create_dmperformance(REFIID iid, void **ret_iface) obj->pDefaultPath = NULL; InitializeCriticalSection(&obj->safe); obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": performance->safe"); - wine_rb_init(&obj->pchannels, pchannel_block_compare); + wine_rb_init(&obj->channel_blocks, channel_block_compare); list_init(&obj->messages); list_init(&obj->notifications); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4359
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/dmime/performance.c | 57 ++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 3f40ecd5549..b46e5ae8609 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -32,14 +32,17 @@ enum dmus_internal_message_type DMUS_PMSGT_INTERNAL_SEGMENT_TICK, }; +struct channel +{ + DWORD midi_group; + DWORD midi_channel; + IDirectMusicPort *port; +}; + struct channel_block { DWORD block_num; /* Block 0 is PChannels 0-15, Block 1 is PChannels 16-31, etc */ - struct { - DWORD channel; /* MIDI channel */ - DWORD group; /* MIDI group */ - IDirectMusicPort *port; - } pchannel[16]; + struct channel channels[16]; struct wine_rb_entry entry; }; @@ -247,7 +250,7 @@ static void channel_block_free(struct wine_rb_entry *entry, void *context) } static struct channel_block *channel_block_set(struct wine_rb_tree *tree, DWORD block_num, - IDirectMusicPort *port, DWORD group, BOOL only_set_new) + IDirectMusicPort *port, DWORD midi_group, BOOL only_set_new) { struct channel_block *block; struct wine_rb_entry *entry; @@ -264,9 +267,9 @@ static struct channel_block *channel_block_set(struct wine_rb_tree *tree, DWORD } for (i = 0; i < 16; ++i) { - block->pchannel[i].port = port; - block->pchannel[i].group = group; - block->pchannel[i].channel = i; + block->channels[i].port = port; + block->channels[i].midi_group = midi_group; + block->channels[i].midi_channel = i; } if (!entry) wine_rb_put(tree, &block->block_num, &block->entry); @@ -1030,51 +1033,51 @@ static HRESULT WINAPI performance_RemovePort(IDirectMusicPerformance8 *iface, ID } static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 *iface, - DWORD block_num, IDirectMusicPort *port, DWORD group) + DWORD block_num, IDirectMusicPort *port, DWORD midi_group) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - FIXME("(%p, %ld, %p, %ld): semi-stub\n", This, block_num, port, group); + FIXME("(%p, %ld, %p, %ld): semi-stub\n", This, block_num, port, midi_group); if (!port) return E_POINTER; if (block_num > MAXDWORD / 16) return E_INVALIDARG; if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; - channel_block_set(&This->channel_blocks, block_num, port, group, FALSE); + channel_block_set(&This->channel_blocks, block_num, port, midi_group, FALSE); return S_OK; } -static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface, DWORD pchannel, - IDirectMusicPort *port, DWORD group, DWORD channel) +static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface, DWORD channel_num, + IDirectMusicPort *port, DWORD midi_group, DWORD midi_channel) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); struct channel_block *block; - FIXME("(%p)->(%ld, %p, %ld, %ld) semi-stub\n", This, pchannel, port, group, channel); + FIXME("(%p)->(%ld, %p, %ld, %ld) semi-stub\n", This, channel_num, port, midi_group, midi_channel); if (!port) return E_POINTER; if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; - block = channel_block_set(&This->channel_blocks, pchannel / 16, port, 0, TRUE); + block = channel_block_set(&This->channel_blocks, channel_num / 16, port, 0, TRUE); if (block) { - block->pchannel[pchannel % 16].group = group; - block->pchannel[pchannel % 16].channel = channel; + block->channels[channel_num % 16].midi_group = midi_group; + block->channels[channel_num % 16].midi_channel = midi_channel; } return S_OK; } -static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, DWORD pchannel, - IDirectMusicPort **port, DWORD *group, DWORD *channel) +static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, DWORD channel_num, + IDirectMusicPort **port, DWORD *midi_group, DWORD *midi_channel) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); struct channel_block *block; struct wine_rb_entry *entry; - DWORD block_num = pchannel / 16; - unsigned int index = pchannel % 16; + DWORD block_num = channel_num / 16; + unsigned int index = channel_num % 16; - TRACE("(%p)->(%ld, %p, %p, %p)\n", This, pchannel, port, group, channel); + TRACE("(%p)->(%ld, %p, %p, %p)\n", This, channel_num, port, midi_group, midi_channel); entry = wine_rb_get(&This->channel_blocks, &block_num); if (!entry) @@ -1082,13 +1085,11 @@ static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, block = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); if (port) { - *port = block->pchannel[index].port; + *port = block->channels[index].port; IDirectMusicPort_AddRef(*port); } - if (group) - *group = block->pchannel[index].group; - if (channel) - *channel = block->pchannel[index].channel; + if (midi_group) *midi_group = block->channels[index].midi_group; + if (midi_channel) *midi_channel = block->channels[index].midi_channel; return S_OK; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4359
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/dmime/performance.c | 46 ++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index b46e5ae8609..7269cd07670 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -249,6 +249,14 @@ static void channel_block_free(struct wine_rb_entry *entry, void *context) free(b); } +static struct channel *performance_get_channel(struct performance *This, DWORD channel_num) +{ + DWORD block_num = channel_num / 16; + struct wine_rb_entry *entry; + if (!(entry = wine_rb_get(&This->channel_blocks, &block_num))) return NULL; + return WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry)->channels + channel_num % 16; +} + static struct channel_block *channel_block_set(struct wine_rb_tree *tree, DWORD block_num, IDirectMusicPort *port, DWORD midi_group, BOOL only_set_new) { @@ -1052,19 +1060,27 @@ static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface IDirectMusicPort *port, DWORD midi_group, DWORD midi_channel) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - struct channel_block *block; + struct channel *channel; + HRESULT hr; FIXME("(%p)->(%ld, %p, %ld, %ld) semi-stub\n", This, channel_num, port, midi_group, midi_channel); if (!port) return E_POINTER; if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; - block = channel_block_set(&This->channel_blocks, channel_num / 16, port, 0, TRUE); - if (block) { - block->channels[channel_num % 16].midi_group = midi_group; - block->channels[channel_num % 16].midi_channel = midi_channel; + if (!(channel = performance_get_channel(This, channel_num))) + { + if (FAILED(hr = IDirectMusicPerformance8_AssignPChannelBlock(iface, + channel_num / 16, port, 0))) + return hr; + if (!(channel = performance_get_channel(This, channel_num))) + return DMUS_E_NOT_FOUND; } + channel->midi_group = midi_group; + channel->midi_channel = midi_channel; + channel->port = port; + return S_OK; } @@ -1072,24 +1088,18 @@ static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, IDirectMusicPort **port, DWORD *midi_group, DWORD *midi_channel) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - struct channel_block *block; - struct wine_rb_entry *entry; - DWORD block_num = channel_num / 16; - unsigned int index = channel_num % 16; + struct channel *channel; TRACE("(%p)->(%ld, %p, %p, %p)\n", This, channel_num, port, midi_group, midi_channel); - entry = wine_rb_get(&This->channel_blocks, &block_num); - if (!entry) - return E_INVALIDARG; - block = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); - - if (port) { - *port = block->channels[index].port; + if (!(channel = performance_get_channel(This, channel_num))) return E_INVALIDARG; + if (port) + { + *port = channel->port; IDirectMusicPort_AddRef(*port); } - if (midi_group) *midi_group = block->channels[index].midi_group; - if (midi_channel) *midi_channel = block->channels[index].midi_channel; + if (midi_group) *midi_group = channel->midi_group; + if (midi_channel) *midi_channel = channel->midi_channel; return S_OK; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4359
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/dmime/performance.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 7269cd07670..4b169427371 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -257,32 +257,31 @@ static struct channel *performance_get_channel(struct performance *This, DWORD c return WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry)->channels + channel_num % 16; } -static struct channel_block *channel_block_set(struct wine_rb_tree *tree, DWORD block_num, - IDirectMusicPort *port, DWORD midi_group, BOOL only_set_new) +static HRESULT channel_block_init(struct performance *This, DWORD block_num, + IDirectMusicPort *port, DWORD midi_group) { struct channel_block *block; struct wine_rb_entry *entry; - unsigned int i; + UINT i; - entry = wine_rb_get(tree, &block_num); - if (entry) { + if ((entry = wine_rb_get(&This->channel_blocks, &block_num))) block = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); - if (only_set_new) - return block; - } else { - if (!(block = malloc(sizeof(*block)))) return NULL; + else + { + if (!(block = calloc(1, sizeof(*block)))) return E_OUTOFMEMORY; block->block_num = block_num; + wine_rb_put(&This->channel_blocks, &block_num, &block->entry); } - for (i = 0; i < 16; ++i) { - block->channels[i].port = port; - block->channels[i].midi_group = midi_group; - block->channels[i].midi_channel = i; + for (i = 0; i < ARRAY_SIZE(block->channels); ++i) + { + struct channel *channel = block->channels + i; + channel->midi_group = midi_group; + channel->midi_channel = i; + channel->port = port; } - if (!entry) - wine_rb_put(tree, &block->block_num, &block->entry); - return block; + return S_OK; } static inline struct performance *impl_from_IDirectMusicPerformance8(IDirectMusicPerformance8 *iface) @@ -994,7 +993,10 @@ static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *par } for (i = 0; i < params->dwChannelGroups; i++) - channel_block_set(&perf->channel_blocks, i, port, i + 1, FALSE); + { + if (FAILED(hr = channel_block_init(perf, i, port, i + 1))) + ERR("Failed to init channel block, hr %#lx\n", hr); + } performance_update_latency_time(perf, port, NULL); return S_OK; @@ -1051,9 +1053,7 @@ static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 * if (block_num > MAXDWORD / 16) return E_INVALIDARG; if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; - channel_block_set(&This->channel_blocks, block_num, port, midi_group, FALSE); - - return S_OK; + return channel_block_init(This, block_num, port, midi_group); } static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface, DWORD channel_num, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4359
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/dmime/performance.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 4b169427371..0e817d232e3 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -245,8 +245,16 @@ static int channel_block_compare(const void *key, const struct wine_rb_entry *en static void channel_block_free(struct wine_rb_entry *entry, void *context) { - struct channel_block *b = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); - free(b); + struct channel_block *block = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); + UINT i; + + for (i = 0; i < ARRAY_SIZE(block->channels); i++) + { + struct channel *channel = block->channels + i; + if (channel->port) IDirectMusicPort_Release(channel->port); + } + + free(block); } static struct channel *performance_get_channel(struct performance *This, DWORD channel_num) @@ -278,7 +286,8 @@ static HRESULT channel_block_init(struct performance *This, DWORD block_num, struct channel *channel = block->channels + i; channel->midi_group = midi_group; channel->midi_channel = i; - channel->port = port; + if (channel->port) IDirectMusicPort_Release(channel->port); + if ((channel->port = port)) IDirectMusicPort_AddRef(channel->port); } return S_OK; @@ -992,6 +1001,8 @@ static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *par return hr; } + wine_rb_destroy(&perf->channel_blocks, channel_block_free, NULL); + for (i = 0; i < params->dwChannelGroups; i++) { if (FAILED(hr = channel_block_init(perf, i, port, i + 1))) @@ -999,6 +1010,7 @@ static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *par } performance_update_latency_time(perf, port, NULL); + IDirectMusicPort_Release(port); return S_OK; } @@ -1079,7 +1091,8 @@ static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface channel->midi_group = midi_group; channel->midi_channel = midi_channel; - channel->port = port; + if (channel->port) IDirectMusicPort_Release(channel->port); + if ((channel->port = port)) IDirectMusicPort_AddRef(channel->port); return S_OK; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4359
The leak causes some game to spawn hundred of synth threads as they call CreateStandardAudioPath dozen of times. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/4359#note_51907
This merge request was approved by Michael Stefaniuc. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/4359
Unrelated test failures in device.c and win.c -- https://gitlab.winehq.org/wine/wine/-/merge_requests/4359#note_51968
participants (2)
-
Michael Stefaniuc (@mstefani) -
Rémi Bernon