From 00f5aa1337b7a757d07021c5c16f37eaae96dcb3 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Fri, 10 Apr 2020 09:10:33 +0200 Subject: pcm: avoid calling pcm_hw->close() twice It would result in a double free: $ tinyplay example.wav failed to open for pcm 0,0 *** glibc detected *** ./utils/tinyplay: double free or corruption (fasttop): 0x402dc258 *** Aborted $ The crash happens here: Program received signal SIGABRT, Aborted. 0x40070e78 in raise () from /lib/libc.so.6 Missing separate debuginfos, use: debuginfo-install glibc-2.16-34.olpc.0.fc18.armv7hl libgcc-4.7.2-8.fc18.armv7hl (gdb) bt #0 0x40070e78 in raise () from /lib/libc.so.6 #1 0x400724b8 in abort () from /lib/libc.so.6 #2 0x400ad6e0 in ?? () from /lib/libc.so.6 #3 0x400b54e8 in ?? () from /lib/libc.so.6 #4 0x2a00486c in pcm_hw_close () #5 0x2a0032e0 in pcm_close () #6 0x2a0016b0 in ctx_init () #7 0x2a000c98 in main () (gdb) The previous free was done here: Breakpoint 1, 0x400b8b8c in free () from /lib/libc.so.6 (gdb) bt #0 0x400b8b8c in free () from /lib/libc.so.6 #1 0x2a00486c in pcm_hw_close () #2 0x2a003674 in pcm_open () #3 0x2a0015e8 in ctx_init () #4 0x2a000c98 in main () (gdb) --- src/pcm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/pcm.c b/src/pcm.c index c28e098..c3807a7 100644 --- a/src/pcm.c +++ b/src/pcm.c @@ -898,7 +898,7 @@ struct pcm *pcm_open(unsigned int card, unsigned int device, if (!pcm->snd_node || pcm_type != SND_NODE_TYPE_PLUGIN) { oops(pcm, -ENODEV, "no device (hw/plugin) for card(%u), device(%u)", card, device); - return pcm; + goto fail_close; } pcm->ops = &plug_ops; pcm->fd = pcm->ops->open(card, device, flags, &pcm->data, pcm->snd_node); @@ -907,7 +907,7 @@ struct pcm *pcm_open(unsigned int card, unsigned int device, if (pcm->fd < 0) { oops(pcm, errno, "cannot open device (%u) for card (%u)", device, card); - return pcm; + goto fail_close; } pcm->flags = flags; @@ -954,9 +954,8 @@ fail_close: if (pcm->snd_node) snd_utils_close_dev_node(pcm->snd_node); #endif - pcm->ops->close(pcm->data); - pcm->fd = -1; - return pcm; + pcm_close(pcm); + return &bad_pcm; } /** Checks if a PCM file has been opened without error. -- cgit v1.2.3