aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib')
-rw-r--r--lib/stdlib/doc/src/Makefile1
-rw-r--r--lib/stdlib/doc/src/filename.xml34
-rw-r--r--lib/stdlib/src/beam_lib.erl23
-rw-r--r--lib/stdlib/src/dets.erl23
-rw-r--r--lib/stdlib/src/erl_eval.erl15
-rw-r--r--lib/stdlib/src/erl_internal.erl2
-rw-r--r--lib/stdlib/src/erl_parse.yrl2
-rw-r--r--lib/stdlib/src/erl_pp.erl4
-rw-r--r--lib/stdlib/src/filename.erl31
-rw-r--r--lib/stdlib/src/io_lib.erl49
-rw-r--r--lib/stdlib/src/io_lib_format.erl8
-rw-r--r--lib/stdlib/src/ms_transform.erl6
-rw-r--r--lib/stdlib/src/proc_lib.erl128
-rw-r--r--lib/stdlib/test/beam_lib_SUITE.erl32
-rw-r--r--lib/stdlib/test/dets_SUITE.erl15
-rw-r--r--lib/stdlib/test/ets_SUITE.erl45
-rw-r--r--lib/stdlib/test/io_SUITE.erl12
17 files changed, 284 insertions, 146 deletions
diff --git a/lib/stdlib/doc/src/Makefile b/lib/stdlib/doc/src/Makefile
index 2b3860b76a..4541b4a463 100644
--- a/lib/stdlib/doc/src/Makefile
+++ b/lib/stdlib/doc/src/Makefile
@@ -155,6 +155,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml
index ce19f70df0..36254c2d00 100644
--- a/lib/stdlib/doc/src/filename.xml
+++ b/lib/stdlib/doc/src/filename.xml
@@ -84,11 +84,6 @@
reject such filenames.
</p></warning>
</description>
- <datatypes>
- <datatype>
- <name name="basedir_type"/>
- </datatype>
- </datatypes>
<funcs>
<func>
@@ -149,18 +144,37 @@
</func>
<func>
- <name name="basedir" arity="2"/>
- <fsummary>Equivalent to <c>basedir(<anno>Type</anno>,<anno>Application</anno>,#{})</c>.</fsummary>
+ <name name="basedir" arity="2" clause_i="1"/>
+ <name name="basedir" arity="2" clause_i="2"/>
+ <fsummary>Equivalent to <c>basedir(<anno>PathType</anno>,
+ <anno>Application</anno>,#{})</c> or
+ <c>basedir(<anno>PathsType</anno>, <anno>Application</anno>,#{})</c>.
+ </fsummary>
+ <type variable="PathType" name_i="1"/>
+ <type name="basedir_path_type"/>
+ <type variable="PathsType" name_i="2"/>
+ <type name="basedir_paths_type"/>
+ <type variable="Application"/>
<desc>
<p>
- Equivalent to <seealso marker="#basedir-3">
- basedir(<anno>Type</anno>, <anno>Application</anno>, #{})</seealso>.
+ Equivalent to <seealso marker="#basedir_3_1">
+ basedir(<anno>PathType</anno>, <anno>Application</anno>, #{})</seealso>
+ or <seealso marker="#basedir_3_2">
+basedir(<anno>PathsType</anno>, <anno>Application</anno>, #{})</seealso>.
</p>
</desc>
</func>
<func>
- <name name="basedir" arity="3"/>
+ <name name="basedir" arity="3" clause_i="1" anchor="basedir_3_1"/>
+ <name name="basedir" arity="3" clause_i="2" anchor="basedir_3_2"/>
<fsummary></fsummary>
+ <type variable="PathType" name_i="1"/>
+ <type name="basedir_path_type"/>
+ <type variable="PathsType" name_i="2"/>
+ <type name="basedir_paths_type"/>
+ <type variable="Application"/>
+ <type variable="Opts"/>
+ <type name="basedir_opts"/>
<desc><marker id="basedir-3"/>
<p>
Returns a suitable path, or paths, for a given type. If
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index ef4c7d255c..01181b1097 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -690,30 +690,31 @@ chunk_to_data(debug_info=Id, Chunk, File, _Cs, AtomTable, Mod) ->
<<0:8,N:8,Mode0:N/binary,Rest/binary>> ->
Mode = binary_to_atom(Mode0, utf8),
Term = decrypt_chunk(Mode, Mod, File, Id, Rest),
- {AtomTable, {Id, Term}};
+ {AtomTable, {Id, anno_from_term(Term)}};
_ ->
case catch binary_to_term(Chunk) of
{'EXIT', _} ->
error({invalid_chunk, File, chunk_name_to_id(Id, File)});
Term ->
- {AtomTable, {Id, Term}}
+ {AtomTable, {Id, anno_from_term(Term)}}
end
end;
chunk_to_data(abstract_code=Id, Chunk, File, _Cs, AtomTable, Mod) ->
+ %% Before Erlang/OTP 20.0.
case Chunk of
<<>> ->
{AtomTable, {Id, no_abstract_code}};
<<0:8,N:8,Mode0:N/binary,Rest/binary>> ->
Mode = binary_to_atom(Mode0, utf8),
Term = decrypt_chunk(Mode, Mod, File, Id, Rest),
- {AtomTable, {Id, anno_from_term(Term)}};
+ {AtomTable, {Id, old_anno_from_term(Term)}};
_ ->
case catch binary_to_term(Chunk) of
{'EXIT', _} ->
error({invalid_chunk, File, chunk_name_to_id(Id, File)});
Term ->
try
- {AtomTable, {Id, anno_from_term(Term)}}
+ {AtomTable, {Id, old_anno_from_term(Term)}}
catch
_:_ ->
error({invalid_chunk, File,
@@ -947,14 +948,24 @@ decrypt_chunk(Type, Module, File, Id, Bin) ->
error({key_missing_or_invalid, File, Id})
end.
-anno_from_term({raw_abstract_v1, Forms}) ->
+old_anno_from_term({raw_abstract_v1, Forms}) ->
{raw_abstract_v1, anno_from_forms(Forms)};
-anno_from_term({Tag, Forms}) when Tag =:= abstract_v1; Tag =:= abstract_v2 ->
+old_anno_from_term({Tag, Forms}) when Tag =:= abstract_v1;
+ Tag =:= abstract_v2 ->
try {Tag, anno_from_forms(Forms)}
catch
_:_ ->
{Tag, Forms}
end;
+old_anno_from_term(T) ->
+ T.
+
+anno_from_term({debug_info_v1=Tag1, erl_abstract_code=Tag2, {Forms, Opts}}) ->
+ try {Tag1, Tag2, {anno_from_forms(Forms), Opts}}
+ catch
+ _:_ ->
+ {Tag1, Tag2, {Forms, Opts}}
+ end;
anno_from_term(T) ->
T.
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index e016d5a80e..0488c2bef2 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -616,12 +616,18 @@ next(Tab, Key) ->
%% Assuming that a file already exists, open it with the
%% parameters as already specified in the file itself.
%% Return a ref leading to the file.
-open_file(File) ->
- case dets_server:open_file(to_list(File)) of
- badarg -> % Should not happen.
- erlang:error(dets_process_died, [File]);
- Reply ->
- einval(Reply, [File])
+open_file(File0) ->
+ File = to_list(File0),
+ case is_list(File) of
+ true ->
+ case dets_server:open_file(File) of
+ badarg -> % Should not happen.
+ erlang:error(dets_process_died, [File]);
+ Reply ->
+ einval(Reply, [File])
+ end;
+ false ->
+ erlang:error(badarg, [File0])
end.
-spec open_file(Name, Args) -> {'ok', Name} | {'error', Reason} when
@@ -1088,6 +1094,7 @@ defaults(Tab, Args) ->
debug = false},
Fun = fun repl/2,
Defaults = lists:foldl(Fun, Defaults0, Args),
+ true = is_list(Defaults#open_args.file),
is_comp_min_max(Defaults).
to_list(T) when is_atom(T) -> atom_to_list(T);
@@ -1112,9 +1119,7 @@ repl({delayed_write, {Delay,Size} = C}, Defs)
Defs#open_args{delayed_write = C};
repl({estimated_no_objects, I}, Defs) ->
repl({min_no_slots, I}, Defs);
-repl({file, File}, Defs) when is_list(File) ->
- Defs#open_args{file = File};
-repl({file, File}, Defs) when is_atom(File) ->
+repl({file, File}, Defs) ->
Defs#open_args{file = to_list(File)};
repl({keypos, P}, Defs) when is_integer(P), P > 0 ->
Defs#open_args{keypos =P};
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 31c0e60fe1..2066b2f60f 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -329,7 +329,8 @@ expr({'fun',Line,{clauses,Cs}} = Ex, Bs, Lf, Ef, RBs) ->
20 -> fun (A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T) ->
eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T], Info) end;
_Other ->
- erlang:raise(error, {'argument_limit',{'fun',Line,Cs}},
+ L = erl_anno:location(Line),
+ erlang:raise(error, {'argument_limit',{'fun',L,to_terms(Cs)}},
?STACKTRACE)
end,
ret_expr(F, Bs, RBs);
@@ -381,7 +382,9 @@ expr({named_fun,Line,Name,Cs} = Ex, Bs, Lf, Ef, RBs) ->
eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T],
RF, Info) end;
_Other ->
- erlang:raise(error, {'argument_limit',{named_fun,Line,Name,Cs}},
+ L = erl_anno:location(Line),
+ erlang:raise(error, {'argument_limit',
+ {named_fun,L,Name,to_terms(Cs)}},
?STACKTRACE)
end,
ret_expr(F, Bs, RBs);
@@ -1092,7 +1095,7 @@ match(Pat, Term, Bs) ->
match(Pat, Term, Bs, BBs) ->
case catch match1(Pat, Term, Bs, BBs) of
invalid ->
- erlang:raise(error, {illegal_pattern,Pat}, ?STACKTRACE);
+ erlang:raise(error, {illegal_pattern,to_term(Pat)}, ?STACKTRACE);
Other ->
Other
end.
@@ -1288,6 +1291,12 @@ merge_bindings(Bs1, Bs2) ->
%% end
%% end, Bs2, Bs1).
+to_terms(Abstrs) ->
+ [to_term(Abstr) || Abstr <- Abstrs].
+
+to_term(Abstr) ->
+ erl_parse:anno_to_term(Abstr).
+
%% Substitute {value, A, Item} for {var, A, Var}, preserving A.
%% {value, A, Item} is a shell/erl_eval convention, and for example
%% the linter cannot handle it.
diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl
index b311a843c2..939abaff00 100644
--- a/lib/stdlib/src/erl_internal.erl
+++ b/lib/stdlib/src/erl_internal.erl
@@ -74,6 +74,7 @@ guard_bif(element, 2) -> true;
guard_bif(float, 1) -> true;
guard_bif(floor, 1) -> true;
guard_bif(hd, 1) -> true;
+guard_bif(is_map_key, 2) -> true;
guard_bif(length, 1) -> true;
guard_bif(map_size, 1) -> true;
guard_bif(map_get, 2) -> true;
@@ -109,7 +110,6 @@ new_type_test(is_function, 2) -> true;
new_type_test(is_integer, 1) -> true;
new_type_test(is_list, 1) -> true;
new_type_test(is_map, 1) -> true;
-new_type_test(is_map_key, 2) -> true;
new_type_test(is_number, 1) -> true;
new_type_test(is_pid, 1) -> true;
new_type_test(is_port, 1) -> true;
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 3390cee8ae..9602f0bcd9 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -980,7 +980,7 @@ Erlang code.
-type af_unary_op(T) :: {'op', anno(), unary_op(), T}.
--type unary_op() :: '+' | '*' | 'bnot' | 'not'.
+-type unary_op() :: '+' | '-' | 'bnot' | 'not'.
%% See also lib/stdlib/{src/erl_bits.erl,include/erl_bits.hrl}.
-type type_specifier_list() :: 'default' | [type_specifier(), ...].
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 367dbefb82..dd302a2880 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -59,7 +59,7 @@
_ -> ?TEST(T)
end).
-define(EXPRS_TEST(L),
- [?TEST(E) || E <- L]).
+ _ = [?TEST(E) || E <- L]).
-define(TEST(T),
%% Assumes that erl_anno has been compiled with DEBUG=true.
%% erl_pp does not use the annoations, but test it anyway.
diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl
index a322bd002d..b7b7b562ab 100644
--- a/lib/stdlib/src/filename.erl
+++ b/lib/stdlib/src/filename.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1012,24 +1012,33 @@ filename_string_to_binary(List) ->
%% basedir
%% http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
--type basedir_type() :: 'user_cache' | 'user_config' | 'user_data'
- | 'user_log'
- | 'site_config' | 'site_data'.
+-type basedir_path_type() :: 'user_cache' | 'user_config' | 'user_data'
+ | 'user_log'.
+-type basedir_paths_type() :: 'site_config' | 'site_data'.
--spec basedir(Type,Application) -> file:filename_all() when
- Type :: basedir_type(),
+-type basedir_opts() :: #{author => string() | binary(),
+ os => 'windows' | 'darwin' | 'linux',
+ version => string() | binary()}.
+
+-spec basedir(PathType,Application) -> file:filename_all() when
+ PathType :: basedir_path_type(),
+ Application :: string() | binary();
+ (PathsType,Application) -> [file:filename_all()] when
+ PathsType :: basedir_paths_type(),
Application :: string() | binary().
basedir(Type,Application) when is_atom(Type), is_list(Application) orelse
is_binary(Application) ->
basedir(Type, Application, #{}).
--spec basedir(Type,Application,Opts) -> file:filename_all() when
- Type :: basedir_type(),
+-spec basedir(PathType,Application,Opts) -> file:filename_all() when
+ PathType :: basedir_path_type(),
+ Application :: string() | binary(),
+ Opts :: basedir_opts();
+ (PathsType,Application,Opts) -> [file:filename_all()] when
+ PathsType :: basedir_paths_type(),
Application :: string() | binary(),
- Opts :: #{author => string() | binary(),
- os => 'windows' | 'darwin' | 'linux',
- version => string() | binary()}.
+ Opts :: basedir_opts().
basedir(Type,Application,Opts) when is_atom(Type), is_map(Opts),
is_list(Application) orelse
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index 3a5aba60b4..8223a52873 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -178,11 +178,11 @@ fread(Cont, Chars, Format) ->
Data :: [term()].
format(Format, Args) ->
- case catch io_lib_format:fwrite(Format, Args) of
- {'EXIT',_} ->
- erlang:error(badarg, [Format, Args]);
- Other ->
- Other
+ try io_lib_format:fwrite(Format, Args)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [Format, Args])
end.
-spec format(Format, Data, Options) -> chars() when
@@ -193,11 +193,11 @@ format(Format, Args) ->
CharsLimit :: chars_limit().
format(Format, Args, Options) ->
- case catch io_lib_format:fwrite(Format, Args, Options) of
- {'EXIT',_} ->
- erlang:error(badarg, [Format, Args, Options]);
- Other ->
- Other
+ try io_lib_format:fwrite(Format, Args, Options)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [Format, Args])
end.
-spec scan_format(Format, Data) -> FormatList when
@@ -208,7 +208,9 @@ format(Format, Args, Options) ->
scan_format(Format, Args) ->
try io_lib_format:scan(Format, Args)
catch
- _:_ -> erlang:error(badarg, [Format, Args])
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [Format, Args])
end.
-spec unscan_format(FormatList) -> {Format, Data} when
@@ -223,7 +225,12 @@ unscan_format(FormatList) ->
FormatList :: [char() | format_spec()].
build_text(FormatList) ->
- io_lib_format:build(FormatList).
+ try io_lib_format:build(FormatList)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [FormatList])
+ end.
-spec build_text(FormatList, Options) -> chars() when
FormatList :: [char() | format_spec()],
@@ -232,7 +239,23 @@ build_text(FormatList) ->
CharsLimit :: chars_limit().
build_text(FormatList, Options) ->
- io_lib_format:build(FormatList, Options).
+ try io_lib_format:build(FormatList, Options)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [FormatList, Options])
+ end.
+
+%% Failure to load a module must not be labeled as badarg.
+%% C, R, and S are included so that the original error, which could be
+%% a bug in io_lib_format, can be found by tracing on
+%% test_modules_loaded/3.
+test_modules_loaded(_C, _R, _S) ->
+ Modules = [io_lib_format, io_lib_pretty, string, unicode],
+ case code:ensure_modules_loaded(Modules) of
+ ok -> ok;
+ Error -> erlang:error(Error)
+ end.
-spec print(Term) -> chars() when
Term :: term().
diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index c814ab50d4..e247b00a04 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -38,18 +38,16 @@
%% and it also splits the handling of the control characters into two
%% parts.
--spec fwrite(Format, Data) -> FormatList when
+-spec fwrite(Format, Data) -> io_lib:chars() when
Format :: io:format(),
- Data :: [term()],
- FormatList :: [char() | io_lib:format_spec()].
+ Data :: [term()].
fwrite(Format, Args) ->
build(scan(Format, Args)).
--spec fwrite(Format, Data, Options) -> FormatList when
+-spec fwrite(Format, Data, Options) -> io_lib:chars() when
Format :: io:format(),
Data :: [term()],
- FormatList :: [char() | io_lib:format_spec()],
Options :: [Option],
Option :: {'chars_limit', CharsLimit},
CharsLimit :: io_lib:chars_limit().
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index d117481d2e..3845e35e9b 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -224,10 +224,12 @@ transform_from_shell(Dialect, Clauses, BoundEnvironment) ->
%% Called when translating during compiling
%%
--spec parse_transform(Forms, Options) -> Forms2 when
+-spec parse_transform(Forms, Options) -> Forms2 | Errors | Warnings when
Forms :: [erl_parse:abstract_form() | erl_parse:form_info()],
Forms2 :: [erl_parse:abstract_form() | erl_parse:form_info()],
- Options :: term().
+ Options :: term(),
+ Errors :: {error, ErrInfo :: [tuple()], WarnInfo :: []},
+ Warnings :: {warning, Forms2, WarnInfo :: [tuple()]}.
parse_transform(Forms, _Options) ->
SaveFilename = setup_filename(),
diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl
index 89a840be2d..d07c62500b 100644
--- a/lib/stdlib/src/proc_lib.erl
+++ b/lib/stdlib/src/proc_lib.erl
@@ -30,7 +30,7 @@
start/3, start/4, start/5, start_link/3, start_link/4, start_link/5,
hibernate/3,
init_ack/1, init_ack/2,
- init_p/3,init_p/5,format/1,format/2,format/3,report_cb/1,
+ init_p/3,init_p/5,format/1,format/2,format/3,report_cb/2,
initial_call/1,
translate_initial_call/1,
stop/1, stop/3]).
@@ -509,7 +509,7 @@ crash_report(Class, Reason, StartF, Stacktrace) ->
report=>[my_info(Class, Reason, StartF, Stacktrace),
linked_info(self())]},
#{domain=>[otp,sasl],
- report_cb=>fun proc_lib:report_cb/1,
+ report_cb=>fun proc_lib:report_cb/2,
logger_formatter=>#{title=>"CRASH REPORT"},
error_logger=>#{tag=>error_report,type=>crash_report}}).
@@ -750,14 +750,15 @@ check(Res) -> Res.
%%% Format a generated crash info structure.
%%% -----------------------------------------------------------
--spec report_cb(CrashReport) -> {Format,Args} when
- CrashReport :: #{label=>{proc_lib,crash},report=>[term()]},
- Format :: io:format(),
- Args :: [term()].
-report_cb(#{label:={proc_lib,crash},
- report:=CrashReport}) ->
- Depth = error_logger:get_format_depth(),
- get_format_and_args(CrashReport, utf8, Depth).
+-spec report_cb(CrashReport,FormatOpts) -> unicode:chardata() when
+ CrashReport :: #{label => {proc_lib,crash},
+ report => [term()]},
+ FormatOpts :: logger:report_cb_config().
+report_cb(#{label:={proc_lib,crash}, report:=CrashReport}, Extra) ->
+ Default = #{chars_limit => unlimited,
+ depth => unlimited,
+ encoding => latin1},
+ do_format(CrashReport, maps:merge(Default,Extra)).
-spec format(CrashReport) -> string() when
CrashReport :: [term()].
@@ -777,66 +778,47 @@ format(CrashReport, Encoding) ->
Depth :: unlimited | pos_integer().
format(CrashReport, Encoding, Depth) ->
- {F,A} = get_format_and_args(CrashReport, Encoding, Depth),
- lists:flatten(io_lib:format(F,A)).
+ do_format(CrashReport, #{chars_limit => unlimited,
+ depth => Depth,
+ encoding => Encoding}).
-get_format_and_args([OwnReport,LinkReport], Encoding, Depth) ->
- Extra = {Encoding,Depth},
+do_format([OwnReport,LinkReport], Extra) ->
MyIndent = " ",
- {OwnFormat,OwnArgs} = format_report(OwnReport, MyIndent, Extra, [], []),
- {LinkFormat,LinkArgs} = format_link_report(LinkReport, MyIndent, Extra, [], []),
- {" crasher:~n"++OwnFormat++" neighbours:~n"++LinkFormat,OwnArgs++LinkArgs}.
+ OwnFormat = format_report(OwnReport, MyIndent, Extra),
+ LinkFormat = format_link_report(LinkReport, MyIndent, Extra),
+ Str = io_lib:format(" crasher:~n~ts neighbours:~n~ts",
+ [OwnFormat, LinkFormat]),
+ lists:flatten(Str).
-format_link_report([], _Indent, _Extra, Format, Args) ->
- {lists:flatten(lists:reverse(Format)),lists:append(lists:reverse(Args))};
-format_link_report([Link|Reps], Indent, Extra, Format, Args) ->
+format_link_report([Link|Reps], Indent, Extra) ->
Rep = case Link of
{neighbour,Rep0} -> Rep0;
_ -> Link
end,
LinkIndent = [" ",Indent],
- {LinkFormat,LinkArgs} = format_report(Rep, LinkIndent, Extra, [], []),
- F = "~sneighbour:\n"++LinkFormat,
- A = [Indent|LinkArgs],
- format_link_report(Reps, Indent, Extra, [F|Format], [A|Args]);
-format_link_report(Rep, Indent, Extra, Format, Args) ->
- {F,A} = format_report(Rep, Indent, Extra, [], []),
- format_link_report([], Indent, Extra, [F|Format],[A|Args]).
-
-format_report([], _Indent, _Extra, Format, Args) ->
- {lists:flatten(lists:reverse(Format)),lists:append(lists:reverse(Args))};
-format_report([Rep|Reps], Indent, Extra, Format, Args) ->
- {F,A} = format_rep(Rep, Indent, Extra),
- format_report(Reps, Indent, Extra, [F|Format], [A|Args]);
-format_report(Rep, Indent, {Enc,unlimited}=Extra, Format, Args) ->
- {F,A} = {"~s~"++modifier(Enc)++"p~n", [Indent, Rep]},
- format_report([], Indent, Extra, [F|Format], [A|Args]);
-format_report(Rep, Indent, {Enc,Depth}=Extra, Format, Args) ->
- {F,A} = {"~s~"++modifier(Enc)++"P~n", [Indent, Rep, Depth]},
- format_report([], Indent, Extra, [F|Format], [A|Args]).
-
-format_rep({initial_call,InitialCall}, Indent, Extra) ->
- format_mfa(Indent, InitialCall, Extra);
-format_rep({error_info,{Class,Reason,StackTrace}}, _Indent, Extra) ->
- {lists:flatten(format_exception(Class, Reason, StackTrace, Extra)),[]};
-format_rep({Tag,Data}, Indent, Extra) ->
- format_tag(Indent, Tag, Data, Extra).
-
-format_mfa(Indent, {M,F,Args}=StartF, {Enc,_}=Extra) ->
- try
- A = length(Args),
- {lists:flatten([Indent,"initial call: ",atom_to_list(M),
- $:,to_string(F, Enc),$/,integer_to_list(A),"\n"]),[]}
- catch
- error:_ ->
- format_tag(Indent, initial_call, StartF, Extra)
- end.
-
-format_tag(Indent, Tag, Data, {Enc,Depth}) ->
- {P,Tl} = p(Enc, Depth),
- {"~s~p: ~80.18" ++ P ++ "\n", [Indent, Tag, Data|Tl]}.
+ [Indent,"neighbour:\n",format_report(Rep, LinkIndent, Extra)|
+ format_link_report(Reps, Indent, Extra)];
+format_link_report(Rep, Indent, Extra) ->
+ format_report(Rep, Indent, Extra).
+
+format_report(Rep, Indent, Extra) when is_list(Rep) ->
+ format_rep(Rep, Indent, Extra);
+format_report(Rep, Indent, #{encoding:=Enc,depth:=unlimited}) ->
+ io_lib:format("~s~"++modifier(Enc)++"p~n", [Indent, Rep]);
+format_report(Rep, Indent, #{encoding:=Enc,depth:=Depth}) ->
+ io_lib:format("~s~"++modifier(Enc)++"P~n", [Indent, Rep, Depth]).
+
+format_rep([{initial_call,InitialCall}|Rep], Indent, Extra) ->
+ [format_mfa(Indent, InitialCall, Extra)|format_rep(Rep, Indent, Extra)];
+format_rep([{error_info,{Class,Reason,StackTrace}}|Rep], Indent, Extra) ->
+ [format_exception(Class, Reason, StackTrace, Extra)|
+ format_rep(Rep, Indent, Extra)];
+format_rep([{Tag,Data}|Rep], Indent, Extra) ->
+ [format_tag(Indent, Tag, Data, Extra)|format_rep(Rep, Indent, Extra)];
+format_rep(_, _, _Extra) ->
+ [].
-format_exception(Class, Reason, StackTrace, {Enc,_}=Extra) ->
+format_exception(Class, Reason, StackTrace, #{encoding:=Enc}=Extra) ->
PF = pp_fun(Extra),
StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
%% EI = " exception: ",
@@ -844,17 +826,37 @@ format_exception(Class, Reason, StackTrace, {Enc,_}=Extra) ->
[EI, erl_error:format_exception(1+length(EI), Class, Reason,
StackTrace, StackFun, PF, Enc), "\n"].
+format_mfa(Indent, {M,F,Args}=StartF, #{encoding:=Enc}=Extra) ->
+ try
+ A = length(Args),
+ [Indent,"initial call: ",atom_to_list(M),$:,to_string(F, Enc),$/,
+ integer_to_list(A),"\n"]
+ catch
+ error:_ ->
+ format_tag(Indent, initial_call, StartF, Extra)
+ end.
+
to_string(A, latin1) ->
io_lib:write_atom_as_latin1(A);
to_string(A, _) ->
io_lib:write_atom(A).
-pp_fun({Enc,Depth}) ->
+pp_fun(#{encoding:=Enc,depth:=Depth,chars_limit:=Limit}) ->
{P,Tl} = p(Enc, Depth),
+ Opts = if is_integer(Limit) -> [{chars_limit,Limit}];
+ true -> []
+ end,
fun(Term, I) ->
- io_lib:format("~." ++ integer_to_list(I) ++ P, [Term|Tl])
+ io_lib:format("~." ++ integer_to_list(I) ++ P, [Term|Tl], Opts)
end.
+format_tag(Indent, Tag, Data, #{encoding:=Enc,depth:=Depth,chars_limit:=Limit}) ->
+ {P,Tl} = p(Enc, Depth),
+ Opts = if is_integer(Limit) -> [{chars_limit,Limit}];
+ true -> []
+ end,
+ io_lib:format("~s~p: ~80.18" ++ P ++ "\n", [Indent, Tag, Data|Tl], Opts).
+
p(Encoding, Depth) ->
{Letter, Tl} = case Depth of
unlimited -> {"p", []};
diff --git a/lib/stdlib/test/beam_lib_SUITE.erl b/lib/stdlib/test/beam_lib_SUITE.erl
index 73219f8fd8..3597d6d94b 100644
--- a/lib/stdlib/test/beam_lib_SUITE.erl
+++ b/lib/stdlib/test/beam_lib_SUITE.erl
@@ -78,7 +78,7 @@ normal(Conf) when is_list(Conf) ->
BeamFile = Simple ++ ".beam",
simple_file(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
do_normal(Source, PrivDir, BeamFile, []),
@@ -95,7 +95,7 @@ normal(Conf) when is_list(Conf) ->
file:delete(BeamFile),
file:delete(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
true = (P0 == pps()),
ok.
@@ -173,7 +173,7 @@ error(Conf) when is_list(Conf) ->
WrongFile = Simple ++ "foo.beam",
simple_file(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
{ok,_} = compile:file(Source, [{outdir,PrivDir},debug_info]),
ACopy = filename:join(PrivDir, "a_copy.beam"),
@@ -213,7 +213,7 @@ error(Conf) when is_list(Conf) ->
%% we have eliminated them.
ok = file:write_file(BeamFile, <<"FOR1",5:32,"BEAMfel">>),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
true = (P0 == pps()),
file:delete(Source),
file:delete(WrongFile),
@@ -273,7 +273,7 @@ cmp(Conf) when is_list(Conf) ->
{Source2D1, BeamFile2D1} = make_beam(Dir1, simple2, concat),
{SourceD2, BeamFileD2} = make_beam(Dir2, simple, concat),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
%% cmp
@@ -300,7 +300,7 @@ cmp(Conf) when is_list(Conf) ->
ver(not_a_directory, beam_lib:diff_dirs(foo, bar)),
true = (P0 == pps()),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
delete_files([SourceD1, BeamFileD1, Source2D1,
BeamFile2D1, SourceD2, BeamFileD2]),
@@ -321,7 +321,7 @@ cmp_literals(Conf) when is_list(Conf) ->
{SourceD1, BeamFileD1} = make_beam(Dir1, simple, constant),
{SourceD2, BeamFileD2} = make_beam(Dir2, simple, constant2),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
%% cmp
@@ -334,7 +334,7 @@ cmp_literals(Conf) when is_list(Conf) ->
ver(chunks_different, beam_lib:cmp(B1, B2)),
true = (P0 == pps()),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
delete_files([SourceD1, BeamFileD1, SourceD2, BeamFileD2]),
@@ -351,7 +351,7 @@ strip(Conf) when is_list(Conf) ->
{Source4D1, BeamFile4D1} = make_beam(PrivDir, constant, constant),
{Source5D1, BeamFile5D1} = make_beam(PrivDir, lines, lines),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
%% strip binary
@@ -392,7 +392,7 @@ strip(Conf) when is_list(Conf) ->
(catch lines:t(atom)),
true = (P0 == pps()),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
delete_files([SourceD1, BeamFileD1,
Source2D1, BeamFile2D1,
@@ -457,7 +457,7 @@ building(Conf) when is_list(Conf) ->
{SourceD1, BeamFileD1} = make_beam(Dir1, building, member),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
%% read all chunks
@@ -487,7 +487,7 @@ building(Conf) when is_list(Conf) ->
end, ChunkIds),
true = (P0 == pps()),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
delete_files([SourceD1, BeamFileD1, BeamFileD2]),
file:del_dir(Dir1),
@@ -535,7 +535,7 @@ encrypted_abstr_1(Conf) ->
%% Avoid getting an extra port when crypto starts erl_ddll.
erl_ddll:start(),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
Key = "#a_crypto_key",
@@ -549,7 +549,7 @@ encrypted_abstr_1(Conf) ->
ok = crypto:stop(), %To get rid of extra ets tables.
file:delete(BeamFile),
file:delete(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
true = (P0 == pps()),
ok.
@@ -658,7 +658,7 @@ encrypted_abstr_file_1(Conf) ->
%% Avoid getting an extra port when crypto starts erl_ddll.
erl_ddll:start(),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
Key = "Long And niCe 99Krypto Key",
@@ -676,7 +676,7 @@ encrypted_abstr_file_1(Conf) ->
file:delete(filename:join(PrivDir, ".erlang.crypt")),
file:delete(BeamFile),
file:delete(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
true = (P0 == pps()),
ok.
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index fe324391af..65977a764a 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -3417,6 +3417,7 @@ otp_11709(Config) when is_list(Config) ->
ok.
%% OTP-13229. open_file() exits with badarg when given binary file name.
+%% Also OTP-15253.
otp_13229(_Config) ->
F = <<"binfile.tab">>,
try dets:open_file(name, [{file, F}]) of
@@ -3425,6 +3426,20 @@ otp_13229(_Config) ->
catch
error:badarg ->
ok
+ end,
+ try dets:open_file(F, []) of % OTP-15253
+ R2 ->
+ exit({open_succeeded, R2})
+ catch
+ error:badarg ->
+ ok
+ end,
+ try dets:open_file(F) of
+ R3 ->
+ exit({open_succeeded, R3})
+ catch
+ error:badarg ->
+ ok
end.
%% OTP-13260. Race when opening a table.
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 7a48d1d55e..d8912e548c 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -66,7 +66,7 @@
meta_lookup_named_read/1, meta_lookup_named_write/1,
meta_newdel_unnamed/1, meta_newdel_named/1]).
-export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1,
- smp_select_replace/1, otp_8166/1, otp_8732/1]).
+ smp_select_replace/1, otp_8166/1, otp_8732/1, delete_unfix_race/1]).
-export([exit_large_table_owner/1,
exit_many_large_table_owner/1,
exit_many_tables_owner/1,
@@ -142,7 +142,8 @@ all() ->
ets_all,
massive_ets_all,
take,
- whereis_table].
+ whereis_table,
+ delete_unfix_race].
groups() ->
[{new, [],
@@ -5489,6 +5490,46 @@ smp_fixed_delete_do() ->
%%verify_table_load(T),
ets:delete(T).
+%% ERL-720
+%% Provoke race between ets:delete and table unfix (by select_count)
+%% that caused ets_misc memory counter to indicate false leak.
+delete_unfix_race(Config) when is_list(Config) ->
+ EtsMem = etsmem(),
+ Table = ets:new(t,[set,public,{write_concurrency,true}]),
+ InsertOp =
+ fun() ->
+ receive stop ->
+ false
+ after 0 ->
+ ets:insert(Table, {rand:uniform(10)}),
+ true
+ end
+ end,
+ DeleteOp =
+ fun() ->
+ receive stop ->
+ false
+ after 0 ->
+ ets:delete(Table, rand:uniform(10)),
+ true
+ end
+ end,
+ SelectOp =
+ fun() ->
+ ets:select_count(Table, ets:fun2ms(fun(X) -> true end))
+ end,
+ Main = self(),
+ Ins = spawn(fun()-> repeat_while(InsertOp), Main ! self() end),
+ Del = spawn(fun()-> repeat_while(DeleteOp), Main ! self() end),
+ spawn(fun()->
+ repeat(SelectOp, 10000),
+ Del ! stop,
+ Ins ! stop
+ end),
+ [receive Pid -> ok end || Pid <- [Ins,Del]],
+ ets:delete(Table),
+ verify_etsmem(EtsMem).
+
num_of_buckets(T) ->
element(1,ets:info(T,stats)).
diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl
index 79cee54335..f097552e8c 100644
--- a/lib/stdlib/test/io_SUITE.erl
+++ b/lib/stdlib/test/io_SUITE.erl
@@ -31,7 +31,7 @@
otp_10836/1, io_lib_width_too_small/1,
io_with_huge_message_queue/1, format_string/1,
maps/1, coverage/1, otp_14178_unicode_atoms/1, otp_14175/1,
- otp_14285/1, limit_term/1, otp_14983/1, otp_15103/1,
+ otp_14285/1, limit_term/1, otp_14983/1, otp_15103/1, otp_15076/1,
otp_15159/1]).
-export([pretty/2, trf/3]).
@@ -64,7 +64,7 @@ all() ->
io_lib_print_binary_depth_one, otp_10302, otp_10755, otp_10836,
io_lib_width_too_small, io_with_huge_message_queue,
format_string, maps, coverage, otp_14178_unicode_atoms, otp_14175,
- otp_14285, limit_term, otp_14983, otp_15103, otp_15159].
+ otp_14285, limit_term, otp_14983, otp_15103, otp_15076, otp_15159].
%% Error cases for output.
error_1(Config) when is_list(Config) ->
@@ -2639,3 +2639,11 @@ otp_15159(_Config) ->
"[atom]" =
lists:flatten(io_lib:format("~p", [[atom]], [{chars_limit,5}])),
ok.
+
+otp_15076(_Config) ->
+ {'EXIT', {badarg, _}} = (catch io_lib:format("~c", [a])),
+ L = io_lib:scan_format("~c", [a]),
+ {"~c", [a]} = io_lib:unscan_format(L),
+ {'EXIT', {badarg, _}} = (catch io_lib:build_text(L)),
+ {'EXIT', {badarg, _}} = (catch io_lib:build_text(L, [])),
+ ok.