Skip to content

Commit 04fa12b

Browse files
committed
stdlib: Fix unicode_util:gc/1 breaking binary continuations
The gc/1 fast-path for $\r was calling cp(R0) and returning [CP|T] when \r was not followed by \n. This "exploded" the binary tail into mixed chardata (integers + binary fragments), which downstream functions in string.erl (bin_search_loop, bin_search_inv_n) could not handle — they expect [BinR|Cont] when is_binary(BinR). This caused string:trim/3 to return wrong results or crash with {case_clause,[]} when trimming strings containing binaries followed by another list element, and the binary contained $\r not followed by $\n. Fix: return the original input (Str) instead of [CP|cp(R0)], consistent with what gc_1/1 already does. Closes #11380
1 parent c388a2d commit 04fa12b

3 files changed

Lines changed: 9 additions & 2 deletions

File tree

lib/stdlib/test/string_SUITE.erl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ trim(_) ->
327327
?TEST(["..h", ".e", <<"j..">>], [both, ". "], "h.ej"),
328328
?TEST(["..h", <<".ejsa"/utf8>>, "n.."], [both, ". "], "h.ejsan"),
329329
%% Test that it behaves with graphemes (i.e. nfd tests are the hard part)
330+
?TEST([<<"\r \r">>, []], [trailing, [$\r, [$\r, $\n]]], "\r "),
330331
?TEST([1013,101,778,101,101], [trailing, [101]], [1013,101,778]),
331332
?TEST("aaåaa", [both, "a"], "å"),
332333
?TEST(["aaa",778,"äöoo"], [both, "ao"], "åäö"),

lib/stdlib/test/unicode_util_SUITE.erl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ gc(Config) ->
123123
"hejsan" = fetch(["hej"|<<"san">>], Get),
124124
{error, <<128>>} = Get(<<128>>),
125125
{error, [<<128>>, 0]} = Get([<<128>>, 0]),
126+
[$\r, <<>>, []] = Get([<<$\r>>, []]),
127+
[$\r|<<$a>>] = Get(<<$\r,$a>>),
128+
[$\r|<<$a>>] = Get([<<$\r,$a>>]),
129+
[$\r, <<$a>>, []] = Get([<<$\r,$a>>, []]),
130+
[$\r, <<$a>>, <<>>] = Get([<<$\r,$a>>, <<>>]),
131+
126132

127133
{'EXIT', _} = catch Get([-1]),
128134
{'EXIT', _} = catch Get([-1, $a]),

lib/stdlib/uc_spec/gen_unicode_mod.escript

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -666,10 +666,10 @@ gen_gc(Fd, GBP) ->
666666
io:put_chars(Fd,
667667
"gc([]=R) -> R;\n"
668668
"gc([CP]=R) when ?IS_CP(CP) -> R;\n"
669-
"gc([$\\r=CP|R0]) ->\n"
669+
"gc([$\\r=CP|R0] = Str) ->\n"
670670
" case cp(R0) of % Don't break CRLF\n"
671671
" [$\\n|R1] -> [[$\\r,$\\n]|R1];\n"
672-
" T -> [CP|T]\n"
672+
" _ -> Str % Keep the tail binary\n"
673673
" end;\n"
674674
"gc([CP1|T1]=T) when ?IS_CP(CP1), CP1 < 256 ->\n"
675675
" case T1 of\n"

0 commit comments

Comments
 (0)