Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:23
erlang
0229-stdlib-Correct-evaluation-order-when-creat...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0229-stdlib-Correct-evaluation-order-when-creating-bitstr.patch of Package erlang
From a6bd8264bf7594dc6711396cdbccef67a0e94e40 Mon Sep 17 00:00:00 2001 From: Hans Bolinder <hasse@erlang.org> Date: Mon, 12 Oct 2020 13:21:30 +0200 Subject: [PATCH 2/2] stdlib: Correct evaluation order when creating bitstrings The evaluation of bitstring creation separates the evaluation of values and sizes from the creation of binaries in order to get the same error messages as output by the compiler. It could even happen that compiled code got stuck in a loop while interpreted code failed. --- lib/stdlib/src/eval_bits.erl | 53 +++++++++++++++++++----------- lib/stdlib/test/erl_eval_SUITE.erl | 6 +++- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/lib/stdlib/src/eval_bits.erl b/lib/stdlib/src/eval_bits.erl index 157d823a09..35eca359dc 100644 --- a/lib/stdlib/src/eval_bits.erl +++ b/lib/stdlib/src/eval_bits.erl @@ -64,39 +64,54 @@ convert_list(List) -> expr_grp(Fields, Bindings, EvalFun) -> expr_grp(Fields, Bindings, EvalFun, <<>>). -expr_grp([Field | FS], Bs0, Lf, Acc) -> - {Bin,Bs} = eval_field(Field, Bs0, Lf), - expr_grp(FS, Bs, Lf, <<Acc/binary-unit:1,Bin/binary-unit:1>>); -expr_grp([], Bs0, _Lf, Acc) -> - {value,Acc,Bs0}. +expr_grp(FS, Bs0, Ef, Acc) -> + %% Separate the evaluation of values, sizes, and TLS:s from the + %% creation of the binary in order to mimic compiled code when it + %% comes to loops and failures. + {ListOfEvalField,Bs1} = expr_grp1(FS, Bs0, Ef, []), + {value,create_binary(ListOfEvalField, Acc),Bs1}. + +expr_grp1([Field | FS], Bs0, Ef, ListOfEvalField) -> + {EvalField,Bs} = eval_field(Field, Bs0, Ef), + expr_grp1(FS, Bs, Ef, [EvalField|ListOfEvalField]); +expr_grp1([], Bs, _Ef, ListOfFieldData) -> + {lists:reverse(ListOfFieldData),Bs}. + +create_binary([EvalField|ListOfEvalField], Acc) -> + Bin = EvalField(), + create_binary(ListOfEvalField, <<Acc/binary-unit:1,Bin/binary-unit:1>>); +create_binary([], Acc) -> + Acc. eval_field({bin_element, _, {string, _, S}, {integer,_,8}, [integer,{unit,1},unsigned,big]}, Bs0, _Fun) -> Latin1 = [C band 16#FF || C <- S], - {list_to_binary(Latin1),Bs0}; + {fun() -> list_to_binary(Latin1) end,Bs0}; eval_field({bin_element, _, {string, _, S}, default, default}, Bs0, _Fun) -> Latin1 = [C band 16#FF || C <- S], - {list_to_binary(Latin1),Bs0}; + {fun() ->list_to_binary(Latin1) end,Bs0}; eval_field({bin_element, Line, {string, _, S}, Size0, Options0}, Bs0, Fun) -> {Size1,[Type,{unit,Unit},Sign,Endian]} = make_bit_type(Line, Size0, Options0), {value,Size,Bs1} = Fun(Size1, Bs0), - Res = << <<(eval_exp_field1(C, Size, Unit, - Type, Endian, Sign))/bitstring>> || - C <- S >>, - case S of - "" -> % find errors also when the string is empty - _ = eval_exp_field1(0, Size, Unit, Type, Endian, Sign), - ok; - _ -> - ok - end, - {Res,Bs1}; + {fun() -> + Res = << <<(eval_exp_field1(C, Size, Unit, + Type, Endian, Sign))/bitstring>> || + C <- S >>, + case S of + "" -> % find errors also when the string is empty + _ = eval_exp_field1(0, Size, Unit, Type, Endian, Sign), + ok; + _ -> + ok + end, + Res + end,Bs1}; eval_field({bin_element,Line,E,Size0,Options0}, Bs0, Fun) -> {value,V,Bs1} = Fun(E, Bs0), {Size1,[Type,{unit,Unit},Sign,Endian]} = make_bit_type(Line, Size0, Options0), {value,Size,Bs} = Fun(Size1, Bs1), - {eval_exp_field1(V, Size, Unit, Type, Endian, Sign),Bs}. + {fun() -> eval_exp_field1(V, Size, Unit, Type, Endian, Sign) end,Bs}. eval_exp_field1(V, Size, Unit, Type, Endian, Sign) -> try diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index 392e52bdb1..e6754d13f5 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -1146,7 +1146,7 @@ otp_14826(_Config) -> backtrace_check("<<100:8/foo>>.", {undefined_bittype,foo}, [{eval_bits,make_bit_type,3},eval_bits, - eval_bits,erl_eval], + eval_bits,eval_bits], none, none), backtrace_check("B = <<\"foo\">>, <<B/binary-unit:7>>.", badarg, @@ -1750,6 +1750,10 @@ otp_16865(Config) when is_list(Config) -> check(fun() -> << <<>> || <<34:(1/0)>> <= <<"string">> >> end, "<< <<>> || <<34:(1/0)>> <= <<\"string\">> >>.", <<>>), + %% The order of evaluation is important. Follow the example set by + %% compiled code: + error_check("<< <<>> || <<>> <= <<1:(-1), (fun() -> a = b end())>> >>.", + {badmatch, b}), ok. %% Check the string in different contexts: as is; in fun; from compiled code. -- 2.26.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor