From: Jaroslav Kysela Date: Wed, 20 Mar 2013 19:37:50 +0000 (+0100) Subject: pcm: fix and optimize snd_pcm_areas_copy function X-Git-Tag: v1.0.27~9 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=009193a34575fe439211b9a711e56322afc7460e;p=alsa-lib.git pcm: fix and optimize snd_pcm_areas_copy function The memcpy() function in snd_pcm_area_copy() should not be called with the overlapped areas. Alex discovered - using own LD_PRELOAD checked for memcpy() input - that the memcpy() is called with src == dst. For some special plugin combos (rate+softvol+hw for example), the same areas with same offsets can be asked to be copied (softvol). The collapse check uses own areas created on heap, causing dst_area == src_area && dst_offset == src_offset check bypassed. Two fixes are in this patch: - use assert to check the memcpy() input for future triggers - bypass the snd_pcm_area_copy() call for collapsed identical areas Reported-by: Alexander Kruppa Signed-off-by: Jaroslav Kysela --- diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 5053a7bc..05737d99 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -2711,6 +2711,8 @@ int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t dst_area->step == (unsigned int) width) { size_t bytes = samples * width / 8; samples -= bytes * 8 / width; + assert(src < dst || src >= dst + bytes); + assert(dst < src || dst >= src + bytes); memcpy(dst, src, bytes); if (samples == 0) return 0; @@ -2845,17 +2847,21 @@ int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_ break; } if (chns > 1 && chns * width == step) { - /* Collapse the areas */ - snd_pcm_channel_area_t s, d; - s.addr = src_start->addr; - s.first = src_start->first; - s.step = width; - d.addr = dst_start->addr; - d.first = dst_start->first; - d.step = width; - snd_pcm_area_copy(&d, dst_offset * chns, - &s, src_offset * chns, - frames * chns, format); + if (src_offset != dst_offset || + src_start->addr != dst_start->addr || + src_start->first != dst_start->first) { + /* Collapse the areas */ + snd_pcm_channel_area_t s, d; + s.addr = src_start->addr; + s.first = src_start->first; + s.step = width; + d.addr = dst_start->addr; + d.first = dst_start->first; + d.step = width; + snd_pcm_area_copy(&d, dst_offset * chns, + &s, src_offset * chns, + frames * chns, format); + } channels -= chns; } else { snd_pcm_area_copy(dst_start, dst_offset,