Mercurial > prosody-hg
comparison util/format.lua @ 12032:3db09eb4c43b
util.format: Ensure sanitation of strings passed to wrong format
Ie. log("debug", "%d", "\1\2\3") should not result in garbage.
Also optimizing for the common case of ASCII string passed to %s and
early returns everywhere.
Returning nil from a gsub callback keeps the original substring.
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Sat, 11 Dec 2021 13:30:34 +0100 |
| parents | 87bc26f23d9b |
| children | 161f8268c4b3 |
comparison
equal
deleted
inserted
replaced
| 12031:87bc26f23d9b | 12032:3db09eb4c43b |
|---|---|
| 47 | 47 |
| 48 | 48 |
| 49 -- process each format specifier | 49 -- process each format specifier |
| 50 local i = 0; | 50 local i = 0; |
| 51 formatstring = formatstring:gsub("%%[^cdiouxXaAeEfgGqs%%]*[cdiouxXaAeEfgGqs%%]", function(spec) | 51 formatstring = formatstring:gsub("%%[^cdiouxXaAeEfgGqs%%]*[cdiouxXaAeEfgGqs%%]", function(spec) |
| 52 if spec ~= "%%" then | 52 if spec == "%%" then return end |
| 53 i = i + 1; | 53 i = i + 1; |
| 54 local arg = args[i]; | 54 local arg = args[i]; |
| 55 | 55 |
| 56 local option = spec:sub(-1); | 56 if arg == nil then |
| 57 if arg == nil then | 57 args[i] = "nil"; |
| 58 args[i] = "nil"; | 58 return "(%s)"; |
| 59 spec = "(%s)"; | 59 end |
| 60 elseif option == "q" then | 60 |
| 61 args[i] = dump(arg); | 61 local option = spec:sub(-1); |
| 62 spec = "%s"; | 62 local t = type(arg); |
| 63 elseif option == "s" then | 63 |
| 64 if option == "s" and t == "string" and not arg:find("[%z\1-\31\128-\255]") then | |
| 65 -- No UTF-8 or control characters, assumed to be the common case. | |
| 66 return | |
| 67 end | |
| 68 | |
| 69 if option ~= "s" and option ~= "q" then | |
| 70 -- all other options expect numbers | |
| 71 if t ~= "number" then | |
| 72 -- arg isn't number as expected? | |
| 64 arg = tostring(arg); | 73 arg = tostring(arg); |
| 65 if arg:find("[\128-\255]") and not valid_utf8(arg) then | |
| 66 args[i] = dump(arg); | |
| 67 else | |
| 68 args[i] = arg:gsub("[%z\1-\8\11-\31\127]", control_symbols):gsub("\n\t?", "\n\t"); | |
| 69 end | |
| 70 elseif type(arg) ~= "number" then -- arg isn't number as expected? | |
| 71 args[i] = tostring(arg); | |
| 72 spec = "[%s]"; | |
| 73 option = "s"; | 74 option = "s"; |
| 74 spec = "[%s]"; | 75 spec = "[%s]"; |
| 75 t = "string"; | 76 t = "string"; |
| 76 elseif expects_integer[option] and num_type(arg) ~= "integer" then | 77 elseif expects_integer[option] and num_type(arg) ~= "integer" then |
| 77 args[i] = tostring(arg); | 78 args[i] = tostring(arg); |
| 78 spec = "[%s]"; | 79 return "[%s]"; |
| 80 else | |
| 81 return -- acceptable number | |
| 79 end | 82 end |
| 80 end | 83 end |
| 81 return spec; | 84 |
| 85 if t == "string" then | |
| 86 if not valid_utf8(arg) then | |
| 87 option = "q"; | |
| 88 else | |
| 89 args[i] = arg:gsub("[%z\1-\8\11-\31\127]", control_symbols):gsub("\n\t?", "\n\t"); | |
| 90 return spec; | |
| 91 end | |
| 92 end | |
| 93 | |
| 94 if option == "q" then | |
| 95 args[i] = dump(arg); | |
| 96 return "%s"; | |
| 97 end | |
| 82 end); | 98 end); |
| 83 | 99 |
| 84 -- process extra args | 100 -- process extra args |
| 85 while i < args_length do | 101 while i < args_length do |
| 86 i = i + 1; | 102 i = i + 1; |
