aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/asn1/c_src/asn1_erl_nif.c5
-rw-r--r--lib/asn1/doc/src/notes.xml29
-rw-r--r--lib/asn1/test/asn1_SUITE.erl13
-rw-r--r--lib/asn1/test/testX420.erl2
-rw-r--r--lib/asn1/test/test_modified_x420.erl22
-rw-r--r--lib/compiler/src/beam_asm.erl2
-rw-r--r--lib/compiler/src/beam_disasm.erl7
-rw-r--r--lib/compiler/src/beam_receive.erl2
-rw-r--r--lib/compiler/src/beam_type.erl23
-rw-r--r--lib/compiler/src/beam_validator.erl14
-rw-r--r--lib/compiler/src/compile.erl6
-rw-r--r--lib/compiler/src/core_lint.erl2
-rw-r--r--lib/compiler/src/sys_core_fold.erl9
-rw-r--r--lib/compiler/test/Makefile1
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl50
-rw-r--r--lib/compiler/test/unused_multiple_values_error.core11
-rw-r--r--lib/kernel/doc/src/specs.xml1
-rw-r--r--lib/kernel/src/inet6_tcp_dist.erl8
-rw-r--r--lib/kernel/src/inet_tcp_dist.erl8
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/odbc/src/odbc.erl4
-rw-r--r--lib/odbc/test/odbc_query_SUITE.erl67
-rw-r--r--lib/odbc/vsn.mk2
-rw-r--r--lib/sasl/src/sasl.appup.src16
-rw-r--r--lib/stdlib/src/erl_lint.erl19
-rw-r--r--lib/stdlib/src/eval_bits.erl64
-rw-r--r--lib/stdlib/src/shell.erl4
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl48
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl112
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/test_server/src/test_server.erl44
-rw-r--r--lib/test_server/src/test_server_ctrl.erl173
-rw-r--r--lib/test_server/src/test_server_gl.erl23
-rw-r--r--lib/test_server/src/test_server_h.erl2
-rw-r--r--lib/test_server/src/test_server_io.erl6
-rw-r--r--lib/test_server/src/test_server_node.erl12
-rw-r--r--lib/test_server/src/test_server_sup.erl14
-rw-r--r--lib/tools/src/cover.erl48
-rw-r--r--lib/tools/test/cover_SUITE.erl17
-rw-r--r--lib/tools/test/cover_SUITE_data/compile_beam/v.erl7
-rw-r--r--lib/tools/test/cover_SUITE_data/compile_beam/z.erl1
-rw-r--r--lib/tools/vsn.mk2
42 files changed, 681 insertions, 223 deletions
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