aboutsummaryrefslogtreecommitdiffstats
path: root/util/format.lua
diff options
context:
space:
mode:
authorKim Alvefur <zash@zash.se>2021-12-11 13:30:34 +0100
committerKim Alvefur <zash@zash.se>2021-12-11 13:30:34 +0100
commit1eca4e8870f69699f7bc9bbd132a7bf64ca70918 (patch)
treef46fbc10f5c88e0a0468b41f9dc5718b5a7e9aec /util/format.lua
parentd4c145179420e6de0d2189059ea988072a7e7e45 (diff)
downloadprosody-1eca4e8870f69699f7bc9bbd132a7bf64ca70918.tar.gz
prosody-1eca4e8870f69699f7bc9bbd132a7bf64ca70918.zip
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.
Diffstat (limited to 'util/format.lua')
-rw-r--r--util/format.lua58
1 files changed, 37 insertions, 21 deletions
diff --git a/util/format.lua b/util/format.lua
index d452fd3d..8168ccaa 100644
--- a/util/format.lua
+++ b/util/format.lua
@@ -49,36 +49,52 @@ local function format(formatstring, ...)
-- process each format specifier
local i = 0;
formatstring = formatstring:gsub("%%[^cdiouxXaAeEfgGqs%%]*[cdiouxXaAeEfgGqs%%]", function(spec)
- if spec ~= "%%" then
- i = i + 1;
- local arg = args[i];
+ if spec == "%%" then return end
+ i = i + 1;
+ local arg = args[i];
+
+ if arg == nil then
+ args[i] = "nil";
+ return "(%s)";
+ end
+
+ local option = spec:sub(-1);
+ local t = type(arg);
+
+ if option == "s" and t == "string" and not arg:find("[%z\1-\31\128-\255]") then
+ -- No UTF-8 or control characters, assumed to be the common case.
+ return
+ end
- local option = spec:sub(-1);
- if arg == nil then
- args[i] = "nil";
- spec = "(%s)";
- elseif option == "q" then
- args[i] = dump(arg);
- spec = "%s";
- elseif option == "s" then
+ if option ~= "s" and option ~= "q" then
+ -- all other options expect numbers
+ if t ~= "number" then
+ -- arg isn't number as expected?
arg = tostring(arg);
- if arg:find("[\128-\255]") and not valid_utf8(arg) then
- args[i] = dump(arg);
- else
- args[i] = arg:gsub("[%z\1-\8\11-\31\127]", control_symbols):gsub("\n\t?", "\n\t");
- end
- elseif type(arg) ~= "number" then -- arg isn't number as expected?
- args[i] = tostring(arg);
- spec = "[%s]";
option = "s";
spec = "[%s]";
t = "string";
elseif expects_integer[option] and num_type(arg) ~= "integer" then
args[i] = tostring(arg);
- spec = "[%s]";
+ return "[%s]";
+ else
+ return -- acceptable number
+ end
+ end
+
+ if t == "string" then
+ if not valid_utf8(arg) then
+ option = "q";
+ else
+ args[i] = arg:gsub("[%z\1-\8\11-\31\127]", control_symbols):gsub("\n\t?", "\n\t");
+ return spec;
end
end
- return spec;
+
+ if option == "q" then
+ args[i] = dump(arg);
+ return "%s";
+ end
end);
-- process extra args