Skip to content

Commit 280e2ef

Browse files
fix: prevent AMCP channel crash on Unicode/emoji in CG UPDATE (#1106) (#1707)
boost::log throws conversion_error when logging wide strings containing characters outside the system locale's encoding (e.g. emojis on C locale). Since this exception is unhandled in the AMCP protocol handler, it kills the connection. Fix by sanitizing log output with replace_nonprintable() in the three places where user-supplied wide strings are logged: - AMCPProtocolStrategy: received AMCP messages - html_producer: CEF console messages and renderer process messages - strategy_adapters: sent response messages Also replace boost::wformat with string concatenation in html_cg_proxy::update() to avoid a secondary crash path, and use explicit skip method for UTF-8 conversion to gracefully handle any invalid sequences. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 9646d11 commit 280e2ef

File tree

4 files changed

+15
-13
lines changed

4 files changed

+15
-13
lines changed

src/modules/html/producer/html_cg_proxy.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,9 @@ void html_cg_proxy::next(int layer) { producer_->call({L"next()"}); }
6060

6161
void html_cg_proxy::update(int layer, const std::wstring& data)
6262
{
63-
producer_->call({(boost::wformat(L"update(\"%1%\")") %
64-
boost::algorithm::replace_all_copy(
65-
boost::algorithm::trim_copy_if(data, boost::is_any_of(" \"")), "\"", "\\\""))
66-
.str()});
63+
auto escaped = boost::algorithm::replace_all_copy(
64+
boost::algorithm::trim_copy_if(data, boost::is_any_of(" \"")), "\"", "\\\"");
65+
producer_->call({L"update(\"" + escaped + L"\")"});
6766
}
6867

6968
std::wstring html_cg_proxy::invoke(int layer, const std::wstring& label)

src/modules/html/producer/html_producer.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -404,16 +404,17 @@ class html_client
404404
const CefString& source,
405405
int line) override
406406
{
407+
auto msg = log::replace_nonprintable_copy(message.ToWString(), L'?');
407408
if (level == cef_log_severity_t::LOGSEVERITY_DEBUG)
408-
CASPAR_LOG(debug) << print() << L" Log: " << message.ToWString();
409+
CASPAR_LOG(debug) << print() << L" Log: " << msg;
409410
else if (level == cef_log_severity_t::LOGSEVERITY_WARNING)
410-
CASPAR_LOG(warning) << print() << L" Log: " << message.ToWString();
411+
CASPAR_LOG(warning) << print() << L" Log: " << msg;
411412
else if (level == cef_log_severity_t::LOGSEVERITY_ERROR)
412-
CASPAR_LOG(error) << print() << L" Log: " << message.ToWString();
413+
CASPAR_LOG(error) << print() << L" Log: " << msg;
413414
else if (level == cef_log_severity_t::LOGSEVERITY_FATAL)
414-
CASPAR_LOG(fatal) << print() << L" Log: " << message.ToWString();
415+
CASPAR_LOG(fatal) << print() << L" Log: " << msg;
415416
else
416-
CASPAR_LOG(info) << print() << L" Log: " << message.ToWString();
417+
CASPAR_LOG(info) << print() << L" Log: " << msg;
417418
return true;
418419
}
419420

@@ -484,7 +485,7 @@ class html_client
484485
if (name == LOG_MESSAGE_NAME) {
485486
auto args = message->GetArgumentList();
486487
auto severity = static_cast<boost::log::trivial::severity_level>(args->GetInt(0));
487-
auto msg = args->GetString(1).ToWString();
488+
auto msg = log::replace_nonprintable_copy(args->GetString(1).ToWString(), L'?');
488489

489490
BOOST_LOG_SEV(log::logger::get(), severity) << print() << L" [renderer_process] " << msg;
490491
}

src/protocol/amcp/AMCPProtocolStrategy.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ class AMCPProtocolStrategy
140140
return;
141141
}
142142

143-
CASPAR_LOG(info) << L"Received message from " << client->address() << ": " << message << L"\\r\\n";
143+
CASPAR_LOG(info) << L"Received message from " << client->address() << ": "
144+
<< log::replace_nonprintable_copy(message, L'?') << L"\\r\\n";
144145

145146
std::wstring request_id;
146147
std::wstring command_name;

src/protocol/util/strategy_adapters.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class to_unicode_adapter : public protocol_strategy<char>
4242

4343
void parse(const std::basic_string<char>& data) override
4444
{
45-
auto utf_data = boost::locale::conv::to_utf<wchar_t>(data, codepage_);
45+
auto utf_data = boost::locale::conv::to_utf<wchar_t>(data, codepage_, boost::locale::conv::skip);
4646

4747
unicode_strategy_->parse(utf_data);
4848
}
@@ -73,7 +73,8 @@ class from_unicode_client_connection : public client_connection<wchar_t>
7373
if (data.length() < 512) {
7474
boost::replace_all(data, L"\n", L"\\n");
7575
boost::replace_all(data, L"\r", L"\\r");
76-
CASPAR_LOG(info) << L"Sent message to " << client_->address() << L":" << data;
76+
CASPAR_LOG(info) << L"Sent message to " << client_->address() << L":"
77+
<< log::replace_nonprintable_copy(data, L'?');
7778
} else
7879
CASPAR_LOG(info) << L"Sent more than 512 bytes to " << client_->address();
7980
}

0 commit comments

Comments
 (0)