From 45c729bd44f85bcb542afd0069fee851527b6ae3 Mon Sep 17 00:00:00 2001 From: Frank Hunleth Date: Thu, 4 Apr 2024 09:34:09 -0400 Subject: [PATCH] Don't crash on non-Unicode data This fixes an issue where ASCII data got passed through that was a little corrupt and it triggered a crash. This bulletproofs the flattening code against junk being logged. --- lib/ring_logger.ex | 18 +++++++++++++++++- test/ring_logger_test.exs | 25 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/ring_logger.ex b/lib/ring_logger.ex index b8f011b..ebbe5b9 100644 --- a/lib/ring_logger.ex +++ b/lib/ring_logger.ex @@ -328,6 +328,22 @@ defmodule RingLogger do end defp flatten({mod, msg, ts, md}) do - {mod, IO.chardata_to_string(msg), ts, md} + {mod, safe_chardata_to_string(msg), ts, md} + end + + defp safe_chardata_to_string(msg) do + IO.chardata_to_string(msg) + rescue + UnicodeConversionError -> + # ASCII? + safe_iodata_to_binary(msg) + end + + defp safe_iodata_to_binary(msg) do + IO.iodata_to_binary(msg) + rescue + ArgumentError -> + # Give up + inspect(msg) end end diff --git a/test/ring_logger_test.exs b/test/ring_logger_test.exs index 891521f..75bed58 100644 --- a/test/ring_logger_test.exs +++ b/test/ring_logger_test.exs @@ -555,6 +555,31 @@ defmodule RingLoggerTest do assert message =~ "[info] Cześć!" end + test "logging corrupt data", %{io: io} do + # This is non-Unicode and shouldn't crash RingLogger. There are slightly + # different paths that are taken for iodata vs binary data, so make sure + # they behave identically. + message_string = <<227, 97, 195, 253, 123, 50, 91, 116, 114, 227, 110>> + message = [message_string] + + :ok = RingLogger.attach(io: io) + Logger.debug(message_string) + assert_receive {:io, message_string_result} + + Logger.debug(message) + assert_receive {:io, message_result} + + assert message_result == message_string_result + assert message_result =~ "{2[tr" + end + + test "logging totally wrong data doesn't crash", %{io: io} do + :ok = RingLogger.attach(io: io) + Logger.info([[{1, 2, 3}]]) + assert_receive {:io, message} + assert message =~ "[info] cannot truncate chardata" + end + describe "fetching config" do test "can retrieve config for attached client", %{io: io} do :ok = RingLogger.attach(io: io)