fix(alsa): Avoid dangling pointers

This commit is contained in:
Michael Carlberg 2016-12-09 22:53:26 +01:00
parent cab2d49532
commit b303492759
3 changed files with 67 additions and 36 deletions

View File

@ -72,10 +72,10 @@ class alsa_ctl_interface {
void process_events(); void process_events();
private: private:
int m_numid{0};
std::mutex m_lock; std::mutex m_lock;
int m_numid{0};
snd_hctl_t* m_hctl{nullptr}; snd_hctl_t* m_hctl{nullptr};
snd_hctl_elem_t* m_elem{nullptr}; snd_hctl_elem_t* m_elem{nullptr};
@ -90,7 +90,7 @@ class alsa_ctl_interface {
class alsa_mixer { class alsa_mixer {
public: public:
explicit alsa_mixer(const string& mixer_control_name); explicit alsa_mixer(string mixer_control_name);
~alsa_mixer(); ~alsa_mixer();
string get_name(); string get_name();
@ -107,10 +107,11 @@ class alsa_mixer {
bool is_muted(); bool is_muted();
private: private:
string m_name;
std::mutex m_lock; std::mutex m_lock;
string m_name;
snd_mixer_selem_id_t* m_mixerid{nullptr};
snd_mixer_t* m_hardwaremixer{nullptr}; snd_mixer_t* m_hardwaremixer{nullptr};
snd_mixer_elem_t* m_mixerelement{nullptr}; snd_mixer_elem_t* m_mixerelement{nullptr};
}; };

View File

@ -6,16 +6,20 @@ POLYBAR_NS
// class : alsa_ctl_interface {{{ // class : alsa_ctl_interface {{{
alsa_ctl_interface::alsa_ctl_interface(int numid) : m_numid(numid) { alsa_ctl_interface::alsa_ctl_interface(int numid) : m_numid(numid) {
snd_ctl_elem_info_alloca(&m_info); snd_ctl_elem_info_malloc(&m_info);
snd_ctl_elem_value_alloca(&m_value);
snd_ctl_elem_id_alloca(&m_id);
if (m_info == nullptr) { if (m_info == nullptr) {
throw alsa_ctl_interface_error("Failed to allocate alsa_ctl info"); throw alsa_ctl_interface_error("Failed to allocate alsa_ctl info");
} }
snd_ctl_elem_value_malloc(&m_value);
if (m_value == nullptr) { if (m_value == nullptr) {
throw alsa_ctl_interface_error("Failed to allocate alsa_ctl value"); throw alsa_ctl_interface_error("Failed to allocate alsa_ctl value");
} }
snd_ctl_elem_id_malloc(&m_id);
if (m_id == nullptr) { if (m_id == nullptr) {
throw alsa_ctl_interface_error("Failed to allocate alsa_ctl id"); throw alsa_ctl_interface_error("Failed to allocate alsa_ctl id");
} }
@ -25,22 +29,28 @@ alsa_ctl_interface::alsa_ctl_interface(int numid) : m_numid(numid) {
int err = 0; int err = 0;
if ((err = snd_ctl_open(&m_ctl, ALSA_SOUNDCARD, SND_CTL_NONBLOCK | SND_CTL_READONLY)) < 0) { if ((err = snd_ctl_open(&m_ctl, ALSA_SOUNDCARD, SND_CTL_NONBLOCK | SND_CTL_READONLY)) == -1) {
throw_exception<alsa_ctl_interface_error>("Could not open control '" + string{ALSA_SOUNDCARD} + "'", err); throw_exception<alsa_ctl_interface_error>("Could not open control '" + string{ALSA_SOUNDCARD} + "'", err);
} }
snd_config_update_free_global();
if ((err = snd_ctl_elem_info(m_ctl, m_info)) < 0) { if ((err = snd_ctl_elem_info(m_ctl, m_info)) < 0) {
throw_exception<alsa_ctl_interface_error>("Could not get control datal", err); throw_exception<alsa_ctl_interface_error>("Could not get control datal", err);
} }
snd_ctl_elem_info_get_id(m_info, m_id); snd_ctl_elem_info_get_id(m_info, m_id);
if ((err = snd_hctl_open(&m_hctl, ALSA_SOUNDCARD, 0)) < 0) { if ((err = snd_hctl_open(&m_hctl, ALSA_SOUNDCARD, 0)) == -1) {
throw_exception<alsa_ctl_interface_error>("Failed to open hctl", err); throw_exception<alsa_ctl_interface_error>("Failed to open hctl", err);
} }
snd_config_update_free_global();
if (m_hctl == nullptr || (err = snd_hctl_load(m_hctl)) < 0) { if (m_hctl == nullptr || (err = snd_hctl_load(m_hctl)) < 0) {
throw_exception<alsa_ctl_interface_error>("Failed to load hctl", err); throw_exception<alsa_ctl_interface_error>("Failed to load hctl", err);
} }
if ((m_elem = snd_hctl_find_elem(m_hctl, m_id)) == nullptr) { if ((m_elem = snd_hctl_find_elem(m_hctl, m_id)) == nullptr) {
throw alsa_ctl_interface_error("Could not find control with id " + to_string(snd_ctl_elem_id_get_numid(m_id))); throw alsa_ctl_interface_error("Could not find control with id " + to_string(snd_ctl_elem_id_get_numid(m_id)));
} }
@ -52,8 +62,21 @@ alsa_ctl_interface::alsa_ctl_interface(int numid) : m_numid(numid) {
alsa_ctl_interface::~alsa_ctl_interface() { alsa_ctl_interface::~alsa_ctl_interface() {
std::lock_guard<std::mutex> guard(m_lock); std::lock_guard<std::mutex> guard(m_lock);
snd_ctl_close(m_ctl); if (m_info != nullptr) {
snd_hctl_close(m_hctl); snd_ctl_elem_info_free(m_info);
}
if (m_value != nullptr) {
snd_ctl_elem_value_free(m_value);
}
if (m_id != nullptr) {
snd_ctl_elem_id_free(m_id);
}
if (m_ctl != nullptr) {
snd_ctl_close(m_ctl);
}
if (m_hctl != nullptr) {
snd_hctl_close(m_hctl);
}
} }
int alsa_ctl_interface::get_numid() { int alsa_ctl_interface::get_numid() {
@ -71,23 +94,22 @@ bool alsa_ctl_interface::wait(int timeout) {
int err = 0; int err = 0;
if ((err = snd_ctl_wait(m_ctl, timeout)) < 0) { if ((err = snd_ctl_wait(m_ctl, timeout)) == -1) {
throw_exception<alsa_ctl_interface_error>("Failed to wait for events", err); throw_exception<alsa_ctl_interface_error>("Failed to wait for events", err);
} }
snd_ctl_event_t* event; snd_ctl_event_t* event;
snd_ctl_event_alloca(&event); snd_ctl_event_alloca(&event);
if ((err = snd_ctl_read(m_ctl, event)) < 0) { if ((err = snd_ctl_read(m_ctl, event)) == -1) {
return false;
}
if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM) {
return false; return false;
} }
auto mask = snd_ctl_event_elem_get_mask(event); if (snd_ctl_event_get_type(event) == SND_CTL_EVENT_ELEM) {
return snd_ctl_event_elem_get_mask(event) & SND_CTL_EVENT_MASK_VALUE;
}
return mask & SND_CTL_EVENT_MASK_VALUE; return false;
} }
bool alsa_ctl_interface::test_device_plugged() { bool alsa_ctl_interface::test_device_plugged() {
@ -114,37 +136,38 @@ void alsa_ctl_interface::process_events() {
// }}} // }}}
// class : alsa_mixer {{{ // class : alsa_mixer {{{
alsa_mixer::alsa_mixer(const string& mixer_control_name) : m_name(mixer_control_name) { alsa_mixer::alsa_mixer(string mixer_control_name) : m_name(move(mixer_control_name)) {
if (m_name.empty()) { if (m_name.empty()) {
throw alsa_mixer_error("Invalid control name"); throw alsa_mixer_error("Invalid control name");
} }
snd_mixer_selem_id_t* mixer_id{nullptr}; snd_mixer_selem_id_malloc(&m_mixerid);
snd_mixer_selem_id_alloca(&mixer_id);
if (mixer_id == nullptr) { if (m_mixerid == nullptr) {
throw alsa_mixer_error("Failed to allocate mixer id"); throw alsa_mixer_error("Failed to allocate mixer id");
} }
int err = 0; int err = 0;
if ((err = snd_mixer_open(&m_hardwaremixer, 1)) == -1) {
if ((err = snd_mixer_open(&m_hardwaremixer, 1)) < 0) {
throw_exception<alsa_mixer_error>("Failed to open hardware mixer", err); throw_exception<alsa_mixer_error>("Failed to open hardware mixer", err);
} }
if ((err = snd_mixer_attach(m_hardwaremixer, ALSA_SOUNDCARD)) < 0) {
snd_config_update_free_global();
if ((err = snd_mixer_attach(m_hardwaremixer, ALSA_SOUNDCARD)) == -1) {
throw_exception<alsa_mixer_error>("Failed to attach hardware mixer control", err); throw_exception<alsa_mixer_error>("Failed to attach hardware mixer control", err);
} }
if ((err = snd_mixer_selem_register(m_hardwaremixer, nullptr, nullptr)) < 0) { if ((err = snd_mixer_selem_register(m_hardwaremixer, nullptr, nullptr)) == -1) {
throw_exception<alsa_mixer_error>("Failed to register simple mixer element", err); throw_exception<alsa_mixer_error>("Failed to register simple mixer element", err);
} }
if ((err = snd_mixer_load(m_hardwaremixer)) < 0) { if ((err = snd_mixer_load(m_hardwaremixer)) == -1) {
throw_exception<alsa_mixer_error>("Failed to load mixer", err); throw_exception<alsa_mixer_error>("Failed to load mixer", err);
} }
snd_mixer_selem_id_set_index(mixer_id, 0); snd_mixer_selem_id_set_index(m_mixerid, 0);
snd_mixer_selem_id_set_name(mixer_id, m_name.c_str()); snd_mixer_selem_id_set_name(m_mixerid, m_name.c_str());
if ((m_mixerelement = snd_mixer_find_selem(m_hardwaremixer, mixer_id)) == nullptr) { if ((m_mixerelement = snd_mixer_find_selem(m_hardwaremixer, m_mixerid)) == nullptr) {
throw alsa_mixer_error("Cannot find simple element"); throw alsa_mixer_error("Cannot find simple element");
} }
@ -153,9 +176,16 @@ alsa_mixer::alsa_mixer(const string& mixer_control_name) : m_name(mixer_control_
alsa_mixer::~alsa_mixer() { alsa_mixer::~alsa_mixer() {
std::lock_guard<std::mutex> guard(m_lock); std::lock_guard<std::mutex> guard(m_lock);
snd_mixer_elem_remove(m_mixerelement); if (m_mixerid != nullptr) {
snd_mixer_detach(m_hardwaremixer, ALSA_SOUNDCARD); snd_mixer_selem_id_free(m_mixerid);
snd_mixer_close(m_hardwaremixer); }
if (m_mixerelement != nullptr) {
snd_mixer_elem_free(m_mixerelement);
}
if (m_hardwaremixer != nullptr) {
snd_mixer_detach(m_hardwaremixer, ALSA_SOUNDCARD);
snd_mixer_close(m_hardwaremixer);
}
} }
string alsa_mixer::get_name() { string alsa_mixer::get_name() {
@ -173,7 +203,7 @@ bool alsa_mixer::wait(int timeout) {
int err = 0; int err = 0;
if ((err = snd_mixer_wait(m_hardwaremixer, timeout)) < 0) { if ((err = snd_mixer_wait(m_hardwaremixer, timeout)) == -1) {
throw_exception<alsa_mixer_error>("Failed to wait for events", err); throw_exception<alsa_mixer_error>("Failed to wait for events", err);
} }
@ -190,7 +220,6 @@ int alsa_mixer::process_events() {
std::lock_guard<std::mutex> guard(m_lock, std::adopt_lock); std::lock_guard<std::mutex> guard(m_lock, std::adopt_lock);
int num_events = snd_mixer_handle_events(m_hardwaremixer); int num_events = snd_mixer_handle_events(m_hardwaremixer);
if (num_events < 0) { if (num_events < 0) {
throw_exception<alsa_mixer_error>("Failed to process pending events", num_events); throw_exception<alsa_mixer_error>("Failed to process pending events", num_events);
} }

View File

@ -80,6 +80,7 @@ namespace modules {
void volume_module::teardown() { void volume_module::teardown() {
m_mixer.clear(); m_mixer.clear();
m_ctrl.clear();
} }
bool volume_module::has_event() { bool volume_module::has_event() {