Skip to content

Commit 4c69e26

Browse files
authored
Merge pull request #307 from thalesmg/20250422-fix-trailing-slash
fix: prevent trailing backslash from "eating" triple quotes
2 parents 32a3d0b + 0fc98c1 commit 4c69e26

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

src/hocon_scanner.xrl

+5-2
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,14 @@ Float = {Integer}?{Fraction}|{Integer}{Fraction}{Exponent}
5050

5151
%% String
5252
Hex = [0-9A-Fa-f]
53-
Escape = ["\\bfnrt]
53+
EscapeNoQuote = [\\bfnrt]
54+
Escape = "|{EscapeNoQuote}
5455
UnicodeEscape = u{Hex}{Hex}{Hex}{Hex}
5556
Char = ([^\"{LineFeed}]|\\{Escape}|\\{UnicodeEscape})
5657
String = "{Char}*"
57-
MultilineChar = ([^"]|"[^"]|""[^"]|\\{Escape}|\\{UnicodeEscape})
58+
%% Special handling for trailing quote: if we don't assert it's not followed by two other
59+
%% quotes, `{Escape}` would "eat" one of the quotes in the triple quote...
60+
MultilineChar = ([^"]|"[^"]|""[^"]|\\{EscapeNoQuote}|\\{UnicodeEscape})
5861
MultilineString = """{MultilineChar}*"""
5962
6063
%% Bytesize and Duration

test/hocon_pp_tests.erl

+25
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,31 @@ no_triple_quote_string_when_oneliner_test_() ->
334334
?_assertEqual([<<"root {a = \"a\\nb\"}">>], hocon_pp:do(Value, #{newline => <<>>}))
335335
].
336336

337+
%% Tests that having an one liner with characters that should be escaped do not interfere
338+
%% badly with other values which are triple quoted with indentation.
339+
%%
340+
%% At the time of writing, the below example does not trigger the original bug if only
341+
%% root2 is present and expected. Also, if the trailing backslash in root1 is removed, it
342+
%% also does not trigger the bug.
343+
triple_quote_string_ending_in_backslash_test() ->
344+
Raw = #{
345+
<<"root1">> => #{<<"x">> => <<"\t\"\\\"\\t\\">>},
346+
<<"root2">> => #{<<"x">> => <<"select \n from\n \"hello\" ">>}
347+
},
348+
Sc = #{
349+
roots => [root1, root2],
350+
fields => #{
351+
root1 => [{"x", hoconsc:mk(binary())}],
352+
root2 => [{"x", hoconsc:mk(binary())}]
353+
}
354+
},
355+
%% Parses fine.
356+
Raw = hocon_tconf:check_plain(Sc, Raw, #{}),
357+
PP = hocon_pp:do(Raw, #{}),
358+
%% Roundtrip: must read back the same thing.
359+
?assertEqual({ok, Raw}, hocon:binary(PP)),
360+
ok.
361+
337362
crlf_multiline_test_() ->
338363
Value = #{<<"root">> => #{<<"x">> => <<"\r\n\r\na\r\nb\n">>}},
339364
CRLF = <<"\r\n">>,

0 commit comments

Comments
 (0)