diff options
70 files changed, 693 insertions, 232 deletions
diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot Binary files differindex f1eb1a8818..05f177db91 100644 --- a/bootstrap/bin/start.boot +++ b/bootstrap/bin/start.boot diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot Binary files differindex f1eb1a8818..05f177db91 100644 --- a/bootstrap/bin/start_clean.boot +++ b/bootstrap/bin/start_clean.boot diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam Binary files differindex fd36250580..360438a79f 100644 --- a/bootstrap/lib/compiler/ebin/beam_asm.beam +++ b/bootstrap/lib/compiler/ebin/beam_asm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam Binary files differindex 2ecba86d56..4fdaff48c3 100644 --- a/bootstrap/lib/compiler/ebin/beam_disasm.beam +++ b/bootstrap/lib/compiler/ebin/beam_disasm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_type.beam b/bootstrap/lib/compiler/ebin/beam_type.beam Binary files differindex 7b005ba802..7f760cd1b7 100644 --- a/bootstrap/lib/compiler/ebin/beam_type.beam +++ b/bootstrap/lib/compiler/ebin/beam_type.beam diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam Binary files differindex f67076fa93..75c2945971 100644 --- a/bootstrap/lib/compiler/ebin/beam_validator.beam +++ b/bootstrap/lib/compiler/ebin/beam_validator.beam diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam Binary files differindex 2eaae61431..0133b1346a 100644 --- a/bootstrap/lib/compiler/ebin/compile.beam +++ b/bootstrap/lib/compiler/ebin/compile.beam diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app index b6d060167e..e3ff9ac11e 100644 --- a/bootstrap/lib/compiler/ebin/compiler.app +++ b/bootstrap/lib/compiler/ebin/compiler.app @@ -18,7 +18,7 @@ {application, compiler, [{description, "ERTS CXC 138 10"}, - {vsn, "4.8.2"}, + {vsn, "4.9"}, {modules, [ beam_a, beam_asm, diff --git a/bootstrap/lib/compiler/ebin/compiler.appup b/bootstrap/lib/compiler/ebin/compiler.appup index 887d074b16..8cc82fff38 100644 --- a/bootstrap/lib/compiler/ebin/compiler.appup +++ b/bootstrap/lib/compiler/ebin/compiler.appup @@ -1 +1 @@ -{"4.8.1",[],[]}. +{"4.9",[],[]}. diff --git a/bootstrap/lib/compiler/ebin/core_lint.beam b/bootstrap/lib/compiler/ebin/core_lint.beam Binary files differindex bc18af0f7c..f600432713 100644 --- a/bootstrap/lib/compiler/ebin/core_lint.beam +++ b/bootstrap/lib/compiler/ebin/core_lint.beam diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam Binary files differindex a4529cdd39..824abb4f33 100644 --- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam +++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam Binary files differindex 5b41832dec..5871d1c149 100644 --- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam +++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam diff --git a/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam Binary files differindex dd2d62b8a0..4b5543b994 100644 --- a/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam +++ b/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam Binary files differindex 4fd0b25503..0e05cfd7a5 100644 --- a/bootstrap/lib/kernel/ebin/inet_db.beam +++ b/bootstrap/lib/kernel/ebin/inet_db.beam diff --git a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam Binary files differindex 39389454f9..358d9ae403 100644 --- a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam +++ b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app index c6f75faea9..ab1ae605b6 100644 --- a/bootstrap/lib/kernel/ebin/kernel.app +++ b/bootstrap/lib/kernel/ebin/kernel.app @@ -21,7 +21,7 @@ {application, kernel, [ {description, "ERTS CXC 138 10"}, - {vsn, "2.16"}, + {vsn, "2.16.1"}, {modules, [application, application_controller, application_master, diff --git a/bootstrap/lib/kernel/ebin/kernel.appup b/bootstrap/lib/kernel/ebin/kernel.appup index b534b736be..5a6be8c68e 100644 --- a/bootstrap/lib/kernel/ebin/kernel.appup +++ b/bootstrap/lib/kernel/ebin/kernel.appup @@ -15,7 +15,7 @@ %% under the License. %% %% %CopyrightEnd% -{"2.16", +{"2.16.1", %% Up from - max two major revisions back [{<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam Binary files differindex 8e7991754a..001d9f42af 100644 --- a/bootstrap/lib/stdlib/ebin/beam_lib.beam +++ b/bootstrap/lib/stdlib/ebin/beam_lib.beam diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam Binary files differindex 4178980970..d1ace62f55 100644 --- a/bootstrap/lib/stdlib/ebin/dets.beam +++ b/bootstrap/lib/stdlib/ebin/dets.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam Binary files differindex 1b9a0409d1..2538caca66 100644 --- a/bootstrap/lib/stdlib/ebin/erl_lint.beam +++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam diff --git a/bootstrap/lib/stdlib/ebin/gb_sets.beam b/bootstrap/lib/stdlib/ebin/gb_sets.beam Binary files differindex 10b584677d..ea2c4db64f 100644 --- a/bootstrap/lib/stdlib/ebin/gb_sets.beam +++ b/bootstrap/lib/stdlib/ebin/gb_sets.beam diff --git a/bootstrap/lib/stdlib/ebin/io_lib_format.beam b/bootstrap/lib/stdlib/ebin/io_lib_format.beam Binary files differindex 1a7c3393f8..669f988c3d 100644 --- a/bootstrap/lib/stdlib/ebin/io_lib_format.beam +++ b/bootstrap/lib/stdlib/ebin/io_lib_format.beam diff --git a/bootstrap/lib/stdlib/ebin/math.beam b/bootstrap/lib/stdlib/ebin/math.beam Binary files differindex 9b662405ea..c2e8dfb874 100644 --- a/bootstrap/lib/stdlib/ebin/math.beam +++ b/bootstrap/lib/stdlib/ebin/math.beam diff --git a/bootstrap/lib/stdlib/ebin/random.beam b/bootstrap/lib/stdlib/ebin/random.beam Binary files differindex bc8c5ef31f..4a95240dfe 100644 --- a/bootstrap/lib/stdlib/ebin/random.beam +++ b/bootstrap/lib/stdlib/ebin/random.beam diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app index 461531e1df..56b384ea89 100644 --- a/bootstrap/lib/stdlib/ebin/stdlib.app +++ b/bootstrap/lib/stdlib/ebin/stdlib.app @@ -19,7 +19,7 @@ %% {application, stdlib, [{description, "ERTS CXC 138 10"}, - {vsn, "1.19"}, + {vsn, "1.19.1"}, {modules, [array, base64, beam_lib, diff --git a/bootstrap/lib/stdlib/ebin/stdlib.appup b/bootstrap/lib/stdlib/ebin/stdlib.appup index ff9b5387c9..0f374eb279 100644 --- a/bootstrap/lib/stdlib/ebin/stdlib.appup +++ b/bootstrap/lib/stdlib/ebin/stdlib.appup @@ -15,7 +15,7 @@ %% under the License. %% %% %CopyrightEnd% -{"1.19", +{"1.19.1", %% Up from - max two major revisions back [{<<"1\\.19(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 {<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index f57fa2bfbb..81c1ea749a 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -1853,7 +1853,10 @@ load_code(LoaderState* stp) unsigned tag; switch (last_op->a[arg].val) { - case 0: /* Floating point number */ + case 0: + /* Floating point number. + * Not generated by the compiler in R16B and later. + */ { Eterm* hp; /* XXX:PaN - Halfword should use ARCH_64 variant instead */ diff --git a/erts/vsn.mk b/erts/vsn.mk index 53638f435c..4cdc20b550 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -17,8 +17,8 @@ # %CopyrightEnd% # -VSN = 5.10 -SYSTEM_VSN = R16A +VSN = 5.10.1 +SYSTEM_VSN = R16B # Port number 4365 in 4.2 # Port number 4366 in 4.3 diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c index e7e5f5f2f5..b3dd312fed 100644 --- a/lib/asn1/c_src/asn1_erl_nif.c +++ b/lib/asn1/c_src/asn1_erl_nif.c @@ -1130,8 +1130,8 @@ int ber_encode_length(size_t size, mem_chunk_t **curr, unsigned int *count) { (*curr)->curr -= 1; (*count)++; } else { - int chunks = size / 256 + 1; - if (ber_check_memory(curr, chunks + 1)) + int chunks = 0; + if (ber_check_memory(curr, 8)) return ASN1_ERROR; while (size > 0) @@ -1140,6 +1140,7 @@ int ber_encode_length(size_t size, mem_chunk_t **curr, unsigned int *count) { size >>= 8; (*curr)->curr -= 1; (*count)++; + chunks++; } *(*curr)->curr = chunks | 0x80; diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml index da0812f000..5e21b926a8 100644 --- a/lib/asn1/doc/src/notes.xml +++ b/lib/asn1/doc/src/notes.xml @@ -98,6 +98,35 @@ </section> +<section><title>Asn1 1.8.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + ASN.1 decoders generated with the options <c>-bber_bin + +optimize +nif</c> would decode open types with a size + larger than 511 incorrectly. That bug could cause + decoding by <c>public_key</c> to fail. The bug was in the + NIF library <c>asn1_erl_nif.so</c>; therefore there is no + need re-compile ASN.1 specifications that had the + problem.</p> + <p> + Own Id: OTP-10805 Aux Id: seq12244 </p> + </item> + <item> + <p> + Encoding SEQUENCEs with multiple extension addition + groups with optional values could fail (depending both on + the specification and whether all values were provided).</p> + <p> + Own Id: OTP-10811 Aux Id: OTP-10664 </p> + </item> + </list> + </section> + +</section> + <section><title>Asn1 1.8</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl index 644cba8c3c..be9b82cddf 100644 --- a/lib/asn1/test/asn1_SUITE.erl +++ b/lib/asn1/test/asn1_SUITE.erl @@ -1043,17 +1043,24 @@ testDoubleEllipses(Config, Rule, Opts) -> testDoubleEllipses:main(Rule). test_modified_x420(Config) -> + test(Config, fun test_modified_x420/3, [ber]). +test_modified_x420(Config, Rule, Opts) -> Files = [filename:join(modified_x420, F) || F <- ["PKCS7", "InformationFramework", "AuthenticationFramework"]], - asn1_test_lib:compile_all(Files, Config, [der]), - test_modified_x420:test_io(Config). + asn1_test_lib:compile_all(Files, Config, [Rule,der|Opts]), + test_modified_x420:test(Config). testX420() -> [{timetrap,{minutes,90}}]. testX420(Config) -> - test(Config, fun testX420/3, [ber]). + case erlang:system_info(system_architecture) of + "sparc-sun-solaris2.10" -> + {skip,"Too slow for an old Sparc"}; + _ -> + test(Config, fun testX420/3, [ber]) + end. testX420(Config, Rule, Opts) -> testX420:compile(Rule, [der|Opts], Config), ok = testX420:ticket7759(Rule, Config), diff --git a/lib/asn1/test/testX420.erl b/lib/asn1/test/testX420.erl index 52b20a2c70..045660a8e2 100644 --- a/lib/asn1/test/testX420.erl +++ b/lib/asn1/test/testX420.erl @@ -37,7 +37,7 @@ compile_loop(Erule, [Spec|Specs], Options, Config) when Erule =:= ber; Erule =:= per -> CaseDir = ?config(case_dir, Config), asn1_test_lib:compile(filename:join([x420, Spec]), Config, - [Erule, {i, CaseDir}]), + [Erule, {i, CaseDir} | Options]), compile_loop(Erule, Specs, Options, Config); compile_loop(_Erule, _Specs, _Options, _Config) -> ok. diff --git a/lib/asn1/test/test_modified_x420.erl b/lib/asn1/test/test_modified_x420.erl index 2e9dfeee87..ae9d1989fb 100644 --- a/lib/asn1/test/test_modified_x420.erl +++ b/lib/asn1/test/test_modified_x420.erl @@ -18,27 +18,21 @@ %% %% -module(test_modified_x420). - -%-compile(export_all). --export([test_io/1]). +-export([test/1]). -include_lib("test_server/include/test_server.hrl"). -test_io(Config) -> - io:format("~p~n~n", [catch test(Config)]). - test(Config) -> - ?line DataDir = ?config(data_dir,Config), -% ?line OutDir = ?config(priv_dir,Config), + DataDir = ?config(data_dir,Config), - ?line Der = read_pem(filename:join([DataDir,modified_x420,"p7_signed_data.pem"])), - ?line {ok, {_,_,SignedData}} = 'PKCS7':decode('ContentInfo', Der), - ?line {ok,_} = 'PKCS7':decode('SignedData', SignedData). + Der = read_pem(filename:join([DataDir,modified_x420,"p7_signed_data.pem"])), + {ok,{_,_,SignedData}} = asn1_wrapper:decode('PKCS7', 'ContentInfo', Der), + {ok,_} = asn1_wrapper:decode('PKCS7', 'SignedData', SignedData). read_pem(File) -> - ?line {ok, Bin} = file:read_file(File), - ?line ssl_base64:join_decode(lists:flatten(extract_base64(Bin))). - + {ok,Bin} = file:read_file(File), + Der = base64:mime_decode(lists:flatten(extract_base64(Bin))), + binary_to_list(Der). extract_base64(Binary) -> diff --git a/lib/compiler/src/beam_asm.erl b/lib/compiler/src/beam_asm.erl index a7c8508321..98967e651f 100644 --- a/lib/compiler/src/beam_asm.erl +++ b/lib/compiler/src/beam_asm.erl @@ -387,7 +387,7 @@ encode_arg({list, List}, Dict0) -> {L, Dict} = encode_list(List, Dict0, []), {[encode(?tag_z, 1), encode(?tag_u, length(List))|L], Dict}; encode_arg({float, Float}, Dict) when is_float(Float) -> - {[encode(?tag_z, 0),<<Float:64/float>>], Dict}; + encode_arg({literal,Float}, Dict); encode_arg({fr,Fr}, Dict) -> {[encode(?tag_z, 2),encode(?tag_u, Fr)], Dict}; encode_arg({field_flags,Flags0}, Dict) -> diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl index 62bdc74cc8..67d756c45c 100644 --- a/lib/compiler/src/beam_disasm.erl +++ b/lib/compiler/src/beam_disasm.erl @@ -512,7 +512,12 @@ decode_z_tagged(Tag,B,Bs,Literals) when (B band 16#08) =:= 0 -> decode_alloc_list(Bs, Literals); 4 -> % literal {{u,LitIndex},RestBs} = decode_arg(Bs), - {{literal,gb_trees:get(LitIndex, Literals)},RestBs}; + case gb_trees:get(LitIndex, Literals) of + Float when is_float(Float) -> + {{float,Float},RestBs}; + Literal -> + {{literal,Literal},RestBs} + end; _ -> ?exit({decode_z_tagged,{invalid_extended_tag,N}}) end; diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl index 0bb527aeb9..3dd5ed182e 100644 --- a/lib/compiler/src/beam_receive.erl +++ b/lib/compiler/src/beam_receive.erl @@ -249,7 +249,7 @@ opt_ref_used(Is, RefReg, Fail, D) -> Done = gb_sets:singleton(Fail), Regs = regs_init_x0(), try - opt_ref_used_1(Is, RefReg, D, Done, Regs), + _ = opt_ref_used_1(Is, RefReg, D, Done, Regs), true catch throw:not_used -> diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl index 7392f99fb6..372923a5cf 100644 --- a/lib/compiler/src/beam_type.erl +++ b/lib/compiler/src/beam_type.erl @@ -142,9 +142,11 @@ simplify_float(Is0, Ts0) -> throw:not_possible -> not_possible end. -simplify_float_1([{set,[D0],[A],{alloc,_,{gc_bif,'-',{f,0}}}}=I|Is]=Is0, Ts0, Rs0, Acc0) -> - case tdb_find(A, Ts0) of +simplify_float_1([{set,[D0],[A0],{alloc,_,{gc_bif,'-',{f,0}}}}=I|Is]=Is0, + Ts0, Rs0, Acc0) -> + case tdb_find(A0, Ts0) of float -> + A = coerce_to_float(A0), {Rs1,Acc1} = load_reg(A, Ts0, Rs0, Acc0), {D,Rs} = find_dest(D0, Rs1), Areg = fetch_reg(A, Rs), @@ -156,13 +158,16 @@ simplify_float_1([{set,[D0],[A],{alloc,_,{gc_bif,'-',{f,0}}}}=I|Is]=Is0, Ts0, Rs {Rs,Acc} = flush(Rs0, Is0, Acc0), simplify_float_1(Is, Ts, Rs, [I|checkerror(Acc)]) end; -simplify_float_1([{set,[D0],[A,B],{alloc,_,{gc_bif,Op0,{f,0}}}}=I|Is]=Is0, Ts0, Rs0, Acc0) -> - case float_op(Op0, A, B, Ts0) of +simplify_float_1([{set,[D0],[A0,B0],{alloc,_,{gc_bif,Op0,{f,0}}}}=I|Is]=Is0, + Ts0, Rs0, Acc0) -> + case float_op(Op0, A0, B0, Ts0) of no -> Ts = update(I, Ts0), {Rs,Acc} = flush(Rs0, Is0, Acc0), simplify_float_1(Is, Ts, Rs, [I|checkerror(Acc)]); {yes,Op} -> + A = coerce_to_float(A0), + B = coerce_to_float(B0), {Rs1,Acc1} = load_reg(A, Ts0, Rs0, Acc0), {Rs2,Acc2} = load_reg(B, Ts0, Rs1, Acc1), {D,Rs} = find_dest(D0, Rs2), @@ -187,6 +192,16 @@ simplify_float_1([], Ts, Rs, Acc0) -> Is = opt_fmoves(Is0, []), {Is,Ts}. +coerce_to_float({integer,I}=Int) -> + try float(I) of + F -> + {float,F} + catch _:_ -> + %% Let the overflow happen at run-time. + Int + end; +coerce_to_float(Other) -> Other. + opt_fmoves([{set,[{x,_}=R],[{fr,_}]=Src,fmove}=I1, {set,[_]=Dst,[{x,_}=R],move}=I2|Is], Acc) -> case beam_utils:is_killed_block(R, Is) of diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 58aba0b9cc..eb72290306 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -649,7 +649,8 @@ valfun_4(send, Vst) -> call(send, 2, Vst); valfun_4({set_tuple_element,Src,Tuple,I}, Vst) -> assert_term(Src, Vst), - assert_type({tuple_element,I+1}, Tuple, Vst); + assert_type({tuple_element,I+1}, Tuple, Vst), + Vst; %% Match instructions. valfun_4({select_val,Src,{f,Fail},{list,Choices}}, Vst) -> assert_term(Src, Vst), @@ -1044,7 +1045,7 @@ float_op(Src, Dst, Vst0) -> assert_fls(Fls, Vst) -> case get_fls(Vst) of - Fls -> Vst; + Fls -> ok; OtherFls -> error({bad_floating_point_state,OtherFls}) end. @@ -1120,7 +1121,7 @@ bsm_match_state(Slots) -> {match_context,0,Slots}. bsm_validate_context(Reg, Vst) -> - bsm_get_context(Reg, Vst), + _ = bsm_get_context(Reg, Vst), ok. bsm_get_context({x,X}=Reg, #vst{current=#st{x=Xs}}=_Vst) when is_integer(X) -> @@ -1133,7 +1134,7 @@ bsm_get_context(Reg, _) -> error({bad_source,Reg}). bsm_save(Reg, {atom,start}, Vst) -> %% Save point refering to where the match started. %% It is always valid. But don't forget to validate the context register. - bsm_get_context(Reg, Vst), + bsm_validate_context(Reg, Vst), Vst; bsm_save(Reg, SavePoint, Vst) -> case bsm_get_context(Reg, Vst) of @@ -1146,7 +1147,7 @@ bsm_save(Reg, SavePoint, Vst) -> bsm_restore(Reg, {atom,start}, Vst) -> %% (Mostly) automatic save point refering to where the match started. %% It is always valid. But don't forget to validate the context register. - bsm_get_context(Reg, Vst), + bsm_validate_context(Reg, Vst), Vst; bsm_restore(Reg, SavePoint, Vst) -> case bsm_get_context(Reg, Vst) of @@ -1312,8 +1313,7 @@ assert_term(Src, Vst) -> %% assert_type(WantedType, Term, Vst) -> - assert_type(WantedType, get_term_type(Term, Vst)), - Vst. + assert_type(WantedType, get_term_type(Term, Vst)). assert_type(Correct, Correct) -> ok; assert_type(float, {float,_}) -> ok; diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index d2baf51edd..497af2b52c 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -683,7 +683,7 @@ binary_passes() -> %% Remove the target file so we don't have an old one if the compilation fail. remove_file(St) -> - file:delete(St#compile.ofile), + _ = file:delete(St#compile.ofile), {ok,St}. -record(asm_module, {module, @@ -1092,7 +1092,7 @@ makedep_output(#compile{code=Code,options=Opts,ofile=Ofile}=St) -> io:fwrite(Output1, "~ts", [Code]), %% Close the file if relevant. if - CloseOutput -> file:close(Output1); + CloseOutput -> ok = file:close(Output1); true -> ok end, {ok,St} @@ -1231,7 +1231,7 @@ encrypt(des3_cbc=Mode, {K1,K2,K3, IVec}, Bin0) -> random_bytes(N) -> {A,B,C} = now(), - random:seed(A, B, C), + _ = random:seed(A, B, C), random_bytes_1(N, []). random_bytes_1(0, Acc) -> Acc; diff --git a/lib/compiler/src/core_lint.erl b/lib/compiler/src/core_lint.erl index 8b688df830..1e8983f594 100644 --- a/lib/compiler/src/core_lint.erl +++ b/lib/compiler/src/core_lint.erl @@ -309,7 +309,7 @@ expr(#c_fun{vars=Vs,body=B}, Def, Rt, St0) -> {Vvs,St1} = variable_list(Vs, St0), return_match(Rt, 1, body(B, union(Vvs, Def), any, St1)); expr(#c_seq{arg=Arg,body=B}, Def, Rt, St0) -> - St1 = expr(Arg, Def, any, St0), %Ignore values + St1 = expr(Arg, Def, 1, St0), body(B, Def, Rt, St1); expr(#c_let{vars=Vs,arg=Arg,body=B}, Def, Rt, St0) -> St1 = body(Arg, Def, let_varcount(Vs), St0), %This is a body diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index d5fec0c869..cda3f7d81e 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -132,7 +132,12 @@ body(Body, Sub) -> body(#c_values{anno=A,es=Es0}, Ctxt, Sub) -> Es1 = expr_list(Es0, Ctxt, Sub), - #c_values{anno=A,es=Es1}; + case Ctxt of + value -> + #c_values{anno=A,es=Es1}; + effect -> + make_effect_seq(Es1, Sub) + end; body(E, Ctxt, Sub) -> ?ASSERT(verify_scope(E, Sub)), expr(E, Ctxt, Sub). @@ -1272,6 +1277,8 @@ eval_element(Call, #c_literal{val=Pos}, #c_var{name=V}, Types) true -> eval_failure(Call, badarg) end; + {ok,_} -> + eval_failure(Call, badarg); error -> Call end; diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile index b9c5be09ce..51b3064589 100644 --- a/lib/compiler/test/Makefile +++ b/lib/compiler/test/Makefile @@ -75,6 +75,7 @@ INLINE= \ CORE_MODULES = \ bs_shadowed_size_var \ + unused_multiple_values_error \ nested_call_in_case diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl index 53a65d8d17..abc9ab6a72 100644 --- a/lib/compiler/test/core_fold_SUITE.erl +++ b/lib/compiler/test/core_fold_SUITE.erl @@ -21,7 +21,8 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, t_element/1,setelement/1,t_length/1,append/1,t_apply/1,bifs/1, - eq/1,nested_call_in_case/1,guard_try_catch/1,coverage/1]). + eq/1,nested_call_in_case/1,guard_try_catch/1,coverage/1, + unused_multiple_values_error/1,unused_multiple_values/1]). -export([foo/0,foo/1,foo/2,foo/3]). @@ -36,7 +37,8 @@ all() -> groups() -> [{p,test_lib:parallel(), [t_element,setelement,t_length,append,t_apply,bifs, - eq,nested_call_in_case,guard_try_catch,coverage]}]. + eq,nested_call_in_case,guard_try_catch,coverage, + unused_multiple_values_error,unused_multiple_values]}]. init_per_suite(Config) -> @@ -69,6 +71,9 @@ t_element(Config) when is_list(Config) -> ?line {'EXIT',{badarg,_}} = (catch element(5, {a,b,c,d})), ?line {'EXIT',{badarg,_}} = (catch element(5, {a,b,X,d})), ?line {'EXIT',{badarg,_}} = (catch element(5.0, {a,b,X,d})), + {'EXIT',{badarg,_}} = (catch element(2, not_a_tuple)), + {'EXIT',{badarg,_}} = (catch element(2, [])), + {'EXIT',{badarg,_}} = (catch element(2, Tuple == 3)), case id({a,b,c}) of {_,_,_}=Tup -> ?line {'EXIT',{badarg,_}} = (catch element(4, Tup)) @@ -89,6 +94,9 @@ setelement(Config) when is_list(Config) -> ?line {'EXIT',{badarg,_}} = (catch setelement_crash({a,b,c,d,e,f})), ?line error = setelement_crash_2({a,b,c,d,e,f}, <<42>>), + + {'EXIT',{badarg,_}} = (catch setelement(1, not_a_tuple, New)), + ok. setelement_crash(Tuple) -> @@ -283,3 +291,41 @@ cover_is_safe_bool_expr(X) -> end. id(I) -> I. + +unused_multiple_values_error(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + Dir = filename:dirname(code:which(?MODULE)), + Core = filename:join(Dir, "unused_multiple_values_error"), + Opts = [no_copt,clint,return,from_core,{outdir,PrivDir} + |test_lib:opt_opts(?MODULE)], + {error,[{unused_multiple_values_error, + [{core_lint,{return_mismatch,{hello,1}}}]}], + []} = c:c(Core, Opts), + ok. + +unused_multiple_values(Config) when is_list(Config) -> + put(unused_multiple_values, []), + [false] = test_unused_multiple_values(false), + [b,a,{a,b},false] = test_unused_multiple_values({a,b}), + ok. + +test_unused_multiple_values(X) -> + ok = do_unused_multiple_values(X), + get(unused_multiple_values). + +do_unused_multiple_values(X) -> + case do_something(X) of + false -> + A = false; + Res -> + {A,B} = Res, + do_something(A), + do_something(B) + end, + _ThisShouldNotFail = A, + ok. + +do_something(I) -> + put(unused_multiple_values, + [I|get(unused_multiple_values)]), + I. diff --git a/lib/compiler/test/unused_multiple_values_error.core b/lib/compiler/test/unused_multiple_values_error.core new file mode 100644 index 0000000000..e06587c936 --- /dev/null +++ b/lib/compiler/test/unused_multiple_values_error.core @@ -0,0 +1,11 @@ +module 'unused_multiple_values_error' ['hello'/1] + attributes [] +'hello'/1 = + fun (_cor0) -> + do + case _cor0 of + <_cor0> when 'true' -> + <'ok','ok'> + end + 'ok' +end diff --git a/lib/kernel/doc/src/specs.xml b/lib/kernel/doc/src/specs.xml index b41addaa0c..813bb06e1f 100644 --- a/lib/kernel/doc/src/specs.xml +++ b/lib/kernel/doc/src/specs.xml @@ -29,5 +29,4 @@ <xi:include href="../specs/specs_user.xml"/> <xi:include href="../specs/specs_wrap_log_reader.xml"/> <xi:include href="../specs/specs_zlib_stub.xml"/> - <xi:include href="../specs/specs_packages.xml"/> </specs> diff --git a/lib/kernel/src/inet6_tcp_dist.erl b/lib/kernel/src/inet6_tcp_dist.erl index b9c4fa607c..2315a56582 100644 --- a/lib/kernel/src/inet6_tcp_dist.erl +++ b/lib/kernel/src/inet6_tcp_dist.erl @@ -71,8 +71,12 @@ listen(Name) -> {ok, Socket} -> TcpAddress = get_tcp_address(Socket), {_,Port} = TcpAddress#net_address.address, - {ok, Creation} = erl_epmd:register_node(Name, Port), - {ok, {Socket, TcpAddress, Creation}}; + case erl_epmd:register_node(Name, Port) of + {ok, Creation} -> + {ok, {Socket, TcpAddress, Creation}}; + Error -> + Error + end; Error -> Error end. diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl index 7f935c2b36..70f3c87723 100644 --- a/lib/kernel/src/inet_tcp_dist.erl +++ b/lib/kernel/src/inet_tcp_dist.erl @@ -67,8 +67,12 @@ listen(Name) -> {ok, Socket} -> TcpAddress = get_tcp_address(Socket), {_,Port} = TcpAddress#net_address.address, - {ok, Creation} = erl_epmd:register_node(Name, Port), - {ok, {Socket, TcpAddress, Creation}}; + case erl_epmd:register_node(Name, Port) of + {ok, Creation} -> + {ok, {Socket, TcpAddress, Creation}}; + Error -> + Error + end; Error -> Error end. diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index 46a991eb38..b6cf4407d2 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 2.16 +KERNEL_VSN = 2.16.1 diff --git a/lib/odbc/src/odbc.erl b/lib/odbc/src/odbc.erl index 3eabec9ec3..dde96907e5 100644 --- a/lib/odbc/src/odbc.erl +++ b/lib/odbc/src/odbc.erl @@ -902,7 +902,9 @@ param_values(Params) -> [{_, Values} | _] -> Values; [{_, _, Values} | _] -> - Values + Values; + [] -> + [] end. %%------------------------------------------------------------------------- diff --git a/lib/odbc/test/odbc_query_SUITE.erl b/lib/odbc/test/odbc_query_SUITE.erl index 1852678b4b..61253b29aa 100644 --- a/lib/odbc/test/odbc_query_SUITE.erl +++ b/lib/odbc/test/odbc_query_SUITE.erl @@ -63,7 +63,8 @@ groups() -> param_insert_numeric, {group, param_insert_string}, param_insert_float, param_insert_real, param_insert_double, param_insert_mix, param_update, - param_delete, param_select]}, + param_delete, param_select, + param_select_empty_params, param_delete_empty_params]}, {param_integers, [], [param_insert_tiny_int, param_insert_small_int, param_insert_int, param_insert_integer]}, @@ -1345,6 +1346,70 @@ param_select(Config) when is_list(Config) -> ok. %%------------------------------------------------------------------------- +param_select_empty_params(doc) -> + ["Test parameterized select query with no parameters."]; +param_select_empty_params(suite) -> + []; +param_select_empty_params(Config) when is_list(Config) -> + Ref = ?config(connection_ref, Config), + Table = ?config(tableName, Config), + + {updated, _} = + odbc:sql_query(Ref, + "CREATE TABLE " ++ Table ++ + " (ID INTEGER, DATA CHARACTER VARYING(10)," + " PRIMARY KEY(ID))"), + + {updated, Count} = odbc:param_query(Ref, "INSERT INTO " ++ Table ++ + "(ID, DATA) VALUES(?, ?)", + [{sql_integer, [1, 2, 3]}, + {{sql_varchar, 10}, + ["foo", "bar", "foo"]}]), + + true = odbc_test_lib:check_row_count(3, Count), + + SelectResult = ?RDBMS:param_select(), + + SelectResult = odbc:param_query(Ref, "SELECT * FROM " ++ Table ++ + " WHERE DATA = \'foo\'", + []), + ok. + +%%------------------------------------------------------------------------- +param_delete_empty_params(doc) -> + ["Test parameterized delete query with no parameters."]; +param_delete_empty_params(suite) -> + []; +param_delete_empty_params(Config) when is_list(Config) -> + Ref = ?config(connection_ref, Config), + Table = ?config(tableName, Config), + + {updated, _} = + odbc:sql_query(Ref, + "CREATE TABLE " ++ Table ++ + " (ID INTEGER, DATA CHARACTER VARYING(10)," + " PRIMARY KEY(ID))"), + + {updated, Count} = odbc:param_query(Ref, "INSERT INTO " ++ Table ++ + "(ID, DATA) VALUES(?, ?)", + [{sql_integer, [1, 2, 3]}, + {{sql_varchar, 10}, + ["foo", "bar", "baz"]}]), + true = odbc_test_lib:check_row_count(3, Count), + + {updated, NewCount} = odbc:param_query(Ref, "DELETE FROM " ++ Table ++ + " WHERE ID = 1 OR ID = 2", + []), + + true = odbc_test_lib:check_row_count(2, NewCount), + + UpdateResult = ?RDBMS:param_delete(), + + UpdateResult = + odbc:sql_query(Ref, "SELECT * FROM " ++ Table), + ok. + +%%------------------------------------------------------------------------- describe_integer(doc) -> ["Test describe_table/[2,3] for integer columns."]; describe_integer(suite) -> diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk index 585b92b2d2..b3ffff2cf8 100644 --- a/lib/odbc/vsn.mk +++ b/lib/odbc/vsn.mk @@ -1 +1 @@ -ODBC_VSN = 2.10.14 +ODBC_VSN = 2.10.15 diff --git a/lib/sasl/src/sasl.appup.src b/lib/sasl/src/sasl.appup.src index ce4aa1f8f8..a4a38ee40a 100644 --- a/lib/sasl/src/sasl.appup.src +++ b/lib/sasl/src/sasl.appup.src @@ -1,7 +1,7 @@ %% -*- erlang -*- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -17,11 +17,13 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max two major revisions back - [{<<"2\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 - {<<"2\\.1\\.10(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14B04 (and later?) - {<<"2\\.1\\.[6-9](\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13B-R14B03 + [{<<"2\\.3(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"2\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.1\\.10(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14B04 + {<<"2\\.1\\.9\\.[24](\\.[0-9]+)*">>,[restart_new_emulator]}],%% R14B-R14B03 %% Down to - max two major revisions back - [{<<"2\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 - {<<"2\\.1\\.10(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14B04 (and later?) - {<<"2\\.1\\.[6-9](\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13B-R14B03 + [{<<"2\\.3(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"2\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.1\\.10(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14B04 + {<<"2\\.1\\.9\\.[24](\\.[0-9]+)*">>,[restart_new_emulator]}] %% R14B-R14B03 }. diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index deae9640f5..12505b33d1 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -152,8 +152,6 @@ format_error({attribute,A}) -> io_lib:format("attribute '~w' after function definitions", [A]); format_error({missing_qlc_hrl,A}) -> io_lib:format("qlc:q/~w called, but \"qlc.hrl\" not included", [A]); -format_error({redefine_import,{bif,{F,A},M}}) -> - io_lib:format("function ~w/~w already auto-imported from ~w", [F,A,M]); format_error({redefine_import,{{F,A},M}}) -> io_lib:format("function ~w/~w already imported from ~w", [F,A,M]); format_error({bad_inline,{F,A}}) -> @@ -222,8 +220,6 @@ format_error({removed, MFA, String}) when is_list(String) -> io_lib:format("~s: ~s", [format_mfa(MFA), String]); format_error({obsolete_guard, {F, A}}) -> io_lib:format("~p/~p obsolete", [F, A]); -format_error({reserved_for_future,K}) -> - io_lib:format("atom ~w: future reserved keyword - rename or quote", [K]); format_error({too_many_arguments,Arity}) -> io_lib:format("too many arguments (~w) - " "maximum allowed is ~w", [Arity,?MAX_ARGUMENTS]); @@ -236,11 +232,6 @@ format_error({illegal_guard_local_call, {F,A}}) -> io_lib:format("call to local/imported function ~w/~w is illegal in guard", [F,A]); format_error(illegal_guard_expr) -> "illegal guard expression"; -%% --- exports --- -format_error({explicit_export,F,A}) -> - io_lib:format("in this release, the call to ~w/~w must be written " - "like this: erlang:~w/~w", - [F,A,F,A]); %% --- records --- format_error({undefined_record,T}) -> io_lib:format("record ~w undefined", [T]); @@ -278,8 +269,6 @@ format_error({variable_in_record_def,V}) -> %% --- binaries --- format_error({undefined_bittype,Type}) -> io_lib:format("bit type ~w undefined", [Type]); -format_error({bittype_mismatch,T1,T2,What}) -> - io_lib:format("bit type mismatch (~s) between ~p and ~p", [What,T1,T2]); format_error(bittype_unit) -> "a bit unit size must not be specified unless a size is specified too"; format_error(illegal_bitsize) -> @@ -1798,11 +1787,9 @@ gexpr({call,Line,{atom,_La,F},As}, Vt, St0) -> %% BifClash - Function called in guard case erl_internal:guard_bif(F, A) andalso no_guard_bif_clash(St1,{F,A}) of true -> - %% Also check that it is auto-imported. - case erl_internal:bif(F, A) of - true -> {Asvt,St1}; - false -> {Asvt,add_error(Line, {explicit_export,F,A}, St1)} - end; + %% Assert that it is auto-imported. + true = erl_internal:bif(F, A), + {Asvt,St1}; false -> case is_local_function(St1#lint.locals,{F,A}) orelse is_imported_function(St1#lint.imports,{F,A}) of diff --git a/lib/stdlib/src/eval_bits.erl b/lib/stdlib/src/eval_bits.erl index f40904df1c..e49cbc1fd1 100644 --- a/lib/stdlib/src/eval_bits.erl +++ b/lib/stdlib/src/eval_bits.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -67,7 +67,8 @@ expr_grp([], Bs0, _Lf, Acc) -> {value,Acc,Bs0}. eval_field({bin_element, _, {string, _, S}, default, default}, Bs0, _Fun) -> - {list_to_binary(S),Bs0}; + Latin1 = [C band 16#FF || C <- S], + {list_to_binary(Latin1),Bs0}; eval_field({bin_element, Line, {string, _, S}, Size0, Options0}, Bs, _Fun) -> {_Size,[Type,_Unit,_Sign,Endian]} = make_bit_type(Line, Size0, Options0), @@ -162,8 +163,10 @@ bin_gen([], Bin, _Bs0, _BBs0, _Mfun, _Efun, false) -> bin_gen_field({bin_element,_,{string,_,S},default,default}, Bin, Bs, BBs, _Mfun, _Efun) -> - Bits = list_to_binary(S), - Size = byte_size(Bits), + Bits = try list_to_binary(S) + catch _:_ -> <<>> + end, + Size = length(S), case Bin of <<Bits:Size/binary,Rest/bitstring>> -> {match,Bs,BBs,Rest}; @@ -172,16 +175,42 @@ bin_gen_field({bin_element,_,{string,_,S},default,default}, _ -> done end; +bin_gen_field({bin_element,Line,{string,SLine,S},Size0,Options0}, + Bin0, Bs0, BBs0, Mfun, Efun) -> + {Size1, [Type,{unit,Unit},Sign,Endian]} = + make_bit_type(Line, Size0, Options0), + match_check_size(Mfun, Size1, BBs0), + {value, Size, _BBs} = Efun(Size1, BBs0), + F = fun(C, Bin, Bs, BBs) -> + bin_gen_field1(Bin, Type, Size, Unit, Sign, Endian, + {integer,SLine,C}, Bs, BBs, Mfun) + end, + bin_gen_field_string(S, Bin0, Bs0, BBs0, F); bin_gen_field({bin_element,Line,VE,Size0,Options0}, Bin, Bs0, BBs0, Mfun, Efun) -> {Size1, [Type,{unit,Unit},Sign,Endian]} = make_bit_type(Line, Size0, Options0), V = erl_eval:partial_eval(VE), + NewV = coerce_to_float(V, Type), match_check_size(Mfun, Size1, BBs0), {value, Size, _BBs} = Efun(Size1, BBs0), + bin_gen_field1(Bin, Type, Size, Unit, Sign, Endian, NewV, Bs0, BBs0, Mfun). + +bin_gen_field_string([], Rest, Bs, BBs, _F) -> + {match,Bs,BBs,Rest}; +bin_gen_field_string([C|Cs], Bin0, Bs0, BBs0, Fun) -> + case Fun(C, Bin0, Bs0, BBs0) of + {match,Bs,BBs,Rest} -> + bin_gen_field_string(Cs, Rest, Bs, BBs, Fun); + {nomatch,Rest} -> + {nomatch,Rest}; + done -> + done + end. + +bin_gen_field1(Bin, Type, Size, Unit, Sign, Endian, NewV, Bs0, BBs0, Mfun) -> case catch get_value(Bin, Type, Size, Unit, Sign, Endian) of {Val,<<_/bitstring>>=Rest} -> - NewV = coerce_to_float(V, Type), case catch Mfun(match, {NewV,Val,Bs0}) of {match,Bs} -> BBs = add_bin_binding(Mfun, NewV, Bs, BBs0), @@ -223,20 +252,41 @@ match_bits_1([F|Fs], Bits0, Bs0, BBs0, Mfun, Efun) -> match_field_1({bin_element,_,{string,_,S},default,default}, Bin, Bs, BBs, _Mfun, _Efun) -> - Bits = list_to_binary(S), + Bits = list_to_binary(S), % fails if there are characters > 255 Size = byte_size(Bits), <<Bits:Size/binary,Rest/binary-unit:1>> = Bin, {Bs,BBs,Rest}; +match_field_1({bin_element,Line,{string,SLine,S},Size0,Options0}, + Bin0, Bs0, BBs0, Mfun, Efun) -> + {Size1, [Type,{unit,Unit},Sign,Endian]} = + make_bit_type(Line, Size0, Options0), + Size2 = erl_eval:partial_eval(Size1), + match_check_size(Mfun, Size2, BBs0), + {value, Size, _BBs} = Efun(Size2, BBs0), + F = fun(C, Bin, Bs, BBs) -> + match_field(Bin, Type, Size, Unit, Sign, Endian, + {integer,SLine,C}, Bs, BBs, Mfun) + end, + match_field_string(S, Bin0, Bs0, BBs0, F); match_field_1({bin_element,Line,VE,Size0,Options0}, Bin, Bs0, BBs0, Mfun, Efun) -> {Size1, [Type,{unit,Unit},Sign,Endian]} = make_bit_type(Line, Size0, Options0), V = erl_eval:partial_eval(VE), + NewV = coerce_to_float(V, Type), Size2 = erl_eval:partial_eval(Size1), match_check_size(Mfun, Size2, BBs0), {value, Size, _BBs} = Efun(Size2, BBs0), + match_field(Bin, Type, Size, Unit, Sign, Endian, NewV, Bs0, BBs0, Mfun). + +match_field_string([], Rest, Bs, BBs, _Fun) -> + {Bs,BBs,Rest}; +match_field_string([C|Cs], Bin0, Bs0, BBs0, Fun) -> + {Bs,BBs,Bin} = Fun(C, Bin0, Bs0, BBs0), + match_field_string(Cs, Bin, Bs, BBs, Fun). + +match_field(Bin, Type, Size, Unit, Sign, Endian, NewV, Bs0, BBs0, Mfun) -> {Val,Rest} = get_value(Bin, Type, Size, Unit, Sign, Endian), - NewV = coerce_to_float(V, Type), {match,Bs} = Mfun(match, {NewV,Val,Bs0}), BBs = add_bin_binding(Mfun, NewV, Bs, BBs0), {Bs,BBs,Rest}. diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl index 203d2a4f76..0cd408204e 100644 --- a/lib/stdlib/src/shell.erl +++ b/lib/stdlib/src/shell.erl @@ -185,7 +185,7 @@ server(StartSync) -> %% Check if we're in user restricted mode. RShErr = case application:get_env(stdlib, restricted_shell) of - {ok,RShMod} -> + {ok,RShMod} when is_atom(RShMod) -> io:fwrite(<<"Restricted ">>, []), case code:ensure_loaded(RShMod) of {module,RShMod} -> @@ -193,6 +193,8 @@ server(StartSync) -> {error,What} -> {RShMod,What} end; + {ok, Term} -> + {Term,not_an_atom}; undefined -> undefined end, diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index 04d49770cb..d3c91c7326 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2012. All Rights Reserved. +%% Copyright Ericsson AB 1998-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -37,6 +37,7 @@ otp_6977/1, otp_7550/1, otp_8133/1, + otp_10622/1, funs/1, try_catch/1, eval_expr_5/1, @@ -79,7 +80,7 @@ all() -> pattern_expr, match_bin, guard_3, guard_4, lc, simple_cases, unary_plus, apply_atom, otp_5269, otp_6539, otp_6543, otp_6787, otp_6977, otp_7550, - otp_8133, funs, try_catch, eval_expr_5, zero_width]. + otp_8133, otp_10622, funs, try_catch, eval_expr_5, zero_width]. groups() -> []. @@ -960,6 +961,7 @@ otp_8133(Config) when is_list(Config) -> E = fun(N) -> if is_integer(N) -> <<N/integer>>; + true -> erlang:error(foo) end end, @@ -980,6 +982,48 @@ otp_8133(Config) when is_list(Config) -> ok), ok. +otp_10622(doc) -> + ["OTP-10622. Bugs."]; +otp_10622(suite) -> + []; +otp_10622(Config) when is_list(Config) -> + check(fun() -> <<0>> = <<"\x{400}">> end, + "<<0>> = <<\"\\x{400}\">>. ", + <<0>>), + check(fun() -> <<"\x{aa}ff"/utf8>> = <<"\x{aa}ff"/utf8>> end, + "<<\"\\x{aa}ff\"/utf8>> = <<\"\\x{aa}ff\"/utf8>>. ", + <<"�\xaaff">>), + %% The same bug as last example: + check(fun() -> case <<"foo"/utf8>> of + <<"foo"/utf8>> -> true + end + end, + "case <<\"foo\"/utf8>> of <<\"foo\"/utf8>> -> true end.", + true), + check(fun() -> <<"\x{400}"/utf8>> = <<"\x{400}"/utf8>> end, + "<<\"\\x{400}\"/utf8>> = <<\"\\x{400}\"/utf8>>. ", + <<208,128>>), + error_check("<<\"\\x{aaa}\">> = <<\"\\x{aaa}\">>.", + {badmatch,<<"\xaa">>}), + + check(fun() -> [a || <<"\x{aaa}">> <= <<2703:16>>] end, + "[a || <<\"\\x{aaa}\">> <= <<2703:16>>]. ", + []), + check(fun() -> [a || <<"\x{aa}"/utf8>> <= <<"\x{aa}"/utf8>>] end, + "[a || <<\"\\x{aa}\"/utf8>> <= <<\"\\x{aa}\"/utf8>>]. ", + [a]), + check(fun() -> [a || <<"\x{aa}x"/utf8>> <= <<"\x{aa}y"/utf8>>] end, + "[a || <<\"\\x{aa}x\"/utf8>> <= <<\"\\x{aa}y\"/utf8>>]. ", + []), + check(fun() -> [a || <<"\x{aaa}">> <= <<"\x{aaa}">>] end, + "[a || <<\"\\x{aaa}\">> <= <<\"\\x{aaa}\">>]. ", + []), + check(fun() -> [a || <<"\x{aaa}"/utf8>> <= <<"\x{aaa}"/utf8>>] end, + "[a || <<\"\\x{aaa}\"/utf8>> <= <<\"\\x{aaa}\"/utf8>>]. ", + [a]), + + ok. + funs(doc) -> ["Simple cases, just to cover some code."]; funs(suite) -> diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 564f27a512..36229b6989 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -58,7 +58,8 @@ otp_8051/1, format_warn/1, on_load_successful/1, on_load_failing/1, - too_many_arguments/1 + too_many_arguments/1, + basic_errors/1,bin_syntax_errors/1 ]). % Default timetrap timeout (set in init_per_testcase). @@ -84,7 +85,7 @@ all() -> otp_5878, otp_5917, otp_6585, otp_6885, otp_10436, export_all, bif_clash, behaviour_basic, behaviour_multiple, otp_7550, otp_8051, format_warn, {group, on_load}, - too_many_arguments]. + too_many_arguments, basic_errors, bin_syntax_errors]. groups() -> [{unused_vars_warn, [], @@ -1351,7 +1352,17 @@ guard(Config) when is_list(Config) -> (is_record(X, apa)*2)]. ">>, [], - []}], + []}, + {guard8, + <<"t(A) when erlang:is_foobar(A) -> ok; + t(A) when A ! ok -> ok; + t(A) when A ++ [x] -> ok." + >>, + [], + {errors,[{1,erl_lint,illegal_guard_expr}, + {2,erl_lint,illegal_guard_expr}, + {3,erl_lint,illegal_guard_expr}],[]}} + ], ?line [] = run(Config, Ts1), ok. @@ -1639,6 +1650,7 @@ otp_5276(Config) when is_list(Config) -> -deprecated([{'_','_',never}]). -deprecated([{{badly,formed},1}]). -deprecated([{'_','_',next_major_release}]). + -deprecated([{atom_to_list,1}]). -export([t/0]). frutt() -> ok. t() -> ok. @@ -1649,8 +1661,9 @@ otp_5276(Config) when is_list(Config) -> {3,erl_lint,{invalid_deprecated,'foo bar'}}, {5,erl_lint,{bad_deprecated,{f,'_'}}}, {8,erl_lint,{invalid_deprecated,{'_','_',never}}}, - {9,erl_lint,{invalid_deprecated,{{badly,formed},1}}}], - [{12,erl_lint,{unused_function,{frutt,0}}}]}}], + {9,erl_lint,{invalid_deprecated,{{badly,formed},1}}}, + {11,erl_lint,{bad_deprecated,{atom_to_list,1}}}], + [{13,erl_lint,{unused_function,{frutt,0}}}]}}], ?line [] = run(Config, Ts), ok. @@ -1896,9 +1909,23 @@ otp_5362(Config) when is_list(Config) -> warn_deprecated_function, warn_bif_clash]}, {errors, - [{2,erl_lint,disallowed_nowarn_bif_clash}],[]}} + [{2,erl_lint,disallowed_nowarn_bif_clash}],[]}}, - ], + {call_deprecated_function, + <<"t(X) -> erlang:hash(X, 2000).">>, + [], + {warnings, + [{1,erl_lint,{deprecated,{erlang,hash,2}, + {erlang,phash2,2},"in a future release"}}]}}, + + {call_removed_function, + <<"t(X) -> regexp:match(X).">>, + [], + {warnings, + [{1,erl_lint,{removed,{regexp,match,1}, + "removed in R15; use the re module instead"}}]}} + + ], ?line [] = run(Config, Ts), ok. @@ -2971,6 +2998,77 @@ too_many_arguments(Config) when is_list(Config) -> ok. +%% Test some basic errors to improve coverage. +basic_errors(Config) -> + Ts = [{redefine_module, + <<"-module(redefine_module).">>, + [], + {errors,[{1,erl_lint,redefine_module}],[]}}, + + {attr_after_function, + <<"f() -> ok. + -attr(x).">>, + [], + {errors,[{2,erl_lint,{attribute,attr}}],[]}}, + + {redefine_function, + <<"f() -> ok. + f() -> ok.">>, + [], + {errors,[{2,erl_lint,{redefine_function,{f,0}}}],[]}}, + + {redefine_record, + <<"-record(r, {a}). + -record(r, {a}). + f(#r{}) -> ok.">>, + [], + {errors,[{2,erl_lint,{redefine_record,r}}],[]}}, + + {illegal_record_info, + <<"f1() -> record_info(42, record). + f2() -> record_info(shoe_size, record).">>, + [], + {errors,[{1,erl_lint,illegal_record_info}, + {2,erl_lint,illegal_record_info}],[]}}, + + {illegal_expr, + <<"f() -> a:b.">>, + [], + {errors,[{1,erl_lint,illegal_expr}],[]}}, + + {illegal_pattern, + <<"f(A+B) -> ok.">>, + [], + {errors,[{1,erl_lint,illegal_pattern}],[]}} + ], + [] = run(Config, Ts), + ok. + +%% Test binary syntax errors +bin_syntax_errors(Config) -> + Ts = [{bin_syntax_errors, + <<"t(<<X:bad_size>>) -> X; + t(<<_:(x ! y)/integer>>) -> ok; + t(<<X:all/integer>>) -> X; + t(<<X/bad_type>>) -> X; + t(<<X/unit:8>>) -> X; + t(<<X:7/float>>) -> X; + t(<< <<_:8>> >>) -> ok; + t(<<(x ! y):8/integer>>) -> ok. + ">>, + [], + {error,[{1,erl_lint,illegal_bitsize}, + {2,erl_lint,illegal_bitsize}, + {3,erl_lint,illegal_bitsize}, + {4,erl_lint,{undefined_bittype,bad_type}}, + {5,erl_lint,bittype_unit}, + {7,erl_lint,illegal_pattern}, + {8,erl_lint,illegal_pattern}], + [{6,erl_lint,{bad_bitsize,"float"}}]}} + ], + [] = run(Config, Ts), + ok. + run(Config, Tests) -> F = fun({N,P,Ws,E}, BadL) -> case catch run_test(Config, P, Ws) of diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk index 33d7a57cc3..c1467697e3 100644 --- a/lib/stdlib/vsn.mk +++ b/lib/stdlib/vsn.mk @@ -1 +1 @@ -STDLIB_VSN = 1.19 +STDLIB_VSN = 1.19.1 diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 43330d2c91..4c39c604a2 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -186,7 +186,7 @@ do_cover_compile1([M|Rest]) -> {ok,_} -> ok; Error -> - io:fwrite("\nWARNING: Could not cover compile ~w: ~tp\n", + io:fwrite("\nWARNING: Could not cover compile ~w: ~p\n", [M,Error]) end, code:stick_mod(M), @@ -196,7 +196,7 @@ do_cover_compile1([M|Rest]) -> {module,_} -> do_cover_compile1([M|Rest]); Error -> - io:fwrite("\nWARNING: Could not load ~w: ~tp\n",[M,Error]), + io:fwrite("\nWARNING: Could not load ~w: ~p\n",[M,Error]), do_cover_compile1(Rest) end; {false,_} -> @@ -204,7 +204,7 @@ do_cover_compile1([M|Rest]) -> {ok,_} -> ok; Error -> - io:fwrite("\nWARNING: Could not cover compile ~w: ~tp\n", + io:fwrite("\nWARNING: Could not cover compile ~w: ~p\n", [M,Error]) end, do_cover_compile1(Rest) @@ -286,7 +286,7 @@ cover_analyse(Analyse,Modules,Stop) -> {ok,{M,{Cov,NotCov}}} -> {M,{Cov,NotCov,DetailsFun(M)}}; Err -> - io:fwrite("WARNING: Analysis failed for ~w. Reason: ~tp\n", + io:fwrite("WARNING: Analysis failed for ~w. Reason: ~p\n", [M,Err]), {M,Err} end @@ -498,7 +498,7 @@ run_test_case_msgloop(#st{ref=Ref,pid=Pid,end_conf_pid=EndConfPid0}=St0) -> exit(Pid, kill), %% here's the only place we know Reason, so we save %% it as a comment, potentially replacing user data - Error = lists:flatten(io_lib:format("Aborted: ~tp", + Error = lists:flatten(io_lib:format("Aborted: ~p", [Reason])), Error1 = lists:flatten([string:strip(S,left) || S <- string:tokens(Error, @@ -742,8 +742,8 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) -> timer:sleep(1), group_leader() ! {printout,12, "WARNING! " - "~w:end_per_testcase(~w, ~tp)" - " crashed!\n\tReason: ~tp\n", + "~w:end_per_testcase(~w, ~p)" + " crashed!\n\tReason: ~p\n", [Mod,Func,Conf,Why]}; _ -> ok @@ -756,8 +756,8 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) -> Starter ! {self(),{call_end_conf,Data,ok}}; {'EXIT',Pid,Reason} -> group_leader() ! {printout,12, - "WARNING! ~w:end_per_testcase(~w, ~tp)" - " failed!\n\tReason: ~tp\n", + "WARNING! ~w:end_per_testcase(~w, ~p)" + " failed!\n\tReason: ~p\n", [Mod,Func,Conf,Reason]}, Starter ! {self(),{call_end_conf,Data,{error,Reason}}}; {'EXIT',_OtherPid,Reason} -> @@ -802,7 +802,7 @@ spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid, {Result,E} end, group_leader() ! {printout,12, - "WARNING! ~w:end_per_testcase(~w, ~tp)" + "WARNING! ~w:end_per_testcase(~w, ~p)" " failed!\n\tReason: timetrap timeout" " after ~w ms!\n", [Mod,Func,EndConf,TVal]}, FailLoc = proplists:get_value(tc_fail_loc, EndConf), @@ -1180,7 +1180,7 @@ do_init_per_testcase(Mod, Args) -> Bad -> group_leader() ! {printout,12, "ERROR! init_per_testcase has returned " - "bad elements in Config: ~tp\n",[Bad]}, + "bad elements in Config: ~p\n",[Bad]}, {skip,{failed,{Mod,init_per_testcase,bad_return}}} end; {fail,_Reason}=Res -> @@ -1197,7 +1197,7 @@ do_init_per_testcase(Mod, Args) -> FormattedLoc = test_server_sup:format_loc(Line), group_leader() ! {printout,12, "ERROR! init_per_testcase thrown!\n" - "\tLocation: ~ts\n\tReason: ~tp\n", + "\tLocation: ~ts\n\tReason: ~p\n", [FormattedLoc, Other]}, {skip,{failed,{Mod,init_per_testcase,Other}}}; _:Reason0 -> @@ -1208,7 +1208,7 @@ do_init_per_testcase(Mod, Args) -> FormattedLoc = test_server_sup:format_loc(Line), group_leader() ! {printout,12, "ERROR! init_per_testcase crashed!\n" - "\tLocation: ~ts\n\tReason: ~tp\n", + "\tLocation: ~ts\n\tReason: ~p\n", [FormattedLoc,Reason]}, {skip,{failed,{Mod,init_per_testcase,Reason}}} end. @@ -1249,7 +1249,7 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) -> "</font>\n",[Comment0,EndFunc])), group_leader() ! {printout,12, "WARNING: ~w thrown!\n" - "Reason: ~tp\n" + "Reason: ~p\n" "Line: ~ts\n", [EndFunc, Other, test_server_sup:format_loc(get_loc())]}, @@ -1271,7 +1271,7 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) -> "</font>\n",[Comment0,EndFunc])), group_leader() ! {printout,12, "WARNING: ~w crashed!\n" - "Reason: ~tp\n" + "Reason: ~p\n" "Line: ~ts\n", [EndFunc, Reason, test_server_sup:format_loc(get_loc())]}, @@ -1351,7 +1351,7 @@ lookup_config(Key,Config) -> {value,{Key,Val}} -> Val; _ -> - io:format("Could not find element ~tp in Config.~n",[Key]), + io:format("Could not find element ~p in Config.~n",[Key]), undefined end. @@ -1433,7 +1433,7 @@ format(Detail, Format, Args) -> Str = case catch io_lib:format(Format,Args) of {'EXIT',_} -> - io_lib:format("illegal format; ~tp with args ~tp.\n", + io_lib:format("illegal format; ~p with args ~p.\n", [Format,Args]); Valid -> Valid end, @@ -1564,7 +1564,7 @@ fail(Reason) -> cast_to_list(X) when is_list(X) -> X; cast_to_list(X) when is_atom(X) -> atom_to_list(X); -cast_to_list(X) -> lists:flatten(io_lib:format("~tp", [X])). +cast_to_list(X) -> lists:flatten(io_lib:format("~p", [X])). @@ -1735,7 +1735,7 @@ ensure_timetrap(Config) -> Garbage -> erase(test_server_default_timetrap), format("=== WARNING: garbage in " - "test_server_default_timetrap: ~tp~n", + "test_server_default_timetrap: ~p~n", [Garbage]) end, DTmo = case lists:keysearch(default_timeout,1,Config) of @@ -1743,7 +1743,7 @@ ensure_timetrap(Config) -> _ -> ?DEFAULT_TIMETRAP_SECS end, format("=== test_server setting default " - "timetrap of ~tp seconds~n", + "timetrap of ~p seconds~n", [DTmo]), put(test_server_default_timetrap, timetrap(seconds(DTmo))) end. @@ -1764,7 +1764,7 @@ cancel_default_timetrap(true) -> Garbage -> erase(test_server_default_timetrap), format("=== WARNING: garbage in " - "test_server_default_timetrap: ~tp~n", + "test_server_default_timetrap: ~p~n", [Garbage]), error end. @@ -1773,7 +1773,7 @@ time_ms({hours,N}, _, _) -> hours(N); time_ms({minutes,N}, _, _) -> minutes(N); time_ms({seconds,N}, _, _) -> seconds(N); time_ms({Other,_N}, _, _) -> - format("=== ERROR: Invalid time specification: ~tp. " + format("=== ERROR: Invalid time specification: ~p. " "Should be seconds, minutes, or hours.~n", [Other]), exit({invalid_time_format,Other}); time_ms(Ms, _, _) when is_integer(Ms) -> Ms; diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index e5d75e43c9..70cb6fa220 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -92,7 +92,7 @@ -define(raw_cross_coverlog_name, "cross_cover.log"). -define(cross_cover_info, "cross_cover.info"). -define(cover_total, "total_cover.log"). --define(unexpected_io_log, "unexpected_io.log"). +-define(unexpected_io_log, "unexpected_io.log.html"). -define(last_file, "last_name"). -define(last_link, "last_link"). -define(last_test, "last_test"). @@ -229,7 +229,7 @@ parse_cmd_line(['SPEC',Spec|Cmds], SpecList, Names, Param, Trc, Cov, TCCB) -> parse_cmd_line(Cmds, TermList++SpecList, [Name|Names], Param, Trc, Cov, TCCB); {error,Reason} -> - io:format("Can't open ~w: ~tp\n",[Spec, file:format_error(Reason)]), + io:format("Can't open ~w: ~p\n",[Spec, file:format_error(Reason)]), parse_cmd_line(Cmds, SpecList, Names, Param, Trc, Cov, TCCB) end; parse_cmd_line(['NAME',Name|Cmds], SpecList, Names, Param, Trc, Cov, TCCB) -> @@ -1013,7 +1013,7 @@ handle_info({'EXIT',Pid,Reason}, State) -> killed -> io:format("Suite ~ts was killed\n", [Name]); _Other -> - io:format("Suite ~ts was killed with reason ~tp\n", + io:format("Suite ~ts was killed with reason ~p\n", [Name,Reason]) end, State2 = State#state{jobs=NewJobs}, @@ -1058,7 +1058,7 @@ handle_info({tcp,_MainSock,<<1,Request/binary>>}, State) -> %% because the job is finished. Then the above clause ('EXIT') will %% handle the problem. io:format("Suite ~ts was killed on remote target with reason" - " ~tp\n", [Name,Reason]); + " ~p\n", [Name,Reason]); _ -> ignore end, @@ -1192,10 +1192,10 @@ init_tester(Mod, Func, Args, Dir, Name, {_,_,MinLev}=Levels, {'EXIT',test_suites_done} -> ok; {'EXIT',_Pid,Reason} -> - print(1, "EXIT, reason ~tp", [Reason]); + print(1, "EXIT, reason ~p", [Reason]); {'EXIT',Reason} -> report_severe_error(Reason), - print(1, "EXIT, reason ~tp", [Reason]) + print(1, "EXIT, reason ~p", [Reason]) end, Time = TimeMy/1000000, SuccessStr = @@ -1285,7 +1285,7 @@ do_spec(SpecName, TimetrapSpec) when is_list(SpecName) -> {ok,TermList} -> do_spec_list(TermList,TimetrapSpec); {error,Reason} -> - io:format("Can't open ~ts: ~tp\n", [SpecName,Reason]), + io:format("Can't open ~ts: ~p\n", [SpecName,Reason]), {error,{cant_open_spec,Reason}} end. @@ -1368,7 +1368,7 @@ do_spec_terms([{require_nodenames,NumNames}|Terms], TopCases, SkipList, Config) do_spec_terms(Terms, TopCases, SkipList, update_config(Config, {nodenames,NodeNames})); do_spec_terms([Other|Terms], TopCases, SkipList, Config) -> - io:format("** WARNING: Spec file contains unknown directive ~tp\n", + io:format("** WARNING: Spec file contains unknown directive ~p\n", [Other]), do_spec_terms(Terms, TopCases, SkipList, Config). @@ -1507,7 +1507,7 @@ do_test_cases(TopCases, SkipCases, FwMod = get_fw_mod(?MODULE), case collect_all_cases(TopCases, SkipCases) of {error,Why} -> - print(1, "Error starting: ~tp", [Why]), + print(1, "Error starting: ~p", [Why]), exit(test_suites_done); TestSpec0 -> N = case remove_conf(TestSpec0) of @@ -1531,6 +1531,7 @@ do_test_cases(TopCases, SkipCases, TestDescr = "Test " ++ TestName ++ " results", test_server_sup:framework_call(report, [tests_start,{Test,N}]), + {Header,Footer} = case test_server_sup:framework_call(get_html_wrapper, [TestDescr,true,TestDir, @@ -1616,7 +1617,7 @@ do_test_cases(TopCases, SkipCases, print(major, "=emulator_vsn ~ts", [TI#target_info.version]), print(major, "=emulator ~ts", [TI#target_info.emulator]), print(major, "=otp_release ~ts", [TI#target_info.otp_release]), - print(major, "=started ~ts", + print(major, "=started ~s", [lists:flatten(timestamp_get(""))]), put(test_server_html_footer, Footer), @@ -1667,19 +1668,36 @@ start_log_file() -> MkDirError2 -> log_file_error(MkDirError2, TestDir) end, - ok = write_file(filename:join(Dir, ?last_file), TestDir1 ++ "\n"), - ok = write_file(?last_file, TestDir1 ++ "\n"), + FilenameMode = file:native_name_encoding(), + ok = write_file(filename:join(Dir, ?last_file), + TestDir1 ++ "\n", + FilenameMode), + ok = write_file(?last_file, TestDir1 ++ "\n", FilenameMode), put(test_server_log_dir_base,TestDir1), MajorName = filename:join(TestDir1, ?suitelog_name), HtmlName = MajorName ++ ?html_ext, UnexpectedName = filename:join(TestDir1, ?unexpected_io_log), - {ok,Major} = open_file(MajorName), + {ok,Major} = open_utf8_file(MajorName), {ok,Html} = open_html_file(HtmlName), - {ok,Unexpected} = open_file(UnexpectedName), + {ok,Unexpected} = open_html_file(UnexpectedName), test_server_io:set_fd(major, Major), test_server_io:set_fd(html, Html), test_server_io:set_fd(unexpected_io, Unexpected), + {UnexpHeader,UnexpFooter} = + case test_server_sup:framework_call(get_html_wrapper, + ["Unexpected I/O log",false, + TestDir, undefined],"") of + UEmpty when (UEmpty == "") ; (element(2,UEmpty) == "") -> + {html_header("Unexpected I/O log"),"\n</body>\n</html>\n"}; + {basic_html,UH,UF} -> + {UH,UF}; + {xhtml,UH,UF} -> + {UH,UF} + end, + io:put_chars(Unexpected, UnexpHeader++"\n<pre>\n"), + put(test_server_unexpected_footer,UnexpFooter), + make_html_link(filename:absname(?last_test ++ ?html_ext), HtmlName, filename:basename(Dir)), LinkName = filename:join(Dir, ?last_link), @@ -1892,9 +1910,9 @@ copy_html_file(Src, DestDir) -> Dest = filename:join(DestDir, filename:basename(Src)), case file:read_file(Src) of {ok,Bin} -> - ok = write_file(Dest, Bin); + ok = write_binary_file(Dest, Bin); {error,_Reason} -> - io:format("File ~tp: read failed\n", [Src]) + io:format("File ~ts: read failed\n", [Src]) end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2073,7 +2091,7 @@ run_test_cases(TestSpec, Config, TimetrapData) -> [OkN,FailedN,SkipStr,OkN+FailedN+AllSkippedN]), test_server_sup:framework_call(report, [tests_done, {OkN,FailedN,{UserSkipN,AutoSkipN}}]), - print(major, "=finished ~ts", [lists:flatten(timestamp_get(""))]), + print(major, "=finished ~s", [lists:flatten(timestamp_get(""))]), print(major, "=failed ~w", [FailedN]), print(major, "=successful ~w", [OkN]), print(major, "=user_skipped ~w", [UserSkipN]), @@ -2609,7 +2627,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0, TimetrapData, Mode, Status2); Bad -> print(minor, - "~n*** ~w returned bad elements in Config: ~tp.~n", + "~n*** ~w returned bad elements in Config: ~p.~n", [Func,Bad]), Reason = {failed,{Mod,init_per_suite,bad_return}}, Cases2 = skip_cases_upto(Ref, Cases, Reason, conf, CurrMode), @@ -2624,9 +2642,9 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0, stop_minor_log_file(), run_test_cases_loop(Cases, [NewCfg|Config], TimetrapData, Mode, Status2); {_,{framework_error,{FwMod,FwFunc},Reason},_} -> - print(minor, "~n*** ~w failed in ~w. Reason: ~tp~n", + print(minor, "~n*** ~w failed in ~w. Reason: ~p~n", [FwMod,FwFunc,Reason]), - print(1, "~w failed in ~w. Reason: ~tp~n", [FwMod,FwFunc,Reason]), + print(1, "~w failed in ~w. Reason: ~p~n", [FwMod,FwFunc,Reason]), exit(framework_error); {_,Fail,_} when element(1,Fail) == 'EXIT'; element(1,Fail) == timetrap_timeout; @@ -2768,9 +2786,9 @@ run_test_cases_loop([{Mod,Func,Args}|Cases], Config, TimetrapData, Mode, Status) run_init, TimetrapData, Mode) of %% callback to framework module failed, exit immediately {_,{framework_error,{FwMod,FwFunc},Reason},_} -> - print(minor, "~n*** ~w failed in ~w. Reason: ~tp~n", + print(minor, "~n*** ~w failed in ~w. Reason: ~p~n", [FwMod,FwFunc,Reason]), - print(1, "~w failed in ~w. Reason: ~tp~n", [FwMod,FwFunc,Reason]), + print(1, "~w failed in ~w. Reason: ~p~n", [FwMod,FwFunc,Reason]), stop_minor_log_file(), exit(framework_error); %% sequential execution of test case finished @@ -2942,8 +2960,8 @@ print_conf_time(ConfTime) -> print_props(_, []) -> ok; print_props(true, Props) -> - print(major, "=group_props ~tp", [Props]), - print(minor, "Group properties: ~tp~n", [Props]); + print(major, "=group_props ~p", [Props]), + print(minor, "Group properties: ~p~n", [Props]); print_props(_, _) -> ok. @@ -3094,7 +3112,7 @@ skip_case1(Type, CaseNum, Mod, Func, Comment, Mode) -> Comment1 = reason_to_string(Comment), print(major, "~n=case ~w:~w", [Mod,Func]), - print(major, "=started ~ts", [lists:flatten(timestamp_get(""))]), + print(major, "=started ~s", [lists:flatten(timestamp_get(""))]), print(major, "=result skipped: ~ts", [Comment1]), print(2,"*** Skipping test case #~w ~w ***", [CaseNum,{Mod,Func}]), TR = xhtml("<tr valign=\"top\">", ["<tr class=\"",odd_or_even(),"\">"]), @@ -3292,7 +3310,7 @@ wait_and_resend(Ref, [{_,CurrPid,CaseNum,Mod,Func}|Ps] = Cases, Ok,Skip,Fail) -> {'EXIT',CurrPid,Reason} when Reason /= normal -> %% unexpected termination of test case process {value,{_,_,CaseNum,Mod,Func}} = lists:keysearch(CurrPid, 2, Cases), - print(1, "Error! Process for test case #~w (~w:~w) died! Reason: ~tp", + print(1, "Error! Process for test case #~w (~w:~w) died! Reason: ~p", [CaseNum, Mod, Func, Reason]), exit({unexpected_termination,{CaseNum,Mod,Func},{CurrPid,Reason}}) end; @@ -3431,7 +3449,7 @@ handle_io_and_exits(Main, CurrPid, CaseNum, Mod, Func, Cases) -> {'EXIT',TCPid,Reason} when Reason /= normal -> test_server_io:print_buffered(CurrPid), {value,{_,_,Num,M,F}} = lists:keysearch(TCPid, 2, Cases), - print(1, "Error! Process for test case #~w (~w:~w) died! Reason: ~tp", + print(1, "Error! Process for test case #~w (~w:~w) died! Reason: ~p", [Num, M, F, Reason]), exit({unexpected_termination,{Num,M,F},{TCPid,Reason}}) end. @@ -3546,7 +3564,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, undefined -> ""; Name -> cast_to_list(Name) end, - print(major, "=started ~ts", [lists:flatten(timestamp_get(""))]), + print(major, "=started ~s", [lists:flatten(timestamp_get(""))]), {{Col0,Col1},Style} = get_font_style((RunInit==run_init), Mode), TR = xhtml("<tr valign=\"top\">", ["<tr class=\"",odd_or_even(),"\">"]), EncMinorBase = uri_encode(MinorBase), @@ -3573,7 +3591,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, print(minor, "<a name=\"end\"></a>", [], internal_raw), print(minor, "\n", [], internal_raw), print_timestamp(minor, "Ended at "), - print(major, "=ended ~ts", [lists:flatten(timestamp_get(""))]), + print(major, "=ended ~s", [lists:flatten(timestamp_get(""))]), do_unless_parallel(Main, fun() -> file:set_cwd(filename:dirname(TSDir)) end), @@ -3657,13 +3675,13 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, {'EXIT',_} = Exit -> print(minor, "WARNING: There might be slavenodes left in the" - " system. I tried to kill them, but I failed: ~tp\n", + " system. I tried to kill them, but I failed: ~p\n", [Exit]); [] -> ok; List -> print(minor, "WARNING: ~w slave nodes in system after test"++ "case. Tried to killed them.~n"++ - " Names:~tp", + " Names:~p", [length(List),List]) end; false -> @@ -3752,7 +3770,7 @@ progress(skip, CaseNum, Mod, Func, Loc, Reason, Time, progress(failed, CaseNum, Mod, Func, Loc, timetrap_timeout, T, Comment0, {St0,St1}) -> - print(major, "=result failed: timeout, ~tp", [Loc]), + print(major, "=result failed: timeout, ~p", [Loc]), print(1, "*** FAILED *** ~ts", [get_info_str(Func, CaseNum, get(test_server_cases))]), test_server_sup:framework_call(report, @@ -3778,7 +3796,7 @@ progress(failed, CaseNum, Mod, Func, Loc, timetrap_timeout, T, progress(failed, CaseNum, Mod, Func, Loc, {testcase_aborted,Reason}, _T, Comment0, {St0,St1}) -> - print(major, "=result failed: testcase_aborted, ~tp", [Loc]), + print(major, "=result failed: testcase_aborted, ~p", [Loc]), print(1, "*** FAILED *** ~ts", [get_info_str(Func, CaseNum, get(test_server_cases))]), test_server_sup:framework_call(report, @@ -3799,12 +3817,12 @@ progress(failed, CaseNum, Mod, Func, Loc, {testcase_aborted,Reason}, _T, [Comment]), FormatLoc = test_server_sup:format_loc(Loc), print(minor, "=== location ~ts", [FormatLoc]), - print(minor, "=== reason = {testcase_aborted,~tp}", [Reason]), + print(minor, "=== reason = {testcase_aborted,~p}", [Reason]), failed; progress(failed, CaseNum, Mod, Func, unknown, Reason, Time, Comment0, {St0,St1}) -> - print(major, "=result failed: ~tp, ~w", [Reason,unknown]), + print(major, "=result failed: ~p, ~w", [Reason,unknown]), print(1, "*** FAILED *** ~ts", [get_info_str(Func, CaseNum, get(test_server_cases))]), test_server_sup:framework_call(report, [tc_done,{Mod,Func, @@ -3812,7 +3830,7 @@ progress(failed, CaseNum, Mod, Func, unknown, Reason, Time, TimeStr = io_lib:format(if is_float(Time) -> "~.3fs"; true -> "~w" end, [Time]), - ErrorReason = lists:flatten(io_lib:format("~tp", [Reason])), + ErrorReason = lists:flatten(io_lib:format("~p", [Reason])), ErrorReason1 = lists:flatten([string:strip(S,left) || S <- string:tokens(ErrorReason,[$\n])]), ErrorReason2 = @@ -3840,7 +3858,7 @@ progress(failed, CaseNum, Mod, Func, unknown, Reason, Time, progress(failed, CaseNum, Mod, Func, Loc, Reason, Time, Comment0, {St0,St1}) -> - print(major, "=result failed: ~tp, ~tp", [Reason,Loc]), + print(major, "=result failed: ~p, ~p", [Reason,Loc]), print(1, "*** FAILED *** ~ts", [get_info_str(Func, CaseNum, get(test_server_cases))]), test_server_sup:framework_call(report, [tc_done,{Mod,Func, @@ -3885,13 +3903,13 @@ progress(ok, _CaseNum, Mod, Func, _Loc, RetVal, Time, _ -> "<td>" ++ to_string(Comment0) ++ "</td>" end end, - print(major, "=elapsed ~tp", [Time]), + print(major, "=elapsed ~p", [Time]), print(html, "<td>" ++ St0 ++ "~.3fs" ++ St1 ++ "</td>" "<td><font color=\"green\">Ok</font></td>" "~ts</tr>\n", [Time,Comment]), - print(minor, "=== returned value = ~tp", [RetVal]), + print(minor, "=== returned value = ~p", [RetVal]), ok. %%-------------------------------------------------------------------- @@ -3968,11 +3986,11 @@ print_if_known(Known, {SK,AK}, {SU,AU}) -> to_string(Term) when is_list(Term) -> case (catch io_lib:format("~ts", [Term])) of - {'EXIT',_} -> lists:flatten(io_lib:format("~tp", [Term])); + {'EXIT',_} -> lists:flatten(io_lib:format("~p", [Term])); String -> lists:flatten(String) end; to_string(Term) -> - lists:flatten(io_lib:format("~tp", [Term])). + lists:flatten(io_lib:format("~p", [Term])). get_last_loc(Loc) when is_tuple(Loc) -> Loc; @@ -4044,14 +4062,14 @@ format_exception(Reason={_Error,Stack}) when is_list(Stack) -> undefined -> case application:get_env(test_server, format_exception) of {ok,false} -> - {"~tp",Reason}; + {"~p",Reason}; _ -> do_format_exception(Reason) end; FW -> case application:get_env(FW, format_exception) of {ok,false} -> - {"~tp",Reason}; + {"~p",Reason}; _ -> do_format_exception(Reason) end @@ -4066,7 +4084,7 @@ do_format_exception(Reason={Error,Stack}) -> end, case catch lib:format_exception(1, error, Error, Stack, StackFun, PF) of {'EXIT',_} -> - {"~tp",Reason}; + {"~p",Reason}; Formatted -> Formatted1 = re:replace(Formatted, "exception error: ", "", [{return,list}]), {"~ts",lists:flatten(Formatted1)} @@ -4175,7 +4193,7 @@ format(Detail, Format, Args) -> Str = case catch io_lib:format(Format, Args) of {'EXIT',_} -> - io_lib:format("illegal format; ~tp with args ~tp.\n", + io_lib:format("illegal format; ~p with args ~p.\n", [Format,Args]); Valid -> Valid end, @@ -4555,7 +4573,7 @@ collect_files(Dir, Pattern, St) -> Wc = filename:join([Dir1,Pattern++code:objfile_extension()]), case catch filelib:wildcard(Wc) of {'EXIT', Reason} -> - io:format("Could not collect files: ~tp~n", [Reason]), + io:format("Could not collect files: ~p~n", [Reason]), {error,{collect_fail,Dir,Pattern}}; Mods0 -> Mods = [{path_to_module(Mod),all} || Mod <- lists:sort(Mods0)], @@ -4588,16 +4606,16 @@ check_deny([], _DenyList) -> granted; check_deny(Req, DenyList) -> check_deny([Req], DenyList). check_deny_req({Req,Val}, DenyList) -> - %%io:format("ValCheck ~tp=~tp in ~tp\n", [Req,Val,DenyList]), + %%io:format("ValCheck ~p=~p in ~p\n", [Req,Val,DenyList]), case lists:keysearch(Req, 1, DenyList) of {value,{_Req,DenyVal}} when Val >= DenyVal -> - {denied,io_lib:format("Requirement ~tp=~tp", [Req,Val])}; + {denied,io_lib:format("Requirement ~p=~p", [Req,Val])}; _ -> check_deny_req(Req, DenyList) end; check_deny_req(Req, DenyList) -> case lists:member(Req, DenyList) of - true -> {denied,io_lib:format("Requirement ~tp", [Req])}; + true -> {denied,io_lib:format("Requirement ~p", [Req])}; false -> granted end. @@ -4698,7 +4716,7 @@ get_target_info() -> start_node(Name, Type, Options) -> T = 10 * ?ACCEPT_TIMEOUT * test_server:timetrap_scale_factor(), - format(minor, "Attempt to start ~w node ~tp with options ~tp", + format(minor, "Attempt to start ~w node ~p with options ~p", [Type, Name, Options]), case controller_call({start_node,Name,Type,Options}, T) of {{ok,Nodename}, Host, Cmd, Info, Warning} -> @@ -4720,16 +4738,16 @@ start_node(Name, Type, Options) -> {fail,{Ret, Host, Cmd}} -> format(minor, "Failed to start node ~tp on ~tp with command: ~tp~n" - "Reason: ~tp", + "Reason: ~p", [Name, Host, Cmd, Ret]), {fail,Ret}; {Ret, undefined, undefined} -> - format(minor, "Failed to start node ~tp: ~tp", [Name,Ret]), + format(minor, "Failed to start node ~tp: ~p", [Name,Ret]), Ret; {Ret, Host, Cmd} -> format(minor, "Failed to start node ~tp on ~tp with command: ~tp~n" - "Reason: ~tp", + "Reason: ~p", [Name, Host, Cmd, Ret]), Ret end. @@ -4943,11 +4961,11 @@ read_cover_file(CoverFile) -> case check_cover_file(List, [], [], []) of {ok,Exclude,Include,Cross} -> {Exclude,Include,Cross}; error -> - io:fwrite("Faulty format of CoverFile ~tp\n", [CoverFile]), + io:fwrite("Faulty format of CoverFile ~p\n", [CoverFile]), {[],[],[]} end; {error,Reason} -> - io:fwrite("Can't read CoverFile ~ts\nReason: ~tp\n", + io:fwrite("Can't read CoverFile ~ts\nReason: ~p\n", [CoverFile,Reason]), {[],[],[]} end. @@ -5021,7 +5039,8 @@ cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, Stop, TestDir) -> case length(cover:imported_modules()) of Imps when Imps > 0 -> - io:fwrite(CoverLog, "<p>Analysis includes data from ~w imported module(s).\n", + io:fwrite(CoverLog, + "<p>Analysis includes data from ~w imported module(s).\n", [Imps]); _ -> ok @@ -5030,8 +5049,8 @@ cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, Stop, TestDir) -> io:fwrite(CoverLog, "<p>Excluded module(s): <code>~tp</code>\n", [Excluded]), Coverage = cover_analyse(Analyse, AnalyseMods, Stop), - write_file(filename:join(TestDir,?raw_coverlog_name), - term_to_binary(Coverage)), + write_binary_file(filename:join(TestDir,?raw_coverlog_name), + term_to_binary(Coverage)), case lists:filter(fun({_M,{_,_,_}}) -> false; (_) -> true @@ -5045,7 +5064,8 @@ cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, Stop, TestDir) -> end, TotPercent = write_cover_result_table(CoverLog, Coverage), - write_file(filename:join(TestDir, ?cover_total),term_to_binary(TotPercent)). + write_binary_file(filename:join(TestDir, ?cover_total), + term_to_binary(TotPercent)). cover_analyse(Analyse, AnalyseMods, Stop) -> TestDir = get(test_server_log_dir_base), @@ -5092,17 +5112,16 @@ cross_cover_analyse(Analyse, TagDirs0) -> write_cross_cover_info(_Dir,[]) -> ok; write_cross_cover_info(Dir,Cross) -> - {ok,Fd} = open_file(filename:join(Dir,?cross_cover_info)), - lists:foreach(fun(C) -> io:format(Fd,"~tp.~n",[C]) end, Cross), - ok = file:close(Fd). + write_binary_file(filename:join(Dir,?cross_cover_info), + term_to_binary(Cross)). %% For each test from which there are cross cover analysed %% modules, write a cross cover log (cross_cover.html). write_cross_cover_logs([{Tag,Coverage}|T],TagDirMods) -> case lists:keyfind(Tag,1,TagDirMods) of {_,Dir,Mods} when Mods=/=[] -> - write_file(filename:join(Dir,?raw_cross_coverlog_name), - term_to_binary(Coverage)), + write_binary_file(filename:join(Dir,?raw_cross_coverlog_name), + term_to_binary(Coverage)), CoverLogName = filename:join(Dir,?cross_coverlog_name), {ok,CoverLog} = open_html_file(CoverLogName), write_coverlog_header(CoverLog), @@ -5140,8 +5159,9 @@ get_latest_dir([],Latest) -> Latest. get_all_cross_info([{_Tag,Dir}|Rest],Acc) -> - case file:consult(filename:join(Dir,?cross_cover_info)) of - {ok,TagMods} -> + case file:read_file(filename:join(Dir,?cross_cover_info)) of + {ok,Bin} -> + TagMods = binary_to_term(Bin), get_all_cross_info(Rest,TagMods++Acc); _ -> get_all_cross_info(Rest,Acc) @@ -5198,7 +5218,7 @@ write_coverlog_header(CoverLog) -> {'EXIT',Reason} -> io:format("\n\nERROR: Could not write normal heading in coverlog.\n" "CoverLog: ~w\n" - "Reason: ~tp\n", + "Reason: ~p\n", [CoverLog,Reason]), io:format(CoverLog,"<html><body>\n", []); _ -> @@ -5321,17 +5341,24 @@ html_header(Title) -> "link=\"blue\" vlink=\"purple\" alink=\"red\">\n"]. open_html_file(File) -> - file:open(File,[write,{encoding,utf8}]). + open_utf8_file(File). write_html_file(File,Content) -> - file:write_file(File,unicode:characters_to_binary(Content)). + write_file(File,Content,utf8). +%% The 'major' log file, which is a pure text file is also written +%% with utf8 encoding +open_utf8_file(File) -> + file:open(File,[write,{encoding,utf8}]). -%% Text files are written with default encoding -open_file(File) -> - file:open(File,[write]). +%% Write a file with specified encoding +write_file(File,Content,latin1) -> + file:write_file(File,Content); +write_file(File,Content,utf8) -> + write_binary_file(File,unicode:characters_to_binary(Content)). -write_file(File,Content) -> +%% Write a file with only binary data +write_binary_file(File,Content) -> file:write_file(File,Content). %% Encoding of hyperlinks in HTML files diff --git a/lib/test_server/src/test_server_gl.erl b/lib/test_server/src/test_server_gl.erl index 0ab0d58040..766a4537a2 100644 --- a/lib/test_server/src/test_server_gl.erl +++ b/lib/test_server/src/test_server_gl.erl @@ -159,7 +159,15 @@ handle_call({print,Detail,Msg,Printer}, {From,_}, St) -> handle_cast(stop, St) -> {stop,normal,St}. -handle_info({'DOWN',Ref,process,_,_}, #st{minor_monitor=Ref}=St) -> +handle_info({'DOWN',Ref,process,_,Reason}=D, #st{minor_monitor=Ref}=St) -> + case Reason of + normal -> ok; + _ -> + Data = io_lib:format("=== WARNING === TC: ~w\n" + "Got down from minor Fd ~w: ~w\n\n", + [St#st.tc,St#st.minor,D]), + test_server_io:print(xxxFrom, unexpected_io, Data) + end, {noreply,St#st{minor=none,minor_monitor=none}}; handle_info({permit_io,Pid}, #st{permit_io=P}=St) -> {noreply,St#st{permit_io=gb_sets:add(Pid, P)}}; @@ -253,12 +261,19 @@ output_to_file(minor, Data0, From, #st{tc={M,F,A},minor=none}) -> Data = [io_lib:format("=== ~w:~w/~w\n", [M,F,A]),Data0], test_server_io:print(From, unexpected_io, Data), ok; -output_to_file(minor, Data, From, #st{minor=Fd}) -> +output_to_file(minor, Data, From, #st{tc=TC,minor=Fd}) -> try io:put_chars(Fd, Data) catch - _:_ -> - test_server_io:print(From, unexpected_io, Data) + Type:Reason -> + Data1 = + [io_lib:format("=== ERROR === TC: ~w\n" + "Failed to write to minor Fd: ~w\n" + "Type: ~w\n" + "Reason: ~w\n", + [TC,Fd,Type,Reason]), + Data,"\n"], + test_server_io:print(From, unexpected_io, Data1) end; output_to_file(Detail, Data, From, _) -> test_server_io:print(From, Detail, Data). diff --git a/lib/test_server/src/test_server_h.erl b/lib/test_server/src/test_server_h.erl index c624947306..24063ddb10 100644 --- a/lib/test_server/src/test_server_h.erl +++ b/lib/test_server/src/test_server_h.erl @@ -142,7 +142,7 @@ report_receiver(_, _) -> none. tag({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) -> io:format(user, "~n=TESTCASE: ~w:~w/~w", [M,F,A]); tag(Testcase) -> - io:format(user, "~n=TESTCASE: ~tp", [Testcase]). + io:format(user, "~n=TESTCASE: ~p", [Testcase]). tag_event(Event) -> {calendar:local_time(), Event}. diff --git a/lib/test_server/src/test_server_io.erl b/lib/test_server/src/test_server_io.erl index 662ee11515..242c08f765 100644 --- a/lib/test_server/src/test_server_io.erl +++ b/lib/test_server/src/test_server_io.erl @@ -235,7 +235,7 @@ handle_info(kill_group_leaders, #st{gls=Gls,stopping=From}=St) -> gen_server:reply(From, ok), {stop,normal,St}; handle_info(Other, St) -> - io:format("Ignoring: ~tp\n", [Other]), + io:format("Ignoring: ~p\n", [Other]), {noreply,St}. terminate(_, _) -> @@ -261,7 +261,7 @@ do_output(stdout, Str0, #st{job_name=Name}) -> do_output(Tag, Str, #st{fds=Fds}=St) -> case gb_trees:lookup(Tag, Fds) of none -> - S = io_lib:format("\n*** ERROR: ~w, line ~w: No known '~tp' log file\n", + S = io_lib:format("\n*** ERROR: ~w, line ~w: No known '~p' log file\n", [?MODULE,?LINE,Tag]), do_output(stdout, [S,Str], St); {value,Fd} -> @@ -273,7 +273,7 @@ do_output(Tag, Str, #st{fds=Fds}=St) -> end catch _:Error -> S = io_lib:format("\n*** ERROR: ~w, line ~w: Error writing to " - "log file '~tp': ~tp\n", + "log file '~p': ~p\n", [?MODULE,?LINE,Tag,Error]), do_output(stdout, [S,Str], St) end diff --git a/lib/test_server/src/test_server_node.erl b/lib/test_server/src/test_server_node.erl index 62248af4db..54a49b31ca 100644 --- a/lib/test_server/src/test_server_node.erl +++ b/lib/test_server/src/test_server_node.erl @@ -249,7 +249,7 @@ print_trc(Out,{trace_ts,P,call,{M,F,A},C,Ts},N) -> "~w: ~s~n" "Process : ~w~n" "Call : ~w:~w/~w~n" - "Arguments : ~tp~n" + "Arguments : ~p~n" "Caller : ~w~n~n", [N,ts(Ts),P,M,F,length(A),A,C]); print_trc(Out,{trace_ts,P,call,{M,F,A},Ts},N) -> @@ -257,14 +257,14 @@ print_trc(Out,{trace_ts,P,call,{M,F,A},Ts},N) -> "~w: ~s~n" "Process : ~w~n" "Call : ~w:~w/~w~n" - "Arguments : ~tp~n~n", + "Arguments : ~p~n~n", [N,ts(Ts),P,M,F,length(A),A]); print_trc(Out,{trace_ts,P,return_from,{M,F,A},R,Ts},N) -> io:format(Out, "~w: ~s~n" "Process : ~w~n" "Return from : ~w:~w/~w~n" - "Return value : ~tp~n~n", + "Return value : ~p~n~n", [N,ts(Ts),P,M,F,A,R]); print_trc(Out,{drop,X},N) -> io:format(Out, @@ -274,7 +274,7 @@ print_trc(Out,Trace,N) -> Ts = element(size(Trace),Trace), io:format(Out, "~w: ~s~n" - "Trace : ~tp~n~n", + "Trace : ~p~n~n", [N,ts(Ts),Trace]). ts({_, _, Micro} = Now) -> {{Y,M,D},{H,Min,S}} = calendar:now_to_local_time(Now), @@ -465,8 +465,8 @@ handle_start_node_return(Version,VsnStr,{started, Node, OVersion, OVsnStr}) -> Str = io_lib:format("WARNING: Started node " "reports different system " "version than current node! " - "Current node version: ~tp, ~tp " - "Started node version: ~tp, ~tp", + "Current node version: ~p, ~p " + "Started node version: ~p, ~p", [Version, VsnStr, OVersion, OVsnStr]), Str1 = lists:flatten(Str), diff --git a/lib/test_server/src/test_server_sup.erl b/lib/test_server/src/test_server_sup.erl index cd96568970..377aa21018 100644 --- a/lib/test_server/src/test_server_sup.erl +++ b/lib/test_server/src/test_server_sup.erl @@ -75,7 +75,7 @@ timetrap(Timeout0, ReportTVal, Scale, Pid) -> "Testcase process ~w not " "responding to timetrap " "timeout:~n" - " ~tp.~n" + " ~p.~n" "Killing testcase...~n", [Pid, Trap]), exit(Pid, kill) @@ -142,11 +142,11 @@ call_crash(Time,Crash,M,F,A) -> {'EXIT',Pid,_Reason} when Crash==any -> ok; {'EXIT',Reason} -> - test_server:format(12, "Wrong crash reason. Wanted ~tp, got ~tp.", + test_server:format(12, "Wrong crash reason. Wanted ~p, got ~p.", [Crash, Reason]), exit({wrong_crash_reason,Reason}); {'EXIT',Pid,Reason} -> - test_server:format(12, "Wrong crash reason. Wanted ~tp, got ~tp.", + test_server:format(12, "Wrong crash reason. Wanted ~p, got ~p.", [Crash, Reason]), exit({wrong_crash_reason,Reason}); {'EXIT',OtherPid,Reason} when OldTrapExit == false -> @@ -312,7 +312,7 @@ check_dict(Dict, Reason) -> [] -> 1; % All ok. List -> - io:format("** ~ts (~ts) ->~n~tp~n",[Reason, Dict, List]), + io:format("** ~ts (~ts) ->~n~p~n",[Reason, Dict, List]), 0 end. @@ -321,7 +321,7 @@ check_dict_tolerant(Dict, Reason, Mode) -> [] -> 1; % All ok. List -> - io:format("** ~ts (~ts) ->~n~tp~n",[Reason, Dict, List]), + io:format("** ~ts (~ts) ->~n~p~n",[Reason, Dict, List]), case Mode of pedantic -> 0; @@ -397,7 +397,7 @@ append_files_to_logfile([File|Files]) -> %% fail, but in that case it will throw an exception so that %% we will be aware of the problem. io:format(Fd, "Unable to write the crash dump " - "to this file: ~tp~n", [file:format_error(Error)]) + "to this file: ~p~n", [file:format_error(Error)]) end; _Error -> io:format(Fd, "Failed to read: ~ts\n", [File]) @@ -555,7 +555,7 @@ format_loc([{Mod,LineOrFunc}]) -> format_loc({Mod,Func}) when is_atom(Func) -> io_lib:format("{~w,~w}",[Mod,Func]); format_loc(Loc) -> - io_lib:format("~tp",[Loc]). + io_lib:format("~p",[Loc]). format_loc1([{Mod,Func,Line}]) -> [" ",format_loc1({Mod,Func,Line}),"]"]; diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl index 468225dc13..2579711dc7 100644 --- a/lib/tools/src/cover.erl +++ b/lib/tools/src/cover.erl @@ -1372,10 +1372,15 @@ do_compile_beam(Module,Beam,UserOptions) -> Forms0 = epp:interpret_file_attribute(Code), {Forms,Vars} = transform(Vsn, Forms0, Module, Beam), + %% We need to recover the source from the compilation + %% info otherwise the newly compiled module will have + %% source pointing to the current directory + SourceInfo = get_source_info(Module, Beam), + %% Compile and load the result %% It's necessary to check the result of loading since it may %% fail, for example if Module resides in a sticky directory - {ok, Module, Binary} = compile:forms(Forms, UserOptions), + {ok, Module, Binary} = compile:forms(Forms, SourceInfo ++ UserOptions), case code:load_binary(Module, ?TAG, Binary) of {module, Module} -> @@ -1403,6 +1408,17 @@ get_abstract_code(Module, Beam) -> Error -> Error end. +get_source_info(Module, Beam) -> + case beam_lib:chunks(Beam, [compile_info]) of + {ok, {Module, [{compile_info, Compile}]}} -> + case lists:keyfind(source, 1, Compile) of + { source, _ } = Tuple -> [Tuple]; + false -> [] + end; + _ -> + [] + end. + transform(Vsn, Code, Module, Beam) when Vsn=:=abstract_v1; Vsn=:=abstract_v2 -> Vars0 = #vars{module=Module, vsn=Vsn}, MainFile=find_main_filename(Code), @@ -1783,17 +1799,11 @@ munge_expr({'catch',Line,Expr}, Vars) -> {MungedExpr, Vars2} = munge_expr(Expr, Vars), {{'catch',Line,MungedExpr}, Vars2}; munge_expr({call,Line1,{remote,Line2,ExprM,ExprF},Exprs}, - Vars) when Vars#vars.is_guard=:=false-> + Vars) -> {MungedExprM, Vars2} = munge_expr(ExprM, Vars), {MungedExprF, Vars3} = munge_expr(ExprF, Vars2), {MungedExprs, Vars4} = munge_exprs(Exprs, Vars3, []), {{call,Line1,{remote,Line2,MungedExprM,MungedExprF},MungedExprs}, Vars4}; -munge_expr({call,Line1,{remote,_Line2,_ExprM,ExprF},Exprs}, - Vars) when Vars#vars.is_guard=:=true -> - %% Difference in abstract format after preprocessing: BIF calls in guards - %% are translated to {remote,...} (which is not allowed as source form) - %% NOT NECESSARY FOR Vsn=raw_abstract_v1 - munge_expr({call,Line1,ExprF,Exprs}, Vars); munge_expr({call,Line,Expr,Exprs}, Vars) -> {MungedExpr, Vars2} = munge_expr(Expr, Vars), {MungedExprs, Vars3} = munge_exprs(Exprs, Vars2, []), @@ -1945,7 +1955,7 @@ move_clauses([]) -> %% Given a .beam file, find the .erl file. Look first in same directory as %% the .beam file, then in <beamdir>/../src -find_source(File0) -> +find_source(Module, File0) -> case filename:rootname(File0,".beam") of File0 -> File0; @@ -1962,11 +1972,27 @@ find_source(File0) -> true -> InDotDotSrc; false -> - {beam,File0} + find_source_from_module(Module, File0) end end end. +%% In case we can't find the file from the given .beam, +%% we try to get the information directly from the module source +find_source_from_module(Module, File) -> + Compile = Module:module_info(compile), + case lists:keyfind(source, 1, Compile) of + {source, Path} -> + case filelib:is_file(Path) of + true -> + Path; + false -> + {beam, File} + end; + false -> + {beam, File} + end. + do_parallel_analysis(Module, Analysis, Level, Loaded, From, State) -> analyse_info(Module,State#main_state.imported), C = case Loaded of @@ -2070,7 +2096,7 @@ do_parallel_analysis_to_file(Module, OutFile, Opts, Loaded, From, State) -> {imported, File0, _} -> File0 end, - case find_source(File) of + case find_source(Module, File) of {beam,_BeamFile} -> reply(From, {error,no_source_code_found}); ErlFile -> diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl index 57260a3869..5abc5c41b1 100644 --- a/lib/tools/test/cover_SUITE.erl +++ b/lib/tools/test/cover_SUITE.erl @@ -149,7 +149,9 @@ compile(Config) when is_list(Config) -> ok = beam_lib:crypto_key_fun(simple_crypto_fun(Key)), {ok,crypt} = cover:compile_beam("crypt.beam") end, + Path = filename:join([?config(data_dir, Config), "compile_beam", "v.erl"]), ?line {ok,v} = cover:compile_beam(v), + {source,Path} = lists:keyfind(source, 1, v:module_info(compile)), ?line {ok,w} = cover:compile_beam("w.beam"), ?line {error,{no_abstract_code,"./x.beam"}} = cover:compile_beam(x), ?line {error,{already_cover_compiled,no_beam_found,a}}=cover:compile_beam(a), @@ -277,12 +279,23 @@ analyse(Config) when is_list(Config) -> ?line f:f2(), ?line {ok, "f.COVER.out"} = cover:analyse_to_file(f), - %% Source code cannot be found by analyse_to_file + %% Source code can be found via source ?line {ok,v} = compile:file("compile_beam/v",[debug_info]), ?line code:purge(v), ?line {module,v} = code:load_file(v), ?line {ok,v} = cover:compile_beam(v), - ?line {error,no_source_code_found} = cover:analyse_to_file(v), + {ok,"v.COVER.out"} = cover:analyse_to_file(v), + + %% Source code cannot be found + {ok,_} = file:copy("compile_beam/z.erl", "z.erl"), + {ok,z} = compile:file(z,[debug_info]), + code:purge(z), + {module,z} = code:load_file(z), + {ok,z} = cover:compile_beam(z), + ok = file:delete("z.erl"), + {error,no_source_code_found} = cover:analyse_to_file(z), + code:purge(z), + code:delete(z), ?line {error,{not_cover_compiled,b}} = cover:analyse(b), ?line {error,{not_cover_compiled,g}} = cover:analyse(g), diff --git a/lib/tools/test/cover_SUITE_data/compile_beam/v.erl b/lib/tools/test/cover_SUITE_data/compile_beam/v.erl index 007957297a..7fb0b08d40 100644 --- a/lib/tools/test/cover_SUITE_data/compile_beam/v.erl +++ b/lib/tools/test/cover_SUITE_data/compile_beam/v.erl @@ -1,6 +1,9 @@ -module(v). - --export([f/0]). +-compile({ no_auto_import, [is_integer/1] }). +-export([f/0,f/1]). f() -> ok. + +f(Number) when erlang:is_integer(Number) -> + Number. diff --git a/lib/tools/test/cover_SUITE_data/compile_beam/z.erl b/lib/tools/test/cover_SUITE_data/compile_beam/z.erl new file mode 100644 index 0000000000..7a2b143dde --- /dev/null +++ b/lib/tools/test/cover_SUITE_data/compile_beam/z.erl @@ -0,0 +1 @@ +-module(z). diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk index 892a425124..4fb2f30e4f 100644 --- a/lib/tools/vsn.mk +++ b/lib/tools/vsn.mk @@ -1 +1 @@ -TOOLS_VSN = 2.6.9 +TOOLS_VSN = 2.6.10 |