fix(custom): validate JSON output UTF-8 and stop restart-interval:0 busy loop
- parseOutputJson() passed script text/alt/tooltip straight to Pango/GTK; an invalid-UTF-8 byte aborted the bar in g_utf8_collate. Validate/make_valid like parseOutputRaw already does. Fixes #2829. - restart-interval:0 was floored to 1ms, respawning the script ~1000x/s and starving the main loop; a non-positive restart-interval now stops instead. Part of #4842.
This commit is contained in:
+23
-10
@@ -105,7 +105,8 @@ void waybar::modules::Custom::continuousWorker() {
|
|||||||
dp.emit();
|
dp.emit();
|
||||||
spdlog::error("{} stopped unexpectedly, is it endless?", name_);
|
spdlog::error("{} stopped unexpectedly, is it endless?", name_);
|
||||||
}
|
}
|
||||||
if (config_["restart-interval"].isNumeric()) {
|
if (config_["restart-interval"].isNumeric() &&
|
||||||
|
config_["restart-interval"].asDouble() > 0) {
|
||||||
pid_ = -1;
|
pid_ = -1;
|
||||||
thread_.sleep_for(std::chrono::milliseconds(
|
thread_.sleep_for(std::chrono::milliseconds(
|
||||||
std::max(1L, // Minimum 1ms due to millisecond precision
|
std::max(1L, // Minimum 1ms due to millisecond precision
|
||||||
@@ -115,6 +116,8 @@ void waybar::modules::Custom::continuousWorker() {
|
|||||||
throw std::runtime_error("Unable to open " + cmd);
|
throw std::runtime_error("Unable to open " + cmd);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// A non-positive restart-interval must not busy-respawn the script
|
||||||
|
// (that starves the GTK main loop); treat it as "do not restart".
|
||||||
thread_.stop();
|
thread_.stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -316,22 +319,32 @@ void waybar::modules::Custom::parseOutputJson() {
|
|||||||
std::istringstream output(output_.out);
|
std::istringstream output(output_.out);
|
||||||
std::string line;
|
std::string line;
|
||||||
class_.clear();
|
class_.clear();
|
||||||
|
// A script can emit invalid UTF-8; passing it unchecked to Pango/GTK aborts
|
||||||
|
// the whole bar in g_utf8_* (see parseOutputRaw, which validates the same way).
|
||||||
|
auto sanitize = [](const std::string& s) -> Glib::ustring {
|
||||||
|
Glib::ustring value = s;
|
||||||
|
if (!value.validate()) {
|
||||||
|
value = value.make_valid();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
while (getline(output, line)) {
|
while (getline(output, line)) {
|
||||||
auto parsed = parser_.parse(line);
|
auto parsed = parser_.parse(line);
|
||||||
if (config_["escape"].isBool() && config_["escape"].asBool()) {
|
const bool escape = config_["escape"].isBool() && config_["escape"].asBool();
|
||||||
text_ = Glib::Markup::escape_text(parsed["text"].asString());
|
if (escape) {
|
||||||
|
text_ = Glib::Markup::escape_text(sanitize(parsed["text"].asString()));
|
||||||
} else {
|
} else {
|
||||||
text_ = parsed["text"].asString();
|
text_ = sanitize(parsed["text"].asString());
|
||||||
}
|
}
|
||||||
if (config_["escape"].isBool() && config_["escape"].asBool()) {
|
if (escape) {
|
||||||
alt_ = Glib::Markup::escape_text(parsed["alt"].asString());
|
alt_ = Glib::Markup::escape_text(sanitize(parsed["alt"].asString()));
|
||||||
} else {
|
} else {
|
||||||
alt_ = parsed["alt"].asString();
|
alt_ = sanitize(parsed["alt"].asString());
|
||||||
}
|
}
|
||||||
if (config_["escape"].isBool() && config_["escape"].asBool()) {
|
if (escape) {
|
||||||
tooltip_ = Glib::Markup::escape_text(parsed["tooltip"].asString());
|
tooltip_ = Glib::Markup::escape_text(sanitize(parsed["tooltip"].asString()));
|
||||||
} else {
|
} else {
|
||||||
tooltip_ = parsed["tooltip"].asString();
|
tooltip_ = sanitize(parsed["tooltip"].asString());
|
||||||
}
|
}
|
||||||
if (parsed["class"].isString()) {
|
if (parsed["class"].isString()) {
|
||||||
class_.push_back(parsed["class"].asString());
|
class_.push_back(parsed["class"].asString());
|
||||||
|
|||||||
Reference in New Issue
Block a user