Changeset

11638:5f4a657136bc

util.format: Escape ASCII control characters in output This should offer some protection against doing evil things to terminals. Doesn't protect against pure broken UTF-8 garbage however. See #734
author Kim Alvefur <zash@zash.se>
date Tue, 15 Jun 2021 23:24:23 +0200
parents 11637:19cddf92fcc2
children 11639:ad39528e647d
files spec/util_format_spec.lua util/format.lua
diffstat 2 files changed, 21 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/spec/util_format_spec.lua	Tue Jun 29 14:25:57 2021 +0100
+++ b/spec/util_format_spec.lua	Tue Jun 15 23:24:23 2021 +0200
@@ -15,5 +15,10 @@
 			assert.equal("[1.5]", format("%d", 1.5));
 			assert.equal("[7.3786976294838e+19]", format("%d", 73786976294838206464));
 		end);
+
+		it("escapes ascii control stuff", function ()
+			assert.equal("␁", format("%s", "\1"));
+		end);
+
 	end);
 end);
--- a/util/format.lua	Tue Jun 29 14:25:57 2021 +0100
+++ b/util/format.lua	Tue Jun 15 23:24:23 2021 +0200
@@ -13,6 +13,21 @@
 
 -- In Lua 5.3+ these formats throw an error if given a float
 local expects_integer = { c = true, d = true, i = true, o = true, u = true, X = true, x = true, };
+-- Printable Unicode replacements for control characters
+local control_symbols = {
+	-- 0x00 .. 0x1F --> U+2400 .. U+241F, 0x7F --> U+2421
+	["\000"] = "\226\144\128", ["\001"] = "\226\144\129", ["\002"] = "\226\144\130",
+	["\003"] = "\226\144\131", ["\004"] = "\226\144\132", ["\005"] = "\226\144\133",
+	["\006"] = "\226\144\134", ["\007"] = "\226\144\135", ["\008"] = "\226\144\136",
+	["\009"] = "\226\144\137", ["\010"] = "\226\144\138", ["\011"] = "\226\144\139",
+	["\012"] = "\226\144\140", ["\013"] = "\226\144\141", ["\014"] = "\226\144\142",
+	["\015"] = "\226\144\143", ["\016"] = "\226\144\144", ["\017"] = "\226\144\145",
+	["\018"] = "\226\144\146", ["\019"] = "\226\144\147", ["\020"] = "\226\144\148",
+	["\021"] = "\226\144\149", ["\022"] = "\226\144\150", ["\023"] = "\226\144\151",
+	["\024"] = "\226\144\152", ["\025"] = "\226\144\153", ["\026"] = "\226\144\154",
+	["\027"] = "\226\144\155", ["\028"] = "\226\144\156", ["\029"] = "\226\144\157",
+	["\030"] = "\226\144\158", ["\031"] = "\226\144\159", ["\127"] = "\226\144\161",
+};
 
 local function format(formatstring, ...)
 	local args = pack(...);
@@ -45,7 +60,7 @@
 				args[i] = dump(arg);
 				spec = "%s";
 			elseif option == "s" then
-				args[i] = tostring(arg);
+				args[i] = tostring(arg):gsub("[%z\1-31\127]", control_symbols);
 			elseif type(arg) ~= "number" then -- arg isn't number as expected?
 				args[i] = tostring(arg);
 				spec = "[%s]";