Bug 2087786 - @ALSA_0.9 symbols from pcm_old.h public header get resolved to 1.0 version causing crashes
Summary: @ALSA_0.9 symbols from pcm_old.h public header get resolved to 1.0 version ca...
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Fedora
Classification: Fedora
Component: alsa-lib
Version: 36
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Jaroslav Kysela
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2022-05-18 13:56 UTC by Hans de Goede
Modified: 2022-05-18 21:15 UTC (History)
2 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2022-05-18 14:02:49 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Hans de Goede 2022-05-18 13:56:27 UTC
This bug is the result of analyzing a timidity crash reported in bug 1993671.

The timidity alsa_a.c code uses:

#define ALSA_PCM_OLD_HW_PARAMS_API
#define ALSA_PCM_OLD_SW_PARAMS_API
#include <alsa/asoundlib.h>

And when using timidity's alsa output plugin things crash with a NULL pointer deref in snd_pcm_hw_param_set_near() aka snd1_pcm_hw_param_set_near() caused by the unsigned int *val argument being NULL.

This suggests that timidity is directly calling the alsa-lib-1.0 version of snd_pcm_hw_params_set_rate_near() rather then getting the snd_pcm_hw_params_set_rate_near version as it should since /usr/include/alsa/pcm_old.h does:

asm(".symver snd_pcm_hw_params_set_rate_near,snd_pcm_hw_params_set_rate_near");
unsigned int snd_pcm_hw_params_set_rate_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir);


To prove this theory I've build alsa-lib from source and installed it as my system alsa-lib with this patch:

diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 9aec52d1..19b18d7f 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -4777,6 +4777,7 @@ EXPORT_SYMBOL int INTERNAL(snd_pcm_hw_params_set_rate_near)(snd_pcm_t *pcm, snd_
 int snd_pcm_hw_params_set_rate_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
 #endif
 {
+	printf("snd_pcm_hw_params_set_rate_near called, val %p\n", val);
 	return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_RATE, val, dir);
 }
 
@@ -7918,6 +7919,7 @@ EXPORT_SYMBOL ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, re
 #define __P_OLD_NEAR1(pfx, name, ret_type) \
 EXPORT_SYMBOL ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ret_type val, int *dir) \
 { \
+       printf("__P_OLD_NEAR1 %s called val %d\n", #name, (int)val); \
 	if (INTERNAL(name)(pcm, params, &val, dir) < 0) \
 		return 0; \
 	return (ret_type)val; \

And then running: "timidity -Os somefile.mid" to reproduce I get:

snd_pcm_hw_params_set_rate_near called, val (nil)
Segmentation fault (core dumped)

Note that the printf in the __P_OLD_NEAR1 wrapper for the 0.9 alsa-lib version of snd_pcm_hw_params_set_rate_near does not trigger, proving the theory.

So something is going wrong with the symbol versioning, either on the alsa-lib side, or for some reason timidity is not honoring the asm .symver statement in pcm_old.h .

Comment 1 Hans de Goede 2022-05-18 14:02:49 UTC
> So something is going wrong with the symbol versioning, either on the alsa-lib side, or for some reason timidity is not honoring the asm .symver statement in pcm_old.h .

So this made me realize that pcm_old.h has the:

asm(".symver snd_pcm_hw_params_set_rate_near,snd_pcm_hw_params_set_rate_near");

Before the:

unsigned int snd_pcm_hw_params_set_rate_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir);

Prototype and I just realized that with link time optimization (LTO) enabled all .c files essentially become 1 big file, so what if another .c file in timidity does:

#include <alsa/asoundlib.h>

Without doing:

#define ALSA_PCM_OLD_HW_PARAMS_API
#define ALSA_PCM_OLD_SW_PARAMS_API

First, then the (wrong) prototype shows up first without being prefixed by the asm .symver and maybe that is causing timidity to get the wrong version of the function.

So I've tried adding:

%global _lto_cflags %nil

To timidity++.spec and that indeed fixes things.

Sorry for the noise, but hopefully this will be helpful to explain some other similar bugs... ?

Comment 2 Jaroslav Kysela 2022-05-18 14:05:02 UTC
Yep, LTO is always a problem. Just for the record: It's easy to verify the referenced symbol:

  # objdump -t /usr/bin/timidity | grep set_rate_near
  0000000000000000       F *UND*	0000000000000000 snd_pcm_hw_params_set_rate_near.0rc4

Comment 3 Hans de Goede 2022-05-18 15:09:59 UTC
Note I've filed a gcc bug, where the symbol-ver vs LTO issues are being discussed in more detail, see bug 2087904.

It looks like this may be an alsa-lib issue after all, requiring some changes to the pcm_old.h alsa-lib header, but this is still being discussed.


Note You need to log in before you can comment on or make changes to this bug.