Skip to content

Commit

Permalink
Fix a problem where having duplicated blocks could result in endless …
Browse files Browse the repository at this point in the history
…recursion
  • Loading branch information
mworrell committed Dec 13, 2024
1 parent e992412 commit 33801c4
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 8 deletions.
45 changes: 37 additions & 8 deletions src/template_compiler.erl
Original file line number Diff line number Diff line change
Expand Up @@ -423,18 +423,33 @@ cs(Module, Filename, Options, Context) ->

compile_tokens({ok, {extends, {string_literal, _, Extend}, Elements}}, CState, _Options) ->
Blocks = find_blocks(Elements),
{Ws, BlockAsts} = compile_blocks(Blocks, CState),
{ok, {Extend, Ws#ws.includes, BlockAsts, undefined, Ws#ws.is_autoid_var}};
case check_duplicate_blocks(Blocks) of
ok ->
{Ws, BlockAsts} = compile_blocks(Blocks, CState),
{ok, {Extend, Ws#ws.includes, BlockAsts, undefined, Ws#ws.is_autoid_var}};
{error, _} = Error ->
Error
end;
compile_tokens({ok, {overrules, Elements}}, CState, _Options) ->
Blocks = find_blocks(Elements),
{Ws, BlockAsts} = compile_blocks(Blocks, CState),
{ok, {overrules, Ws#ws.includes, BlockAsts, undefined, Ws#ws.is_autoid_var}};
case check_duplicate_blocks(Blocks) of
ok ->
{Ws, BlockAsts} = compile_blocks(Blocks, CState),
{ok, {overrules, Ws#ws.includes, BlockAsts, undefined, Ws#ws.is_autoid_var}};
{error, _} = Error ->
Error
end;
compile_tokens({ok, {base, Elements}}, CState, _Options) ->
Blocks = find_blocks(Elements),
{Ws, BlockAsts} = compile_blocks(Blocks, CState),
CStateElts = CState#cs{blocks = BlockAsts},
{Ws1, TemplateAsts} = template_compiler_element:compile(Elements, CStateElts, Ws),
{ok, {undefined, Ws1#ws.includes, BlockAsts, TemplateAsts, Ws1#ws.is_autoid_var}};
case check_duplicate_blocks(Blocks) of
ok ->
{Ws, BlockAsts} = compile_blocks(Blocks, CState),
CStateElts = CState#cs{blocks = BlockAsts},
{Ws1, TemplateAsts} = template_compiler_element:compile(Elements, CStateElts, Ws),
{ok, {undefined, Ws1#ws.includes, BlockAsts, TemplateAsts, Ws1#ws.is_autoid_var}};
{error, _} = Error ->
Error
end;
compile_tokens({error, {Loc, template_compiler_parser, Msg}}, #cs{ filename = Filename }, Options) ->
% Try format the Yecc error
Err = split_loc(Loc),
Expand Down Expand Up @@ -522,6 +537,20 @@ block_elements({filter, _, Elts}) -> Elts;
block_elements(_) -> [].


check_duplicate_blocks(Blocks) ->
check_duplicate_blocks_1(Blocks, #{}).

check_duplicate_blocks_1([], _Acc) ->
ok;
check_duplicate_blocks_1([{block, {identifier, _Pos, Name}, _Elements}|Blocks], Acc) ->
case maps:is_key(Name, Acc) of
true ->
{error, {duplicate_block, Name}};
false ->
check_duplicate_blocks_1(Blocks, Acc#{ Name => true })
end.


%% @doc Optionally drop text before {% extends %} or {% overrules %}.
maybe_drop_text([{text, _SrcRef, _Text}|Rest], OrgTks) ->
maybe_drop_text(Rest, OrgTks);
Expand Down
5 changes: 5 additions & 0 deletions test/template_compiler_basic_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ groups() ->
,hello_world_block2_test
,hello_world_block3_test
,hello_world_comment_test
,block_nested_error_test
,block_render_test
,raw_test
]}].
Expand Down Expand Up @@ -72,6 +73,10 @@ hello_world_comment_test(_Config) ->
<<"Hello World!">> = iolist_to_binary(Bin),
ok.

block_nested_error_test(_Config) ->
{error, {duplicate_block, <<"main">>}} = template_compiler:render("block_nested_error.tpl", #{}, [], undefined),
ok.

block_render_test(_Config) ->
{ok, BinA} = template_compiler:render_block(a, "block_render.tpl", #{}, [], undefined),
<<"A">> = iolist_to_binary(BinA),
Expand Down
9 changes: 9 additions & 0 deletions test/test-data/block_nested_error.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% block main %}
Hallo
{% block test %}
Daar
{% block main %}
oops - a block with the same name
{% endblock %}
{% endblock %}
{% endblock%}

0 comments on commit 33801c4

Please sign in to comment.