# HG changeset patch # User Kim Alvefur # Date 1623792263 -7200 # Node ID 5f4a657136bcc4d89d238e505d3398f4b4dff5fc # Parent 19cddf92fcc248f2d1ed39227c5fb5c1f9059290 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 diff -r 19cddf92fcc2 -r 5f4a657136bc spec/util_format_spec.lua --- 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); diff -r 19cddf92fcc2 -r 5f4a657136bc util/format.lua --- 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]";