custom-graph: fix worker crash, JSON UTF-8 validation, SIGRTMIN guard
Bring src/modules/custom_graph.cpp in line with the hardened custom.cpp: - continuousWorker: on the restart path, an open() failure threw std::runtime_error out of the SleeperThread lambda, which escaped the thread and called std::terminate, killing all of Waybar. Log the error and stop the worker gracefully instead of throwing. - parseOutputJson: validate/make_valid the text/alt/tooltip JSON string fields before they reach fmt markup / set_tooltip_markup. Invalid UTF-8 from a script otherwise aborts the bar in g_utf8_* (parseOutputRaw already validated the same way). - refresh: wrap the SIGRTMIN-based signal check in #ifdef SIGRTMIN so the module builds on platforms without SIGRTMIN (e.g. some BSDs). Fixes a std::terminate crash on continuous-exec restart failure, an invalid-UTF-8 bar abort via JSON output, and a build break on platforms lacking SIGRTMIN.
This commit is contained in:
@@ -99,7 +99,13 @@ void waybar::modules::CustomGraph::continuousWorker() {
|
|||||||
thread_.sleep_for(std::chrono::seconds(config_["restart-interval"].asUInt()));
|
thread_.sleep_for(std::chrono::seconds(config_["restart-interval"].asUInt()));
|
||||||
fp_ = util::command::open(cmd, pid_, output_name_);
|
fp_ = util::command::open(cmd, pid_, output_name_);
|
||||||
if (!fp_) {
|
if (!fp_) {
|
||||||
throw std::runtime_error("Unable to open " + cmd);
|
// Letting this exception escape the SleeperThread would call
|
||||||
|
// std::terminate and kill all of Waybar. Degrade gracefully instead.
|
||||||
|
output_ = {1, ""};
|
||||||
|
dp.emit();
|
||||||
|
spdlog::error("Unable to restart {}: unable to open {}", name_, cmd);
|
||||||
|
thread_.stop();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thread_.stop();
|
thread_.stop();
|
||||||
@@ -139,9 +145,11 @@ void waybar::modules::CustomGraph::waitingWorker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::CustomGraph::refresh(int sig) {
|
void waybar::modules::CustomGraph::refresh(int sig) {
|
||||||
|
#ifdef SIGRTMIN
|
||||||
if (config_["signal"].isInt() && sig == SIGRTMIN + config_["signal"].asInt()) {
|
if (config_["signal"].isInt() && sig == SIGRTMIN + config_["signal"].asInt()) {
|
||||||
thread_.wake_up();
|
thread_.wake_up();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::CustomGraph::handleEvent() {
|
void waybar::modules::CustomGraph::handleEvent() {
|
||||||
@@ -268,22 +276,32 @@ void waybar::modules::CustomGraph::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