From 5eef2b910521a5df917574d1cde7f63502311dca Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 20 Feb 2017 13:44:08 +0000 Subject: [PATCH] Correctly handle mutation of the watcher list while iterating on them Fixes #1227 --- src/option_manager.cc | 9 +++++++-- test/regression/1227-segfault-on-option-access/cmd | 1 + test/regression/1227-segfault-on-option-access/in | 1 + test/regression/1227-segfault-on-option-access/out | 1 + test/regression/1227-segfault-on-option-access/rc | 10 ++++++++++ 5 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 test/regression/1227-segfault-on-option-access/cmd create mode 100644 test/regression/1227-segfault-on-option-access/in create mode 100644 test/regression/1227-segfault-on-option-access/out create mode 100644 test/regression/1227-segfault-on-option-access/rc diff --git a/src/option_manager.cc b/src/option_manager.cc index c8722c15..eb50bfcb 100644 --- a/src/option_manager.cc +++ b/src/option_manager.cc @@ -108,8 +108,13 @@ void OptionManager::on_option_changed(const Option& option) find_option(m_options, option.name()) != m_options.end()) return; - for (auto watcher : m_watchers) - watcher->on_option_changed(option); + // The watcher list might get mutated during calls to on_option_changed + auto watchers = m_watchers; + for (auto* watcher : watchers) + { + if (contains(m_watchers, watcher)) // make sure this watcher is still alive + watcher->on_option_changed(option); + } } CandidateList OptionsRegistry::complete_option_name(StringView prefix, diff --git a/test/regression/1227-segfault-on-option-access/cmd b/test/regression/1227-segfault-on-option-access/cmd new file mode 100644 index 00000000..1340e922 --- /dev/null +++ b/test/regression/1227-segfault-on-option-access/cmd @@ -0,0 +1 @@ +:test diff --git a/test/regression/1227-segfault-on-option-access/in b/test/regression/1227-segfault-on-option-access/in new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/regression/1227-segfault-on-option-access/in @@ -0,0 +1 @@ + diff --git a/test/regression/1227-segfault-on-option-access/out b/test/regression/1227-segfault-on-option-access/out new file mode 100644 index 00000000..b68fde2a --- /dev/null +++ b/test/regression/1227-segfault-on-option-access/out @@ -0,0 +1 @@ +k diff --git a/test/regression/1227-segfault-on-option-access/rc b/test/regression/1227-segfault-on-option-access/rc new file mode 100644 index 00000000..35f1dcd8 --- /dev/null +++ b/test/regression/1227-segfault-on-option-access/rc @@ -0,0 +1,10 @@ +decl str _ + +hook global BufCreate \*test\* %{ + hook buffer BufSetOption _=.+ 'exec "i%opt{_}"' +} + +def test %{ + edit -scratch *test* + set buffer=*test* _ "k" +}