Fix infinite parse of recursive definitions

Fixed the infinite parse (and eventually segfault) of recursive definitions.
Also fixed the parse of a string slave PCM of direct plugins.
This commit is contained in:
Takashi Iwai 2006-01-30 14:41:51 +00:00
parent bf174b7046
commit eccc92a34d
29 changed files with 127 additions and 36 deletions

View file

@ -249,4 +249,9 @@ void *snd_dlobj_cache_lookup(const char *name);
int snd_dlobj_cache_add(const char *name, void *dlobj, void *open_func);
void snd_dlobj_cache_cleanup(void);
/* for recursive checks */
void snd_config_set_hop(snd_config_t *conf, int hop);
int snd_config_check_hop(snd_config_t *conf);
#define SND_CONF_MAX_HOPS 64
#endif

View file

@ -440,6 +440,7 @@ struct _snd_config {
} u;
struct list_head list;
snd_config_t *father;
int hop;
};
struct filedesc {
@ -4011,6 +4012,24 @@ int snd_config_search_definition(snd_config_t *config,
return snd_config_expand(conf, config, args, NULL, result);
}
#ifndef DOC_HIDDEN
void snd_config_set_hop(snd_config_t *conf, int hop)
{
conf->hop = hop;
}
int snd_config_check_hop(snd_config_t *conf)
{
if (conf) {
if (conf->hop >= SND_CONF_MAX_HOPS) {
SYSERR("Too many definition levels (looped?)\n");
return -EINVAL;
}
return conf->hop;
}
return 0;
}
#endif
#if 0
/* Not strictly needed, but useful to check for memory leaks */

View file

@ -2098,7 +2098,8 @@ static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name,
}
static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root,
const char *name, snd_pcm_stream_t stream, int mode)
const char *name, snd_pcm_stream_t stream,
int mode, int hop)
{
int err;
snd_config_t *pcm_conf;
@ -2107,6 +2108,7 @@ static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root,
SNDERR("Unknown PCM %s", name);
return err;
}
snd_config_set_hop(pcm_conf, hop);
err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode);
snd_config_delete(pcm_conf);
return err;
@ -2128,7 +2130,7 @@ int snd_pcm_open(snd_pcm_t **pcmp, const char *name,
err = snd_config_update();
if (err < 0)
return err;
return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode);
return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode, 0);
}
/**
@ -2145,7 +2147,7 @@ int snd_pcm_open_lconf(snd_pcm_t **pcmp, const char *name,
snd_config_t *lconf)
{
assert(pcmp && name && lconf);
return snd_pcm_open_noupdate(pcmp, lconf, name, stream, mode);
return snd_pcm_open_noupdate(pcmp, lconf, name, stream, mode, 0);
}
#ifndef DOC_HIDDEN
@ -2187,11 +2189,16 @@ int snd_pcm_free(snd_pcm_t *pcm)
int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
snd_config_t *conf, snd_pcm_stream_t stream,
int mode)
int mode, snd_config_t *parent_conf)
{
const char *str;
int hop;
if ((hop = snd_config_check_hop(parent_conf)) < 0)
return hop;
if (snd_config_get_string(conf, &str) >= 0)
return snd_pcm_open_noupdate(pcmp, root, str, stream, mode);
return snd_pcm_open_noupdate(pcmp, root, str, stream, mode,
hop + 1);
return snd_pcm_open_conf(pcmp, NULL, root, conf, stream, mode);
}
#endif

View file

@ -666,7 +666,7 @@ int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name,
SNDERR("invalid slave format");
return -EINVAL;
}
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -538,7 +538,7 @@ int _snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name,
SNDERR("invalid slave format");
return -EINVAL;
}
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -109,7 +109,7 @@ int _snd_pcm_asym_open(snd_pcm_t **pcmp, const char *name ATTRIBUTE_UNUSED,
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0)
return err;
err = snd_pcm_open_slave(pcmp, root, sconf, stream, mode);
err = snd_pcm_open_slave(pcmp, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
return err;
}

View file

@ -284,7 +284,7 @@ int _snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name,
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0)
return err;
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -1260,11 +1260,34 @@ int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg)
/*
* parse slave config and calculate the ipc_key offset
*/
int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction)
static int _snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root,
snd_config_t *sconf,
int direction,
int hop)
{
snd_config_iterator_t i, next;
int err;
long card = 0, device = 0, subdevice = 0;
const char *str;
if (snd_config_get_string(sconf, &str) >= 0) {
snd_config_t *pcm_conf;
if (hop > SND_CONF_MAX_HOPS) {
SNDERR("Too many definition levels (looped?)");
return -EINVAL;
}
err = snd_config_search_definition(root, "pcm", str, &pcm_conf);
if (err < 0) {
SNDERR("Unknown slave PCM %s", str);
return err;
}
err = _snd_pcm_direct_get_slave_ipc_offset(root, pcm_conf,
direction,
hop + 1);
snd_config_delete(pcm_conf);
return err;
}
snd_config_for_each(i, next, sconf) {
snd_config_t *n = snd_config_iterator_entry(i);
@ -1325,6 +1348,12 @@ int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction)
return direction + (card << 1) + (device << 4) + (subdevice << 8);
}
int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root,
snd_config_t *sconf,
int direction)
{
return _snd_pcm_direct_get_slave_ipc_offset(root, sconf, direction, 0);
}
int snd_pcm_direct_parse_open_conf(snd_config_t *conf, struct snd_pcm_direct_open_conf *rec)
{

View file

@ -186,7 +186,7 @@ int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix);
void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix);
int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name);
int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction);
int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root, snd_config_t *sconf, int direction);
int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);

View file

@ -847,7 +847,10 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
if (first_instance) {
ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode | SND_PCM_NONBLOCK);
/* recursion is already checked in
snd_pcm_direct_get_slave_ipc_offset() */
ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
mode | SND_PCM_NONBLOCK, NULL);
if (ret < 0) {
SNDERR("unable to open slave");
goto _err;
@ -1124,7 +1127,7 @@ int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
params.period_size = psize;
params.buffer_size = bsize;
ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream);
ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream);
if (ipc_offset < 0) {
snd_config_delete(sconf);
return ipc_offset;

View file

@ -672,7 +672,10 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
dshare->sync_ptr = snd_pcm_dshare_sync_ptr;
if (first_instance) {
ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode | SND_PCM_NONBLOCK);
/* recursion is already checked in
snd_pcm_direct_get_slave_ipc_offset() */
ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
mode | SND_PCM_NONBLOCK, NULL);
if (ret < 0) {
SNDERR("unable to open slave");
goto _err;
@ -873,7 +876,7 @@ int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
params.period_size = psize;
params.buffer_size = bsize;
ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream);
ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream);
if (ipc_offset < 0) {
snd_config_delete(sconf);
return ipc_offset;

View file

@ -554,7 +554,10 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
if (first_instance) {
ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode | SND_PCM_NONBLOCK);
/* recursion is already checked in
snd_pcm_direct_get_slave_ipc_offset() */
ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
mode | SND_PCM_NONBLOCK, NULL);
if (ret < 0) {
SNDERR("unable to open slave");
goto _err;
@ -745,7 +748,7 @@ int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
params.period_size = psize;
params.buffer_size = bsize;
ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream);
ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream);
if (ipc_offset < 0) {
snd_config_delete(sconf);
return ipc_offset;

View file

@ -622,7 +622,7 @@ int snd_pcm_extplug_create(snd_pcm_extplug_t *extplug, const char *name,
err = snd_pcm_slave_conf(root, slave_conf, &sconf, 0);
if (err < 0)
return err;
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, NULL);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -556,7 +556,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
SNDERR("file is not defined");
return -EINVAL;
}
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -460,7 +460,7 @@ int _snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name,
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0)
return err;
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -662,7 +662,7 @@ int _snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name,
SNDERR("invalid slave format");
return -EINVAL;
}
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -1782,7 +1782,7 @@ int _snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name,
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0)
return err;
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -497,7 +497,7 @@ int _snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name,
SNDERR("slave format is not linear integer or linear float");
return -EINVAL;
}
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -552,7 +552,7 @@ int _snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name,
SNDERR("slave format is not linear");
return -EINVAL;
}
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -748,7 +748,7 @@ int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf,
int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
snd_config_t *conf, snd_pcm_stream_t stream,
int mode);
int mode, snd_config_t *parent_conf);
int snd_pcm_conf_generic_id(const char *id);
int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, int mmap_emulation, int sync_ptr_ioctl);

View file

@ -779,7 +779,7 @@ int _snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name,
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0)
return err;
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -553,7 +553,7 @@ int _snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name,
SNDERR("invalid slave format");
return -EINVAL;
}
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -1103,7 +1103,9 @@ int _snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name,
}
for (idx = 0; idx < slaves_count; ++idx) {
err = snd_pcm_open_slave(&slaves_pcm[idx], root, slaves_conf[idx], stream, mode);
err = snd_pcm_open_slave(&slaves_pcm[idx], root,
slaves_conf[idx], stream, mode,
conf);
if (err < 0)
goto _free;
snd_config_delete(slaves_conf[idx]);

View file

@ -1215,7 +1215,7 @@ int _snd_pcm_plug_open(snd_pcm_t **pcmp, const char *name,
}
#endif
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -1532,7 +1532,7 @@ int _snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name,
SNDERR("slave format is not linear");
return -EINVAL;
}
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -1152,7 +1152,7 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
return err;
}
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0) {
free(ttable);

View file

@ -814,7 +814,7 @@ int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name,
snd_config_delete(sconf);
return -EINVAL;
}
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
if (err < 0)
return err;

View file

@ -53,6 +53,10 @@ typedef struct {
snd_seq_event_t out_event;
int pending;
} snd_rawmidi_virtual_t;
int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name,
int streams, int mode, snd_config_t *lconf,
snd_config_t *parent_conf);
#endif
static int snd_rawmidi_virtual_close(snd_rawmidi_t *rmidi)
@ -439,7 +443,8 @@ int _snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
if (! slave_str)
slave_str = "default";
err = snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode, root);
err = _snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode,
root, conf);
if (err < 0)
return err;

View file

@ -919,7 +919,8 @@ static int snd_seq_open_conf(snd_seq_t **seqp, const char *name,
}
static int snd_seq_open_noupdate(snd_seq_t **seqp, snd_config_t *root,
const char *name, int streams, int mode)
const char *name, int streams, int mode,
int hop)
{
int err;
snd_config_t *seq_conf;
@ -928,6 +929,7 @@ static int snd_seq_open_noupdate(snd_seq_t **seqp, snd_config_t *root,
SNDERR("Unknown SEQ %s", name);
return err;
}
snd_config_set_hop(seq_conf, hop);
err = snd_seq_open_conf(seqp, name, root, seq_conf, streams, mode);
snd_config_delete(seq_conf);
return err;
@ -971,7 +973,7 @@ int snd_seq_open(snd_seq_t **seqp, const char *name,
err = snd_config_update();
if (err < 0)
return err;
return snd_seq_open_noupdate(seqp, snd_config, name, streams, mode);
return snd_seq_open_noupdate(seqp, snd_config, name, streams, mode, 0);
}
/**
@ -993,9 +995,22 @@ int snd_seq_open_lconf(snd_seq_t **seqp, const char *name,
int streams, int mode, snd_config_t *lconf)
{
assert(seqp && name && lconf);
return snd_seq_open_noupdate(seqp, lconf, name, streams, mode);
return snd_seq_open_noupdate(seqp, lconf, name, streams, mode, 0);
}
#ifndef DOC_HIDDEN
int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name,
int streams, int mode, snd_config_t *lconf,
snd_config_t *parent_conf)
{
int hop;
assert(seqp && name && lconf);
if ((hop = snd_config_check_hop(parent_conf)) < 0)
return hop;
return snd_seq_open_noupdate(seqp, lconf, name, streams, mode, hop + 1);
}
#endif
/**
* \brief Close the sequencer
* \param seq Handle returned from #snd_seq_open()