aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/common_test/doc/src/ct_slave.xml139
-rw-r--r--lib/common_test/priv/Makefile.in4
-rw-r--r--lib/common_test/src/ct.erl2
-rw-r--r--lib/common_test/src/ct_util.erl31
-rw-r--r--lib/common_test/test/ct_misc_1_SUITE.erl62
-rw-r--r--lib/compiler/src/beam_block.erl35
-rw-r--r--lib/compiler/src/cerl.erl6
-rw-r--r--lib/compiler/src/core_lint.erl25
-rw-r--r--lib/compiler/src/v3_codegen.erl4
-rw-r--r--lib/compiler/src/v3_core.erl78
-rw-r--r--lib/compiler/test/bs_bincomp_SUITE.erl38
-rw-r--r--lib/compiler/test/bs_construct_SUITE.erl4
-rw-r--r--lib/compiler/test/receive_SUITE.erl25
-rw-r--r--lib/cosFileTransfer/test/Makefile132
-rw-r--r--lib/cosFileTransfer/test/cosFileTransfer.spec1
-rw-r--r--lib/cosFileTransfer/test/fileTransfer_SUITE.erl954
-rw-r--r--lib/cosNotification/doc/src/notes.xml70
-rw-r--r--lib/cosNotification/src/cosNotification_Filter.erl32
-rw-r--r--lib/cosNotification/vsn.mk2
-rw-r--r--lib/dialyzer/RELEASE_NOTES7
-rw-r--r--lib/dialyzer/doc/src/dialyzer.xml14
-rw-r--r--lib/dialyzer/src/dialyzer_races.erl38
-rw-r--r--lib/erl_interface/doc/src/notes.xml14
-rw-r--r--lib/erl_interface/src/connect/eirecv.c16
-rw-r--r--lib/erl_interface/src/connect/send.c3
-rw-r--r--lib/erl_interface/src/connect/send_exit.c3
-rw-r--r--lib/erl_interface/src/connect/send_reg.c3
-rw-r--r--lib/erl_interface/src/epmd/epmd_publish.c6
-rw-r--r--lib/erl_interface/src/epmd/epmd_unpublish.c5
-rw-r--r--lib/erl_interface/src/misc/ei_format.c4
-rw-r--r--lib/erl_interface/src/prog/erl_call.c31
-rw-r--r--lib/erl_interface/src/registry/reg_dump.c4
-rw-r--r--lib/erl_interface/src/registry/reg_restore.c2
-rw-r--r--lib/erl_interface/test/ei_format_SUITE.erl2
-rw-r--r--lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c2
-rw-r--r--lib/erl_interface/vsn.mk2
-rw-r--r--lib/hipe/cerl/erl_types.erl82
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl4
-rw-r--r--lib/hipe/icode/hipe_icode_callgraph.erl6
-rw-r--r--lib/hipe/icode/hipe_icode_range.erl4
-rw-r--r--lib/hipe/main/hipe.erl27
-rw-r--r--lib/hipe/main/hipe_main.erl12
-rw-r--r--lib/hipe/rtl/hipe_rtl.erl5
-rw-r--r--lib/hipe/rtl/hipe_rtl_arith.inc7
-rw-r--r--lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl43
-rw-r--r--lib/hipe/tools/hipe_tool.erl40
-rw-r--r--lib/kernel/doc/src/inet.xml63
-rw-r--r--lib/kernel/doc/src/notes.xml23
-rw-r--r--lib/kernel/src/inet.erl12
-rw-r--r--lib/kernel/src/inet_int.hrl3
-rw-r--r--lib/kernel/src/kernel.erl9
-rw-r--r--lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl9
-rw-r--r--lib/kernel/test/inet_SUITE.erl129
-rw-r--r--lib/odbc/c_src/odbcserver.c100
-rw-r--r--lib/odbc/c_src/odbcserver.h1
-rw-r--r--lib/odbc/configure.in9
-rw-r--r--lib/odbc/src/odbc.erl6
-rw-r--r--lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl13
-rw-r--r--lib/orber/doc/src/notes.xml55
-rw-r--r--lib/orber/vsn.mk2
-rw-r--r--lib/parsetools/include/yeccpre.hrl2
-rw-r--r--lib/parsetools/test/yecc_SUITE.erl12
-rw-r--r--lib/public_key/src/pubkey_cert.erl2
-rw-r--r--lib/ssh/doc/src/notes.xml46
-rw-r--r--lib/ssh/src/ssh.appup.src6
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl16
-rwxr-xr-xlib/ssh/src/ssh_file.erl17
-rw-r--r--lib/ssh/src/ssh_system_sup.erl2
-rw-r--r--lib/ssh/vsn.mk3
-rw-r--r--lib/ssl/doc/src/ssl.xml11
-rw-r--r--lib/ssl/src/ssl.erl4
-rw-r--r--lib/ssl/src/ssl_cipher.erl84
-rw-r--r--lib/ssl/src/ssl_connection.erl150
-rw-r--r--lib/ssl/src/ssl_handshake.erl116
-rw-r--r--lib/ssl/src/ssl_internal.hrl6
-rw-r--r--lib/ssl/src/ssl_ssl3.erl7
-rw-r--r--lib/ssl/src/ssl_tls1.erl7
-rw-r--r--lib/ssl/test/Makefile1
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl254
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl305
-rw-r--r--lib/ssl/test/ssl_test_lib.erl10
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl16
-rw-r--r--lib/stdlib/doc/src/ets.xml22
-rw-r--r--lib/stdlib/doc/src/filelib.xml8
-rw-r--r--lib/stdlib/src/dets.erl111
-rw-r--r--lib/stdlib/src/dets_v8.erl2
-rw-r--r--lib/stdlib/src/dets_v9.erl5
-rw-r--r--lib/stdlib/src/epp.erl43
-rw-r--r--lib/stdlib/src/erl_lint.erl14
-rw-r--r--lib/stdlib/src/lists.erl64
-rw-r--r--lib/stdlib/src/ordsets.erl16
-rw-r--r--lib/stdlib/src/string.erl2
-rw-r--r--lib/stdlib/src/supervisor.erl14
-rw-r--r--lib/stdlib/test/dets_SUITE.erl145
-rw-r--r--lib/stdlib/test/epp_SUITE.erl38
-rw-r--r--lib/stdlib/test/escript_SUITE.erl15
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/arg_overflow5
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/linebuf_overflow5
-rw-r--r--lib/stdlib/test/string_SUITE.erl5
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl4
-rw-r--r--lib/syntax_tools/src/erl_syntax_lib.erl6
-rw-r--r--lib/syntax_tools/src/igor.erl34
-rwxr-xr-xlib/wx/configure.in41
103 files changed, 3047 insertions, 1093 deletions
diff --git a/lib/common_test/doc/src/ct_slave.xml b/lib/common_test/doc/src/ct_slave.xml
deleted file mode 100644
index ceebf51f1a..0000000000
--- a/lib/common_test/doc/src/ct_slave.xml
+++ /dev/null
@@ -1,139 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-<erlref>
-<header>
-<title>ct_slave</title>
-<prepared></prepared>
-<responsible></responsible>
-<docno>1</docno>
-<approved></approved>
-<checked></checked>
-<date></date>
-<rev>A</rev>
-<file>ct_slave.xml</file></header>
-<module>ct_slave</module>
-<modulesummary>Common Test Framework functions for starting and stopping nodes for
-Large Scale Testing.</modulesummary>
-<description>
-<p>Common Test Framework functions for starting and stopping nodes for
-Large Scale Testing.</p>
-
- <p>This module exports functions which are used by the Common Test Master
- to start and stop "slave" nodes. It is the default callback module for the
- <c>{init, node_start}</c> term of the Test Specification.</p></description>
-<funcs>
-<func>
-<name>start(Node) -&gt; Result</name>
-<fsummary>Starts an Erlang node with name Node on the local host.</fsummary>
-<type>
-<v>Node = atom()</v><v>Result = {ok, NodeName} | {error, already_started, NodeName} | {error, started_not_connected, NodeName} | {error, boot_timeout, NodeName} | {error, init_timeout, NodeName} | {error, startup_timeout, NodeName} | {error, not_alive, NodeName}</v><v>NodeName = atom()</v></type>
-<desc><marker id="start-1"/>
-
-<p>Starts an Erlang node with name <c>Node</c> on the local host.</p>
-<p><em>See also:</em> <seealso marker="#start-3">start/3</seealso>.</p>
-</desc></func>
-<func>
-<name>start(Host, Node) -&gt; Result</name>
-<fsummary>Starts an Erlang node with name Node on host
- Host with the default options.</fsummary>
-<type>
-<v>Node = atom()</v><v>Host = atom()</v><v>Result = {ok, NodeName} | {error, already_started, NodeName} | {error, started_not_connected, NodeName} | {error, boot_timeout, NodeName} | {error, init_timeout, NodeName} | {error, startup_timeout, NodeName} | {error, not_alive, NodeName}</v><v>NodeName = atom()</v></type>
-<desc><marker id="start-2"/>
-
-<p>Starts an Erlang node with name <c>Node</c> on host
- <c>Host</c> with the default options.</p>
-<p><em>See also:</em> <seealso marker="#start-3">start/3</seealso>.</p>
-</desc></func>
-<func>
-<name>start(Host, Node, Options::Opts) -&gt; Result</name>
-<fsummary>Starts an Erlang node with name Node on host
- Host as specified by the combination of options in
- Opts.</fsummary>
-<type>
-<v>Node = atom()</v><v>Host = atom()</v><v>Opts = [OptTuples]</v><v>OptTuples = {username, Username} | {password, Password} | {boot_timeout, BootTimeout} | {init_timeout, InitTimeout} | {startup_timeout, StartupTimeout} | {startup_functions, StartupFunctions} | {monitor_master, Monitor} | {kill_if_fail, KillIfFail} | {erl_flags, ErlangFlags}</v><v>Username = string()</v><v>Password = string()</v><v>BootTimeout = integer()</v><v>InitTimeout = integer()</v><v>StartupTimeout = integer()</v><v>StartupFunctions = [StartupFunctionSpec]</v><v>StartupFunctionSpec = {Module, Function, Arguments}</v><v>Module = atom()</v><v>Function = atom()</v><v>Arguments = [term]</v><v>Monitor = bool()</v><v>KillIfFail = bool()</v><v>ErlangFlags = string()</v><v>Result = {ok, NodeName} | {error, already_started, NodeName} | {error, started_not_connected, NodeName} | {error, boot_timeout, NodeName} | {error, init_timeout, NodeName} | {error, startup_timeout, NodeName} | {error, not_alive, NodeName}</v><v>NodeName = atom()</v></type>
-<desc><marker id="start-3"/>
-
-<p>Starts an Erlang node with name <c>Node</c> on host
- <c>Host</c> as specified by the combination of options in
- <c>Opts</c>.</p>
-
- <p>Options <c>Username</c> and <c>Password</c> will be used
- to log in onto the remote host <c>Host</c>.
- Username, if omitted, defaults to the current user name,
- and password is empty by default.</p>
-
- <p>A list of functions specified in the <c>Startup</c> option will be
- executed after startup of the node. Note that all used modules should be
- present in the code path on the <c>Host</c>.</p>
-
- <p>The timeouts are applied as follows:
- <list>
- <item>
- <c>BootTimeout</c> - time to start the Erlang node, in seconds.
- Defaults to 3 seconds. If node does not become pingable within this time,
- the result <c>{error, boot_timeout, NodeName}</c> is returned;
- </item>
- <item>
- <c>InitTimeout</c> - time to wait for the node until it calls the
- internal callback function informing master about successfull startup.
- Defaults to one second.
- In case of timed out message the result
- <c>{error, init_timeout, NodeName}</c> is returned;
- </item>
- <item>
- <c>StartupTimeout</c> - time to wait intil the node finishes to run
- the <c>StartupFunctions</c>. Defaults to one second.
- If this timeout occurs, the result
- <c>{error, startup_timeout, NodeName}</c> is returned.
- </item>
- </list></p>
-
- <p>Option <c>monitor_master</c> specifies, if the slave node should be
- stopped in case of master node stop. Defaults to false.</p>
-
- <p>Option <c>kill_if_fail</c> specifies, if the slave node should be
- killed in case of a timeout during initialization or startup.
- Defaults to true. Note that node also may be still alive it the boot
- timeout occurred, but it will not be killed in this case.</p>
-
- <p>Option <c>erlang_flags</c> specifies, which flags will be added
- to the parameters of the <c>erl</c> executable.</p>
-
- <p>Special return values are:
- <list>
- <item><c>{error, already_started, NodeName}</c> - if the node with
- the given name is already started on a given host;</item>
- <item><c>{error, started_not_connected, NodeName}</c> - if node is
- started, but not connected to the master node.</item>
- <item><c>{error, not_alive, NodeName}</c> - if node on which the
- <c>ct_slave:start/3</c> is called, is not alive. Note that
- <c>NodeName</c> is the name of current node in this case.</item>
- </list></p>
-
-</desc></func>
-<func>
-<name>stop(Node) -&gt; Result</name>
-<fsummary>Stops the running Erlang node with name Node on
- the localhost.</fsummary>
-<type>
-<v>Node = atom()</v><v>Result = {ok, NodeName} | {error, not_started, NodeName} | {error, not_connected, NodeName} | {error, stop_timeout, NodeName}</v><v>NodeName = atom()</v></type>
-<desc><marker id="stop-1"/>
-
-<p>Stops the running Erlang node with name <c>Node</c> on
- the localhost.</p>
-</desc></func>
-<func>
-<name>stop(Host, Node) -&gt; Result</name>
-<fsummary>Stops the running Erlang node with name Node on
- host Host.</fsummary>
-<type>
-<v>Host = atom()</v><v>Node = atom()</v><v>Result = {ok, NodeName} | {error, not_started, NodeName} | {error, not_connected, NodeName} | {error, stop_timeout, NodeName}</v><v>NodeName = atom()</v></type>
-<desc><marker id="stop-2"/>
-
-<p>Stops the running Erlang node with name <c>Node</c> on
- host <c>Host</c>.</p>
-</desc></func></funcs>
-
-<authors>
-<aname> </aname>
-<email> </email></authors></erlref> \ No newline at end of file
diff --git a/lib/common_test/priv/Makefile.in b/lib/common_test/priv/Makefile.in
index 6372bbc8d5..a6ac0f1a02 100644
--- a/lib/common_test/priv/Makefile.in
+++ b/lib/common_test/priv/Makefile.in
@@ -56,8 +56,8 @@ ifneq ($(findstring win32,$(TARGET)),win32)
#
# Files
#
-FILES =
-SCRIPTS =
+FILES = vts.tool
+SCRIPTS =
IMAGES = tile1.jpg
#
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 8ae175f10d..1dbf83ee10 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -694,7 +694,7 @@ userdata(TestDir, Suite, Case) ->
%%%-----------------------------------------------------------------
-%%% @spec get_status() -> TestStatus | {error,Reason}
+%%% @spec get_status() -> TestStatus | {error,Reason} | no_tests_running
%%% TestStatus = [StatusElem]
%%% StatusElem = {current,{Suite,TestCase}} | {successful,Successful} |
%%% {failed,Failed} | {skipped,Skipped} | {total,Total}
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index 0a434666fa..b5ab4cbb6e 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -556,10 +556,37 @@ listenv(Telnet) ->
%%% @hidden
%%% @equiv ct:parse_table/1
parse_table(Data) ->
- [Heading|Lines]=
- [remove_space(string:tokens(L, "|"),[]) || L <- Data, hd(L)==$|],
+ {Heading, Rest} = get_headings(Data),
+ Lines = parse_row(Rest,[],size(Heading)),
{Heading,Lines}.
+get_headings(["|" ++ Headings | Rest]) ->
+ {remove_space(string:tokens(Headings, "|"),[]), Rest};
+get_headings([_ | Rest]) ->
+ get_headings(Rest);
+get_headings([]) ->
+ {{},[]}.
+
+parse_row(["|" ++ _ = Row | T], Rows, NumCols) when NumCols > 1 ->
+ case string:tokens(Row, "|") of
+ Values when length(Values) =:= NumCols ->
+ parse_row(T,[remove_space(Values,[])|Rows], NumCols);
+ Values when length(Values) < NumCols ->
+ parse_row([Row ++"\n"++ hd(T) | tl(T)], Rows, NumCols)
+ end;
+parse_row(["|" ++ _ = Row | T], Rows, 1 = NumCols) ->
+ case string:rchr(Row, $|) of
+ 1 ->
+ parse_row([Row ++"\n"++hd(T) | tl(T)], Rows, NumCols);
+ _Else ->
+ parse_row(T, [remove_space(string:tokens(Row,"|"),[])|Rows],
+ NumCols)
+ end;
+parse_row([_Skip | T], Rows, NumCols) ->
+ parse_row(T, Rows, NumCols);
+parse_row([], Rows, _NumCols) ->
+ lists:reverse(Rows).
+
remove_space([Str|Rest],Acc) ->
remove_space(Rest,[string:strip(string:strip(Str),both,$')|Acc]);
remove_space([],Acc) ->
diff --git a/lib/common_test/test/ct_misc_1_SUITE.erl b/lib/common_test/test/ct_misc_1_SUITE.erl
index eb6c6aa101..8c8b2d0d41 100644
--- a/lib/common_test/test/ct_misc_1_SUITE.erl
+++ b/lib/common_test/test/ct_misc_1_SUITE.erl
@@ -62,7 +62,7 @@ all(doc) ->
all(suite) ->
[
- beam_me_up
+ beam_me_up, parse_table
].
%%--------------------------------------------------------------------
@@ -106,6 +106,66 @@ beam_me_up(Config) when is_list(Config) ->
TestEvents = events_to_check(beam_me_up, 1),
ok = ct_test_support:verify_events(TestEvents, Events, Config).
+
+parse_table(suite) ->
+ [parse_table_empty, parse_table_single,
+ parse_table_multiline_row,
+ parse_table_one_column_multiline,
+ parse_table_one_column_simple].
+
+parse_table_empty(Config) when is_list(Config) ->
+
+ String = ["+----+-------+---------+---------+----------+------+--------+",
+ "| id | col11 | col2222 | col3333 | col4 | col5 | col6666 |",
+ "+----+-------+---------+---------+----------+------+--------+",
+ "+----+-------+---------+---------+----------+------+--------+",
+ "Query Done: 0 records selected"],
+
+ {{"id","col11","col2222","col3333","col4","col5","col6666"},[]} =
+ ct:parse_table(String).
+
+
+parse_table_single(Config) when is_list(Config) ->
+
+ String = ["+------+--------+--------------+------------+------------------+---------+--------+---------+-----------+",
+ "| id | col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8 |",
+"+------+--------+--------------+------------+------------------+---------+--------+---------+-----------+",
+ "| 0 | 0 | -1407231560 | -256 | -1407231489 | 1500 | 1 | 1 | 1 |",
+ "+------+--------+--------------+------------+------------------+---------+--------+---------+-----------+"
+ "Query Done: 1 record selected"],
+
+ {{"id","col1","col2","col3","col4","col5","col6","col7","col8"},
+ [{"0","0","-1407231560","-256","-1407231489", "1500","1","1","1"}]} =
+ ct:parse_table(String).
+
+parse_table_multiline_row(Config) when is_list(Config) ->
+
+ String = ["+------+--------+--------------+------------+------------------+---------+--------+---------+-----------+",
+ "| id | col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8 |",
+"+------+--------+--------------+------------+------------------+---------+--------+---------+-----------+",
+ "| 0 | 0 | Free test string",
+ " on more lines",
+ "than one",
+ "| -256 | -1407231489 | 1500 | 1 | 1 | 1 |",
+ "+------+--------+--------------+------------+------------------+---------+--------+---------+-----------+"
+ "Query Done: 1 record selected"],
+
+ {{"id","col1","col2","col3","col4","col5","col6","col7","col8"},
+ [{"0","0","Free test string\n on more lines\nthan one\n",
+ "-256","-1407231489", "1500","1","1","1"}]} =
+ ct:parse_table(String).
+
+parse_table_one_column_simple(Config) when is_list(Config) ->
+
+ String = ["|test|","|test value|"],
+
+ {{"test"},[{"test value"}]} = ct:parse_table(String).
+
+parse_table_one_column_multiline(Config) when is_list(Config) ->
+ String = ["|test|","|test","value|"],
+
+ {{"test"},[{"test\nvalue"}]} = ct:parse_table(String).
+
%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
%%%-----------------------------------------------------------------
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index 9c6f835ab0..c45874597a 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -36,12 +36,13 @@ function({function,Name,Arity,CLabel,Is0}, Lc0) ->
%% Collect basic blocks and optimize them.
Is2 = blockify(Is1),
- Is3 = beam_utils:live_opt(Is2),
- Is4 = opt_blocks(Is3),
- Is5 = beam_utils:delete_live_annos(Is4),
+ Is3 = move_allocates(Is2),
+ Is4 = beam_utils:live_opt(Is3),
+ Is5 = opt_blocks(Is4),
+ Is6 = beam_utils:delete_live_annos(Is5),
%% Optimize bit syntax.
- {Is,Lc} = bsm_opt(Is5, Lc0),
+ {Is,Lc} = bsm_opt(Is6, Lc0),
%% Done.
{{function,Name,Arity,CLabel,Is},Lc}
@@ -156,11 +157,7 @@ opt_blocks([I|Is]) ->
opt_blocks([]) -> [].
opt_block(Is0) ->
- %% We explicitly move any allocate instruction upwards before optimising
- %% moves, to avoid any potential problems with the calculation of live
- %% registers.
- Is1 = move_allocates(Is0),
- Is = find_fixpoint(fun opt/1, Is1),
+ Is = find_fixpoint(fun opt/1, Is0),
opt_alloc(Is).
find_fixpoint(OptFun, Is0) ->
@@ -170,11 +167,21 @@ find_fixpoint(OptFun, Is0) ->
end.
%% move_allocates(Is0) -> Is
-%% Move allocates upwards in the instruction stream, in the hope of
-%% getting more possibilities for optimizing away moves later.
-
-move_allocates(Is) ->
- move_allocates_1(reverse(Is), []).
+%% Move allocate instructions upwards in the instruction stream, in the
+%% hope of getting more possibilities for optimizing away moves later.
+%%
+%% NOTE: Moving allocation instructions is only safe because it is done
+%% immediately after code generation so that we KNOW that if {x,X} is
+%% initialized, all x registers with lower numbers are also initialized.
+%% That assumption may not be true after other optimizations, such as
+%% the beam_utils:live_opt/1 optimization.
+
+move_allocates([{block,Bl0}|Is]) ->
+ Bl = move_allocates_1(reverse(Bl0), []),
+ [{block,Bl}|move_allocates(Is)];
+move_allocates([I|Is]) ->
+ [I|move_allocates(Is)];
+move_allocates([]) -> [].
move_allocates_1([{set,[],[],{alloc,_,_}=Alloc}|Is0], Acc0) ->
{Is,Acc} = move_allocates_2(Alloc, Is0, Acc0),
diff --git a/lib/compiler/src/cerl.erl b/lib/compiler/src/cerl.erl
index d1fd9d40e2..4b74d60e9f 100644
--- a/lib/compiler/src/cerl.erl
+++ b/lib/compiler/src/cerl.erl
@@ -973,7 +973,7 @@ atom_name(Node) ->
%% TODO: replace the use of the unofficial 'write_string/2'.
--spec atom_lit(cerl()) -> string().
+-spec atom_lit(cerl()) -> nonempty_string().
atom_lit(Node) ->
io_lib:write_string(atom_name(Node), $'). %' stupid Emacs.
@@ -1079,7 +1079,7 @@ char_val(Node) ->
%%
%% @see c_char/1
--spec char_lit(c_literal()) -> string().
+-spec char_lit(c_literal()) -> nonempty_string().
char_lit(Node) ->
io_lib:write_char(char_val(Node)).
@@ -1178,7 +1178,7 @@ string_val(Node) ->
%%
%% @see c_string/1
--spec string_lit(c_literal()) -> string().
+-spec string_lit(c_literal()) -> nonempty_string().
string_lit(Node) ->
io_lib:write_string(string_val(Node)).
diff --git a/lib/compiler/src/core_lint.erl b/lib/compiler/src/core_lint.erl
index b633f568c9..b513a8965c 100644
--- a/lib/compiler/src/core_lint.erl
+++ b/lib/compiler/src/core_lint.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2010. 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
@@ -65,7 +65,8 @@
| {'return_mismatch', fa()} | {'undefined_function', fa()}
| {'duplicate_var', cerl:var_name(), fa()}
| {'unbound_var', cerl:var_name(), fa()}
- | {'undefined_function', fa(), fa()}.
+ | {'undefined_function', fa(), fa()}
+ | {'tail_segment_not_at_end', fa()}.
-type error() :: {module(), err_desc()}.
-type warning() :: {module(), term()}.
@@ -116,7 +117,9 @@ format_error({duplicate_var,N,{F,A}}) ->
format_error({unbound_var,N,{F,A}}) ->
io_lib:format("unbound variable ~s in ~w/~w", [N,F,A]);
format_error({undefined_function,{F1,A1},{F2,A2}}) ->
- io_lib:format("undefined function ~w/~w in ~w/~w", [F1,A1,F2,A2]).
+ io_lib:format("undefined function ~w/~w in ~w/~w", [F1,A1,F2,A2]);
+format_error({tail_segment_not_at_end,{F,A}}) ->
+ io_lib:format("binary tail segment not at end in ~w/~w", [F,A]).
-type ret() :: {'ok', [{module(), [warning(),...]}]}
| {'error', [{module(), [error(),...]}],
@@ -450,7 +453,8 @@ pattern(#c_cons{hd=H,tl=T}, Def, Ps, St) ->
pattern_list([H,T], Def, Ps, St);
pattern(#c_tuple{es=Es}, Def, Ps, St) ->
pattern_list(Es, Def, Ps, St);
-pattern(#c_binary{segments=Ss}, Def, Ps, St) ->
+pattern(#c_binary{segments=Ss}, Def, Ps, St0) ->
+ St = pat_bin_tail_check(Ss, St0),
pat_bin(Ss, Def, Ps, St);
pattern(#c_alias{var=V,pat=P}, Def, Ps, St0) ->
{Vvs,St1} = variable(V, Ps, St0),
@@ -482,6 +486,19 @@ pat_segment(#c_bitstr{val=V,size=S,type=T}, Def0, Ps0, St0) ->
pat_segment(_, Def, Ps, St) ->
{Ps,Def,add_error({not_bs_pattern,St#lint.func}, St)}.
+%% pat_bin_tail_check([Elem], State) -> State.
+%% There must be at most one tail segment (a size-less segment of
+%% type binary) and it must occur at the end.
+
+pat_bin_tail_check([#c_bitstr{size=#c_literal{val=all}}], St) ->
+ %% Size-less field is OK at the end of the list of segments.
+ St;
+pat_bin_tail_check([#c_bitstr{size=#c_literal{val=all}}|_], St) ->
+ add_error({tail_segment_not_at_end,St#lint.func}, St);
+pat_bin_tail_check([_|Ss], St) ->
+ pat_bin_tail_check(Ss, St);
+pat_bin_tail_check([], St) -> St.
+
%% pat_bit_expr(SizePat, Type, Defined, State) -> State.
%% Check the Size pattern, this is an input! Because of optimizations,
%% we must allow any kind of constant and literal here.
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
index 948937c438..77da6c8d00 100644
--- a/lib/compiler/src/v3_codegen.erl
+++ b/lib/compiler/src/v3_codegen.erl
@@ -1523,7 +1523,9 @@ cg_binary_size_1([], Bits, Acc) ->
[{1,_}|_] ->
{bs_init_bits,cg_binary_bytes_to_bits(Sizes, [])};
[{8,_}|_] ->
- {bs_init2,[E || {8,E} <- Sizes]}
+ {bs_init2,[E || {8,E} <- Sizes]};
+ [] ->
+ {bs_init_bits,[]}
end.
cg_binary_size_2({integer,N}, U, _, Next, Bits, Acc) ->
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index f6bb45787c..2da24b2908 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -892,25 +892,22 @@ lc_tq(Line, E, [{generate,Lg,P,G}|Qs0], Mc, St0) ->
lc_tq(Line, E, [{b_generate,Lg,P,G}|Qs0], Mc, St0) ->
{Gs,Qs1} = splitwith(fun is_guard_test/1, Qs0),
{Name,St1} = new_fun_name("blc", St0),
- {Tname,St2} = new_var_name(St1),
- LA = lineno_anno(Line, St2),
+ LA = lineno_anno(Line, St1),
LAnno = #a{anno=LA},
- HeadBinPattern = pattern(P,St2),
- #c_binary{segments=Ps} = HeadBinPattern,
- {EPs,St3} = emasculate_segments(Ps,St2),
- Tail = #c_var{anno=LA,name=Tname},
- TailSegment = #c_bitstr{val=Tail,size=#c_literal{val=all},
- unit=#c_literal{val=1},
- type=#c_literal{val=binary},
- flags=#c_literal{val=[big,unsigned]}},
- Pattern = HeadBinPattern#c_binary{segments=Ps ++ [TailSegment]},
- EPattern = HeadBinPattern#c_binary{segments=EPs ++ [TailSegment]},
+ HeadBinPattern = pattern(P, St1),
+ #c_binary{segments=Ps0} = HeadBinPattern,
+ {Ps,Tail,St2} = append_tail_segment(Ps0, St1),
+ {EPs,St3} = emasculate_segments(Ps, St2),
+ Pattern = HeadBinPattern#c_binary{segments=Ps},
+ EPattern = HeadBinPattern#c_binary{segments=EPs},
{Arg,St4} = new_var(St3),
{Guardc,St5} = lc_guard_tests(Gs, St4), %These are always flat!
+ Tname = Tail#c_var.name,
{Nc,[],St6} = expr({call,Lg,{atom,Lg,Name},[{var,Lg,Tname}]}, St5),
{Bc,Bps,St7} = lc_tq(Line, E, Qs1, Nc, St6),
{Gc,Gps,St10} = safe(G, St7), %Will be a function argument!
Fc = function_clause([Arg], LA, {Name,1}),
+ {TailSegList,_,St} = append_tail_segment([], St10),
Cs = [#iclause{anno=#a{anno=[compiler_generated|LA]},
pats=[Pattern],
guard=Guardc,
@@ -922,14 +919,14 @@ lc_tq(Line, E, [{b_generate,Lg,P,G}|Qs0], Mc, St0) ->
op=#c_var{anno=LA,name={Name,1}},
args=[Tail]}]},
#iclause{anno=LAnno,
- pats=[#c_binary{anno=LA, segments=[TailSegment]}],guard=[],
+ pats=[#c_binary{anno=LA,segments=TailSegList}],guard=[],
body=[Mc]}],
Fun = #ifun{anno=LAnno,id=[],vars=[Arg],clauses=Cs,fc=Fc},
{#iletrec{anno=LAnno,defs=[{{Name,1},Fun}],
body=Gps ++ [#iapply{anno=LAnno,
op=#c_var{anno=LA,name={Name,1}},
args=[Gc]}]},
- [],St10};
+ [],St};
lc_tq(Line, E, [Fil0|Qs0], Mc, St0) ->
%% Special case sequences guard tests.
LA = lineno_anno(Line, St0),
@@ -1037,26 +1034,24 @@ bc_tq1(Line, E, [{b_generate,Lg,P,G}|Qs0], AccExpr, St0) ->
{Gs,Qs1} = splitwith(fun is_guard_test/1, Qs0),
{Name,St1} = new_fun_name("lbc", St0),
LA = lineno_anno(Line, St1),
- {[Tail,AccVar],St2} = new_vars(LA, 2, St1),
+ {AccVar,St2} = new_var(LA, St1),
LAnno = #a{anno=LA},
HeadBinPattern = pattern(P, St2),
- #c_binary{segments=Ps} = HeadBinPattern,
- {EPs,St3} = emasculate_segments(Ps, St2),
- TailSegment = #c_bitstr{val=Tail,size=#c_literal{val=all},
- unit=#c_literal{val=1},
- type=#c_literal{val=binary},
- flags=#c_literal{val=[big,unsigned]}},
- Pattern = HeadBinPattern#c_binary{segments=Ps ++ [TailSegment]},
- EPattern = HeadBinPattern#c_binary{segments=EPs ++ [TailSegment]},
- {Arg,St4} = new_var(St3),
+ #c_binary{segments=Ps0} = HeadBinPattern,
+ {Ps,Tail,St3} = append_tail_segment(Ps0, St2),
+ {EPs,St4} = emasculate_segments(Ps, St3),
+ Pattern = HeadBinPattern#c_binary{segments=Ps},
+ EPattern = HeadBinPattern#c_binary{segments=EPs},
+ {Arg,St5} = new_var(St4),
NewMore = {call,Lg,{atom,Lg,Name},[{var,Lg,Tail#c_var.name},
{var,Lg,AccVar#c_var.name}]},
- {Guardc,St5} = lc_guard_tests(Gs, St4), %These are always flat!
- {Bc,Bps,St6} = bc_tq1(Line, E, Qs1, AccVar, St5),
- {Nc,Nps,St7} = expr(NewMore, St6),
- {Gc,Gps,St8} = safe(G, St7), %Will be a function argument!
+ {Guardc,St6} = lc_guard_tests(Gs, St5), %These are always flat!
+ {Bc,Bps,St7} = bc_tq1(Line, E, Qs1, AccVar, St6),
+ {Nc,Nps,St8} = expr(NewMore, St7),
+ {Gc,Gps,St9} = safe(G, St8), %Will be a function argument!
Fc = function_clause([Arg,AccVar], LA, {Name,2}),
Body = Bps ++ Nps ++ [#iset{var=AccVar,arg=Bc},Nc],
+ {TailSegList,_,St} = append_tail_segment([], St9),
Cs = [#iclause{anno=LAnno,
pats=[Pattern,AccVar],
guard=Guardc,
@@ -1066,7 +1061,7 @@ bc_tq1(Line, E, [{b_generate,Lg,P,G}|Qs0], AccExpr, St0) ->
guard=[],
body=Nps ++ [Nc]},
#iclause{anno=LAnno,
- pats=[#c_binary{anno=LA,segments=[TailSegment]},AccVar],
+ pats=[#c_binary{anno=LA,segments=TailSegList},AccVar],
guard=[],
body=[AccVar]}],
Fun = #ifun{anno=LAnno,id=[],vars=[Arg,AccVar],clauses=Cs,fc=Fc},
@@ -1074,7 +1069,7 @@ bc_tq1(Line, E, [{b_generate,Lg,P,G}|Qs0], AccExpr, St0) ->
body=Gps ++ [#iapply{anno=LAnno,
op=#c_var{anno=LA,name={Name,2}},
args=[Gc,AccExpr]}]},
- [],St8};
+ [],St};
bc_tq1(Line, E, [Fil0|Qs0], AccVar, St0) ->
%% Special case sequences guard tests.
LA = lineno_anno(Line, St0),
@@ -1120,6 +1115,29 @@ bc_tq1(_, {bin,Bl,Elements}, [], AccVar, St0) ->
%%Anno = Anno0#a{anno=[compiler_generated|A]},
{set_anno(E, Anno),Pre,St}.
+append_tail_segment(Segs, St) ->
+ app_tail_seg(Segs, St, []).
+
+app_tail_seg([#c_bitstr{val=Var0,size=#c_literal{val=all}}=Seg0]=L,
+ St0, Acc) ->
+ case Var0 of
+ #c_var{name='_'} ->
+ {Var,St} = new_var(St0),
+ Seg = Seg0#c_bitstr{val=Var},
+ {reverse(Acc, [Seg]),Var,St};
+ #c_var{} ->
+ {reverse(Acc, L),Var0,St0}
+ end;
+app_tail_seg([H|T], St, Acc) ->
+ app_tail_seg(T, St, [H|Acc]);
+app_tail_seg([], St0, Acc) ->
+ {Var,St} = new_var(St0),
+ Tail = #c_bitstr{val=Var,size=#c_literal{val=all},
+ unit=#c_literal{val=1},
+ type=#c_literal{val=binary},
+ flags=#c_literal{val=[unsigned,big]}},
+ {reverse(Acc, [Tail]),Var,St}.
+
emasculate_segments(Segs, St) ->
emasculate_segments(Segs, St, []).
diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl
index a64a5d590b..74f69893af 100644
--- a/lib/compiler/test/bs_bincomp_SUITE.erl
+++ b/lib/compiler/test/bs_bincomp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2010. 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
@@ -24,7 +24,7 @@
-export([all/1,
byte_aligned/1,bit_aligned/1,extended_byte_aligned/1,
extended_bit_aligned/1,mixed/1,filters/1,trim_coverage/1,
- nomatch/1,sizes/1]).
+ nomatch/1,sizes/1,tail/1]).
-include("test_server.hrl").
@@ -32,7 +32,7 @@ all(suite) ->
test_lib:recompile(?MODULE),
[byte_aligned,bit_aligned,extended_byte_aligned,
extended_bit_aligned,mixed,filters,trim_coverage,
- nomatch,sizes].
+ nomatch,sizes,tail].
byte_aligned(Config) when is_list(Config) ->
@@ -270,6 +270,38 @@ sizes(Config) when is_list(Config) ->
?line cs_end(),
ok.
+tail(Config) when is_list(Config) ->
+ ?line [] = tail_1(<<0:7>>),
+ ?line [0] = tail_1(<<0>>),
+ ?line [0] = tail_1(<<0:12>>),
+ ?line [0,0] = tail_1(<<0:20>>),
+
+ ?line [] = tail_2(<<0:7>>),
+ ?line [42] = tail_2(<<0>>),
+ ?line [] = tail_2(<<0:12>>),
+ ?line [42,42] = tail_2(<<0,1>>),
+
+ ?line <<>> = tail_3(<<0:7>>),
+ ?line <<42>> = tail_3(<<0>>),
+ ?line <<42>> = tail_3(<<0:12>>),
+ ?line <<42,42>> = tail_3(<<0:20>>),
+
+ ?line [] = tail_4(<<0:15>>),
+ ?line [7] = tail_4(<<7,8>>),
+ ?line [9] = tail_4(<<9,17:12>>),
+ ok.
+
+tail_1(Bits) ->
+ [X || <<X:8/integer, _/bits>> <= Bits].
+
+tail_2(Bits) ->
+ [42 || <<_:8/integer, _/bytes>> <= Bits].
+
+tail_3(Bits) ->
+ << <<42>> || <<_:8/integer, _/bits>> <= Bits >>.
+
+tail_4(Bits) ->
+ [X || <<X:8/integer, Tail/bits>> <= Bits, bit_size(Tail) >= 8].
cs_init() ->
diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl
index 1862a28bbe..dfe4301791 100644
--- a/lib/compiler/test/bs_construct_SUITE.erl
+++ b/lib/compiler/test/bs_construct_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2010. 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
@@ -66,6 +66,8 @@ id(I) -> I.
l(I_13, I_big1, I_16, Bin) ->
[
+ ?T(<<I_13:0>>,
+ []),
?T(<<-43>>,
[256-43]),
?T(<<4:4,7:4>>,
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index fca3f0387b..2a592dd669 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -21,7 +21,7 @@
-module(receive_SUITE).
-export([all/1,init_per_testcase/2,fin_per_testcase/2,
- recv/1,coverage/1,otp_7980/1,ref_opt/1]).
+ recv/1,coverage/1,otp_7980/1,ref_opt/1,export/1]).
-include("test_server.hrl").
@@ -36,7 +36,7 @@ fin_per_testcase(_Case, Config) ->
all(suite) ->
test_lib:recompile(?MODULE),
- [recv,coverage,otp_7980,ref_opt].
+ [recv,coverage,otp_7980,ref_opt,export].
-record(state, {ena = true}).
@@ -205,4 +205,25 @@ collect_recv_opt_instrs(Code) ->
end] || {function,_,_,_,Is} <- Code],
lists:append(L).
+export(Config) when is_list(Config) ->
+ Ref = make_ref(),
+ ?line self() ! {result,Ref,42},
+ ?line 42 = export_1(Ref),
+ ?line {error,timeout} = export_1(Ref),
+ ok.
+
+export_1(Reference) ->
+ id(Reference),
+ receive
+ {result,Reference,Result} ->
+ Result
+ after 1 ->
+ Result = {error,timeout}
+ end,
+ %% Result ({x,1}) is used, but not the return value ({x,0})
+ %% of the receive. Used to be incorrectly optimized
+ %% by beam_block.
+ id({build,self()}),
+ Result.
+
id(I) -> I.
diff --git a/lib/cosFileTransfer/test/Makefile b/lib/cosFileTransfer/test/Makefile
new file mode 100644
index 0000000000..60f72644bd
--- /dev/null
+++ b/lib/cosFileTransfer/test/Makefile
@@ -0,0 +1,132 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2000-2010. 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
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+VSN=$(COSFILETRANSFER_VSN)
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/cosFileTransfer_test
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+TEST_SPEC_FILE = cosFileTransfer.spec
+
+
+IDL_FILES =
+
+IDLOUTDIR = idl_output
+
+MODULES = \
+ fileTransfer_SUITE \
+
+GEN_MODULES = \
+
+GEN_HRL_FILES = \
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+HRL_FILES =
+
+GEN_FILES = \
+ $(GEN_HRL_FILES:%=$(IDLOUTDIR)/%) \
+ $(GEN_MODULES:%=$(IDLOUTDIR)/%.erl)
+
+GEN_TARGET_FILES = $(GEN_MODULES:%=$(IDLOUTDIR)/%.$(EMULATOR))
+
+SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
+
+TARGET_FILES = \
+ $(GEN_TARGET_FILES) \
+ $(SUITE_TARGET_FILES)
+
+
+# ----------------------------------------------------
+# PROGRAMS
+# ----------------------------------------------------
+LOCAL_CLASSPATH = $(ERL_TOP)lib/cosFileTransfer/priv:$(ERL_TOP)lib/cosFileTransfer/test
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosFileTransfer/ebin \
+ -pa $(ERL_TOP)/lib/cosFileTransfer/src \
+ -pa $(ERL_TOP)/lib/cosFileTransfer/include \
+ -pa $(ERL_TOP)/lib/cosProperty/ebin \
+ -pa $(ERL_TOP)/lib/cosProperty/include \
+ -pa $(ERL_TOP)/lib/orber/ebin \
+ -pa $(ERL_TOP)/lib/ic/ebin
+
+ERL_COMPILE_FLAGS += \
+ $(ERL_IDL_FLAGS) \
+ -pa $(ERL_TOP)/lib/orber/include \
+ -pa $(ERL_TOP)/lib/cosProperty/include \
+ -pa $(ERL_TOP)/internal_tools/test_server/ebin \
+ -pa $(ERL_TOP)/lib/cosFileTransfer/ebin \
+ -pa $(ERL_TOP)/lib/cosFileTransfer/include \
+ -pa $(ERL_TOP)/lib/cosFileTransfer/test/idl_output \
+ -I$(ERL_TOP)/lib/orber/include \
+ -I$(ERL_TOP)/lib/cosProperty/include \
+ -I$(ERL_TOP)/lib/cosFileTransfer/src \
+ -I$(ERL_TOP)/lib/cosFileTransfer/include \
+ -I$(ERL_TOP)/lib/cosFileTransfer \
+ -I$(ERL_TOP)/lib/cosFileTransfer/test/$(IDLOUTDIR) \
+ -I$(ERL_TOP)/lib/test_server/include
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+
+tests debug opt: $(TARGET_FILES)
+
+clean:
+ rm -f idl_output/*
+ rm -f $(TARGET_FILES)
+ rm -f errs core *~
+
+docs:
+
+# ----------------------------------------------------
+# Special Targets
+# ----------------------------------------------------
+
+# ----------------------------------------------------
+# Release Targets
+# ----------------------------------------------------
+# We don't copy generated intermediate erlang and hrl files
+
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec:
+
+release_docs_spec:
+
+release_tests_spec: tests
+ $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \
+ $(ERL_FILES) $(RELSYSDIR)
+ $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR)
+ chmod -f -R u+w $(RELSYSDIR)
diff --git a/lib/cosFileTransfer/test/cosFileTransfer.spec b/lib/cosFileTransfer/test/cosFileTransfer.spec
new file mode 100644
index 0000000000..80fe919f2a
--- /dev/null
+++ b/lib/cosFileTransfer/test/cosFileTransfer.spec
@@ -0,0 +1 @@
+{topcase, {dir, "../cosFileTransfer_test"}}.
diff --git a/lib/cosFileTransfer/test/fileTransfer_SUITE.erl b/lib/cosFileTransfer/test/fileTransfer_SUITE.erl
new file mode 100644
index 0000000000..f877e3ceda
--- /dev/null
+++ b/lib/cosFileTransfer/test/fileTransfer_SUITE.erl
@@ -0,0 +1,954 @@
+%%-----------------------------------------------------------------------
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2010. 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
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+%%----------------------------------------------------------------------
+%% File : fileTransfer_SUITE.erl
+%% Purpose :
+%%----------------------------------------------------------------------
+
+-module(fileTransfer_SUITE).
+
+
+
+%%--------------- INCLUDES -----------------------------------
+-include_lib("cosFileTransfer/src/cosFileTransferApp.hrl").
+
+-include("test_server.hrl").
+
+%%--------------- DEFINES ------------------------------------
+-define(default_timeout, ?t:minutes(20)).
+-define(match(ExpectedRes, Expr),
+ fun() ->
+ AcTuAlReS = (catch (Expr)),
+ case AcTuAlReS of
+ ExpectedRes ->
+ io:format("------ CORRECT RESULT ------~n~p~n",
+ [AcTuAlReS]),
+ AcTuAlReS;
+ _ ->
+ io:format("###### ERROR ERROR ######~n~p~n",
+ [AcTuAlReS]),
+ exit(AcTuAlReS)
+ end
+ end()).
+
+-define(matchnopr(ExpectedRes, Expr),
+ fun() ->
+ AcTuAlReS = (catch (Expr)),
+ case AcTuAlReS of
+ ExpectedRes ->
+ io:format("------ CORRECT RESULT (~p) ------~n", [?LINE]),
+ AcTuAlReS;
+ _ ->
+ io:format("###### ERROR ERROR ######~n~p~n",
+ [AcTuAlReS]),
+ exit(AcTuAlReS)
+ end
+ end()).
+
+
+
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([all/1,
+ cases/0,
+ init_all/1,
+ finish_all/1,
+ fileIterator_api/1,
+ fts_ftp_file_api/1,
+ fts_ftp_file_ssl_api/1,
+ fts_ftp_dir_api/1,
+ fts_native_file_api/1,
+ fts_native_file_ssl_api/1,
+ fts_native_dir_api/1,
+ init_per_testcase/2,
+ fin_per_testcase/2,
+ install_data/2,
+ uninstall_data/1,
+ slave_sup/0,
+ app_test/1]).
+
+%%-----------------------------------------------------------------
+%% Func: all/1
+%% Args:
+%% Returns:
+%%-----------------------------------------------------------------
+all(doc) -> ["API tests for the cosFileTransfer interfaces", ""];
+all(suite) -> {req,
+ [mnesia, orber],
+ {conf, init_all, cases(), finish_all}}.
+
+cases() ->
+ [fts_ftp_dir_api, fts_ftp_file_api, fts_ftp_file_ssl_api,
+ fts_native_dir_api, fts_native_file_api, fts_native_file_ssl_api,
+ fileIterator_api, app_test].
+
+%%-----------------------------------------------------------------
+%% Init and cleanup functions.
+%%-----------------------------------------------------------------
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog=test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+
+
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+init_all(Config) ->
+ orber:jump_start(),
+ cosProperty:install(),
+ cosProperty:start(),
+ Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
+ %% Client
+ cosFileTransferApp:configure(ssl_client_certfile,
+ filename:join([Dir, "client", "cert.pem"])),
+ cosFileTransferApp:configure(ssl_client_cacertfile,
+ filename:join([Dir, "client", "cacerts.pem"])),
+ cosFileTransferApp:configure(ssl_client_verify, 1),
+ cosFileTransferApp:configure(ssl_client_depth, 0),
+ %% Server
+ cosFileTransferApp:configure(ssl_server_certfile,
+ filename:join([Dir, "server", "cert.pem"])),
+ cosFileTransferApp:configure(ssl_server_cacertfile,
+ filename:join([Dir, "server", "cacerts.pem"])),
+ cosFileTransferApp:configure(ssl_server_verify, 1),
+ cosFileTransferApp:configure(ssl_server_depth, 0),
+ crypto:start(),
+ ssl:start(),
+ cosFileTransferApp:install(),
+ cosFileTransferApp:start(),
+ if
+ is_list(Config) ->
+ Config;
+ true ->
+ exit("Config not a list")
+ end.
+
+finish_all(Config) ->
+ ssl:stop(),
+ crypto:stop(),
+ cosFileTransferApp:stop(),
+ cosProperty:stop(),
+ cosProperty:uninstall(),
+ cosFileTransferApp:uninstall(),
+ orber:jump_stop(),
+ Config.
+
+%%-----------------------------------------------------------------
+%% Local definitions
+%%-----------------------------------------------------------------
+-define(FTP_USER, "anonymous").
+-define(FTP_PASS, "fileTransfer_SUITE@localhost").
+-define(TEST_DIR,["/", "incoming"]).
+
+
+-define(FTP_PORT, 21).
+-define(FTP_ACC, "anonymous").
+
+-define(BAD_HOST, "badhostname").
+-define(BAD_USER, "baduser").
+-define(BAD_DIR, "baddirectory").
+
+-define(TEST_FILE_DATA, "If this file exists after a completed test an error occurred.").
+-define(TEST_FILE_DATA2, "1234567890123").
+
+
+%%-----------------------------------------------------------------
+%% aoo-file test
+%%-----------------------------------------------------------------
+app_test(doc) -> [];
+app_test(suite) -> [];
+app_test(_Config) ->
+ ?line ok=?t:app_test(cosFileTransfer),
+ ok.
+
+%%-----------------------------------------------------------------
+%% FileIterator API tests
+%%-----------------------------------------------------------------
+fileIterator_api(doc) -> ["CosFileTransfer FileIterator API tests.", ""];
+fileIterator_api(suite) -> [];
+fileIterator_api(Config) ->
+ case ftp_host(Config) of
+ {skipped, SkippedReason} ->
+ {skipped, SkippedReason};
+ Host ->
+
+ ?line {ok, Node} = create_node("fileIterator_api", 4008, normal),
+ ?line ?match(ok, remote_apply(Node, ?MODULE, install_data,
+ [tcp, {{'NATIVE',
+ 'cosFileTransferNATIVE_file'}, Host,
+ "fileIterator_api"}])),
+
+ %% Create a Virtual File System.
+%% ?line VFS = ?match({_,_,_,_,_,_},
+%% cosFileTransferApp:create_VFS({'NATIVE',
+%% 'cosFileTransferNATIVE_file'},
+%% [], Host, ?FTP_PORT)),
+ ?line VFS = ?matchnopr({'IOP_IOR',"IDL:omg.org/CosFileTransfer/VirtualFileSystem:1.0",_},
+ corba:string_to_object("corbaname::1.2@localhost:4008/NameService#fileIterator_api")),
+
+ %% Start two File Transfer Sessions (Source and Target).
+ ?line {FS, Dir} = ?matchnopr({{_,_,_},{_,_,_}},
+ 'CosFileTransfer_VirtualFileSystem':login(VFS,
+ ?FTP_USER,
+ ?FTP_PASS,
+ ?FTP_ACC)),
+
+ %% Do some basic test on one of the Directories attributes.
+ ?line ?match([_H|_], 'CosFileTransfer_Directory':'_get_name'(Dir)),
+ ?line ?match([_H|_], 'CosFileTransfer_Directory':'_get_complete_file_name'(Dir)),
+ ?line ?match({'IOP_IOR',[],[]}, 'CosFileTransfer_Directory':'_get_parent'(Dir)),
+ ?line ?matchnopr(FS, 'CosFileTransfer_Directory':'_get_associated_session'(Dir)),
+ {ok,[],FileIter} = ?match({ok,[],_}, 'CosFileTransfer_Directory':list(Dir, 0)),
+ %% Usually the working directory for the test is not empty so no need for
+ %% creating files of our own?!
+ #any{value=Children} = ?match({any, _, _},
+ 'CosPropertyService_PropertySet':
+ get_property_value(Dir, "num_children")),
+
+ if
+ Children > 5 ->
+ ?line ?matchnopr({true, _}, 'CosFileTransfer_FileIterator':next_one(FileIter)),
+ ?line ?matchnopr({true, _}, 'CosFileTransfer_FileIterator':next_n(FileIter, 3)),
+ ?line ?matchnopr({true, _}, 'CosFileTransfer_FileIterator':next_n(FileIter,
+ Children)),
+ ?line ?matchnopr({false, _}, 'CosFileTransfer_FileIterator':next_one(FileIter)),
+ ?line ?match({false, []}, 'CosFileTransfer_FileIterator':next_n(FileIter, 1)),
+ ok;
+ true ->
+ ok
+ end,
+ ?line ?match(ok, 'CosFileTransfer_FileIterator':destroy(FileIter)),
+ ?line ?match(false, corba_object:non_existent(FS)),
+ ?line ?match(ok, 'CosFileTransfer_FileTransferSession':logout(FS)),
+ %% To make sure Orber can remove it from mnesia.
+ timer:sleep(1000),
+ ?line ?match(true, corba_object:non_existent(FS)),
+ ?line ?match(ok, remote_apply(Node, ?MODULE, uninstall_data, ["fileIterator_api"])),
+ stop_orber_remote(Node, normal),
+ ok
+ end.
+
+
+%%-----------------------------------------------------------------
+%% FileTransferSession API tests
+%%-----------------------------------------------------------------
+fts_ftp_file_api(doc) -> ["CosFileTransfer FTP FileTransferSession API tests.", ""];
+fts_ftp_file_api(suite) -> [];
+fts_ftp_file_api(Config) ->
+ ?line {ok, Node} = create_node("ftp_file_api", 4004, normal),
+ file_helper(Config, 'FTP', ?TEST_DIR, Node, 4004, "ftp_file_api", tcp).
+
+fts_ftp_file_ssl_api(doc) -> ["CosFileTransfer FTP FileTransferSession API tests.", ""];
+fts_ftp_file_ssl_api(suite) -> [];
+fts_ftp_file_ssl_api(Config) ->
+ case os:type() of
+ vxworks ->
+ {skipped, "No SSL-support for VxWorks."};
+ _ ->
+ ?line {ok, Node} = create_node("ftp_file_api_ssl", {4005, 1}, ssl),
+ file_helper(Config, 'FTP', ?TEST_DIR, Node, 4005, "ftp_file_api_ssl", ssl)
+ end.
+
+fts_native_file_api(doc) -> ["CosFileTransfer NATIVE FileTransferSession API tests.", ""];
+fts_native_file_api(suite) -> [];
+fts_native_file_api(Config) ->
+ ?line {ok, Node} = create_node("native_file_api", 4006, normal),
+ {ok, Pwd} = file:get_cwd(),
+ file_helper(Config,{'NATIVE', 'cosFileTransferNATIVE_file'},filename:split(Pwd),
+ Node, 4006, "native_file_api", tcp).
+
+fts_native_file_ssl_api(doc) -> ["CosFileTransfer NATIVE FileTransferSession API tests.", ""];
+fts_native_file_ssl_api(suite) -> [];
+fts_native_file_ssl_api(Config) ->
+ case os:type() of
+ vxworks ->
+ {skipped, "No SSL-support for VxWorks."};
+ _ ->
+ ?line {ok, Node} = create_node("native_file_ssl_api", {4007, 1}, ssl),
+ {ok, Pwd} = file:get_cwd(),
+ file_helper(Config,{'NATIVE', 'cosFileTransferNATIVE_file'},filename:split(Pwd),
+ Node, 4007, "native_file_ssl_api", ssl)
+ end.
+
+
+
+file_helper(Config, WhichType, TEST_DIR, Node, Port, Name, Type) ->
+ case ftp_host(Config) of
+ {skipped, SkippedReason} ->
+ {skipped, SkippedReason};
+ Host ->
+ TEST_SOURCE = TEST_DIR ++ [create_name(remove_me_source)],
+ TEST_SOURCE2 = TEST_DIR ++ [create_name(remove_me_source)],
+ TEST_TARGET = TEST_DIR ++ [create_name(remove_me_target)],
+
+ io:format("<<<<<< CosFileTransfer Testing Configuration >>>>>>~n",[]),
+ io:format("Source: ~p~nTarget: ~p~n", [TEST_SOURCE, TEST_TARGET]),
+
+ ?line ?match(ok, remote_apply(Node, ?MODULE, install_data,
+ [Type, {WhichType, Host, Name}])),
+
+ ?line VFST = ?match({'IOP_IOR',"IDL:omg.org/CosFileTransfer/VirtualFileSystem:1.0",_},
+ corba:string_to_object("corbaname::1.2@localhost:"++integer_to_list(Port)++"/NameService#"++Name)),
+
+
+ %% Create a Virtual File System.
+ ?line VFS = ?match({_,_,_,_,_,_},
+ cosFileTransferApp:create_VFS(WhichType, [], Host, ?FTP_PORT,
+ [{protocol, Type}])),
+ %% Start two File Transfer Sessions (Source and Target).
+ ?line {FST, _DirT} = ?match({{_,_,_},{_,_,_}},
+ 'CosFileTransfer_VirtualFileSystem':login(VFST,
+ ?FTP_USER,
+ ?FTP_PASS,
+ ?FTP_ACC)),
+ ?line {FSS, DirS} = ?match({{_,_,_,_,_,_},{_,_,_,_,_,_}},
+ 'CosFileTransfer_VirtualFileSystem':login(VFS,
+ ?FTP_USER,
+ ?FTP_PASS,
+ ?FTP_ACC)),
+
+ %% Do some basic test on one of the Directories attributes.
+ ?line ?match([_H|_], 'CosFileTransfer_Directory':'_get_name'(DirS)),
+ ?line ?match([_H|_], 'CosFileTransfer_Directory':'_get_complete_file_name'(DirS)),
+ ?line ?match({'IOP_IOR',[],[]}, 'CosFileTransfer_Directory':'_get_parent'(DirS)),
+ ?line ?match(FSS, 'CosFileTransfer_Directory':'_get_associated_session'(DirS)),
+
+ %% Get a FileList before we create any new Files
+ ?line #'CosFileTransfer_FileWrapper'{the_file = Dir} =
+ ?match({'CosFileTransfer_FileWrapper', _, ndirectory},
+ 'CosFileTransfer_FileTransferSession':get_file(FSS, TEST_DIR)),
+ ?line {ok,FileList, Iter1} = ?match({ok,_,_}, 'CosFileTransfer_Directory':list(Dir, 10)),
+ ?line loop_files(FileList),
+
+ case Iter1 of
+ {'IOP_IOR',[],[]} ->
+ ok;
+ _->
+ ?line ?match(ok, 'CosFileTransfer_FileIterator':destroy(Iter1))
+ end,
+
+ #any{value=Count1} = ?match({any, _, _}, 'CosPropertyService_PropertySet':
+ get_property_value(Dir, "num_children")),
+
+ %% Now we want to transfer a file from source to target. First, we'll create
+ %% a a file to work with.
+ ?line create_file_on_source_node(WhichType, Config, Host,
+ filename:join(TEST_SOURCE), TEST_DIR,
+ ?TEST_FILE_DATA),
+ ?line create_file_on_source_node(WhichType, Config, Host,
+ filename:join(TEST_SOURCE2), TEST_DIR,
+ ?TEST_FILE_DATA2),
+
+ ?line #'CosFileTransfer_FileWrapper'{the_file = FileS} =
+ ?matchnopr({'CosFileTransfer_FileWrapper', _, nfile},
+ 'CosFileTransfer_FileTransferSession':get_file(FSS, TEST_SOURCE)),
+ ?line #'CosFileTransfer_FileWrapper'{the_file = FileS2} =
+ ?matchnopr({'CosFileTransfer_FileWrapper', _, nfile},
+ 'CosFileTransfer_FileTransferSession':get_file(FSS, TEST_SOURCE2)),
+
+ #any{value=Count2} = ?match({any, _, _}, 'CosPropertyService_PropertySet':
+ get_property_value(Dir, "num_children")),
+ timer:sleep(2000),
+ ?match(true, (Count1+2 == Count2)),
+
+ %% Create a target File
+ ?line FileT = ?matchnopr({_,_,_},
+ 'CosFileTransfer_FileTransferSession':create_file(FST, TEST_TARGET)),
+ %% Try to delete the non-existing file.
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_FileTransferSession':delete(FST, FileT)),
+
+ ?line ?match(ok, 'CosFileTransfer_FileTransferSession':transfer(FSS, FileS, FileT)),
+
+ %% Remove this test when ftp supports append.
+ case WhichType of
+ {'NATIVE', 'cosFileTransferNATIVE_file'} ->
+ ?line ?match(ok, 'CosFileTransfer_FileTransferSession':append(FSS, FileS, FileT)),
+ ?line ?match(ok, 'CosFileTransfer_FileTransferSession':insert(FSS, FileS2, FileT, 7));
+ _->
+ ok
+ end,
+
+ %% Delete source and target files
+ ?line ?match(ok, 'CosFileTransfer_FileTransferSession':delete(FSS, FileS)),
+ ?line ?match(ok, 'CosFileTransfer_FileTransferSession':delete(FSS, FileS2)),
+ ?line ?match(ok, 'CosFileTransfer_FileTransferSession':delete(FST, FileT)),
+
+ %% Should be back where we started.
+ timer:sleep(2000),
+ #any{value=Count3} = ?match({any, _, _}, 'CosPropertyService_PropertySet':
+ get_property_value(Dir, "num_children")),
+ ?match(true, (Count1 == Count3)),
+
+
+ ?line ?match(false, corba_object:non_existent(FSS)),
+ ?line ?match(false, corba_object:non_existent(FST)),
+ ?line ?match(ok, 'CosFileTransfer_FileTransferSession':logout(FSS)),
+ ?line ?match(ok, 'CosFileTransfer_FileTransferSession':logout(FST)),
+ %% To make sure Orber can remove it from mnesia.
+ timer:sleep(2000),
+ ?line ?match(true, corba_object:non_existent(FSS)),
+ ?line ?match(true, corba_object:non_existent(FST)),
+ ?line ?match(ok, remote_apply(Node, ?MODULE, uninstall_data, [Name])),
+ stop_orber_remote(Node, normal),
+ ok
+ end.
+
+%%-----------------------------------------------------------------
+%% FileTransferSession API tests
+%%-----------------------------------------------------------------
+fts_ftp_dir_api(doc) -> ["CosFileTransfer FTP FileTransferSession API tests.", ""];
+fts_ftp_dir_api(suite) -> [];
+fts_ftp_dir_api(Config) ->
+ ?line {ok, Node} = create_node("ftp_dir_api", 4009, normal),
+ dir_helper(Config, 'FTP', ?TEST_DIR, Node, 4009, "ftp_dir_api").
+
+
+fts_native_dir_api(doc) -> ["CosFileTransfer NATIVE FileTransferSession API tests.", ""];
+fts_native_dir_api(suite) -> [];
+fts_native_dir_api(Config) ->
+ ?line {ok, Node} = create_node("native_dir_api", 4010, normal),
+ {ok, Pwd} = file:get_cwd(),
+ dir_helper(Config, {'NATIVE', 'cosFileTransferNATIVE_file'},
+ filename:split(Pwd), Node, 4010, "native_dir_api").
+
+dir_helper(Config, WhichType, TEST_DIR, Node, Port, Name) ->
+ case ftp_host(Config) of
+ {skipped, SkippedReason} ->
+ {skipped, SkippedReason};
+ Host ->
+ TEST_DIR_LEVEL1 = TEST_DIR ++ [create_name(remove_me_dir1)],
+ TEST_DIR_LEVEL2 = TEST_DIR_LEVEL1 ++ [create_name(remove_me_dir2)],
+
+ io:format("<<<<<< CosFileTransfer Testing Configuration >>>>>>~n",[]),
+ io:format("Top Dir: ~p~nLevel2 Dir: ~p~n", [TEST_DIR_LEVEL1, TEST_DIR_LEVEL2]),
+
+ ?line ?match(ok, remote_apply(Node, ?MODULE, install_data,
+ [tcp, {WhichType, Host, Name}])),
+
+ ?line VFS = ?matchnopr({'IOP_IOR',"IDL:omg.org/CosFileTransfer/VirtualFileSystem:1.0",_},
+ corba:string_to_object("corbaname::1.2@localhost:"++integer_to_list(Port)++"/NameService#"++Name)),
+
+ %% Start two File Transfer Sessions (Source and Target).
+ ?line {FS, DirS} = ?matchnopr({{'IOP_IOR',_,_}, _},
+ 'CosFileTransfer_VirtualFileSystem':login(VFS,
+ ?FTP_USER,
+ ?FTP_PASS,
+ ?FTP_ACC)),
+
+ %% Do some basic test on one of the Directories attributes.
+ ?line ?match([_H|_], 'CosFileTransfer_Directory':'_get_name'(DirS)),
+ ?line ?match([_H|_], 'CosFileTransfer_Directory':'_get_complete_file_name'(DirS)),
+ ?line ?match({'IOP_IOR',[],[]}, 'CosFileTransfer_Directory':'_get_parent'(DirS)),
+ ?line ?matchnopr(FS, 'CosFileTransfer_Directory':'_get_associated_session'(DirS)),
+
+ %% Create a Root Directory. Currently we only need to create one but
+ %% later on, when supporting other protocols than FTP it's not enough.
+ ?line Dir1 = 'CosFileTransfer_FileTransferSession':create_directory(FS,
+ TEST_DIR_LEVEL1),
+ io:format("<<<<<< CosFileTransfer Testing Properties >>>>>>~n",[]),
+ ?line ?match({ok, [tk_long, tk_boolean]},
+ 'CosFileTransfer_Directory':get_allowed_property_types(Dir1)),
+ ?line ?match({ok, [_,_]},
+ 'CosFileTransfer_Directory':get_allowed_properties(Dir1)),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':define_property_with_mode(Dir1,
+ "num_children",
+ #any{typecode=tk_long, value=0},
+ fixed_readonly)),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':define_property_with_mode(Dir1,
+ "wrong",
+ #any{typecode=tk_long, value=0},
+ fixed_readonly)),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':define_property_with_mode(Dir1,
+ "num_children",
+ #any{typecode=tk_short, value=0},
+ fixed_readonly)),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':define_property_with_mode(Dir1,
+ "num_children",
+ #any{typecode=tk_long, value=0},
+ fixed_normal)),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':define_properties_with_modes(Dir1,
+ [#'CosPropertyService_PropertyDef'
+ {property_name = "num_children",
+ property_value = #any{typecode=tk_long, value=0},
+ property_mode = fixed_readonly}])),
+ ?line ?match(fixed_readonly,
+ 'CosFileTransfer_Directory':get_property_mode(Dir1, "num_children")),
+ ?line ?match({true,
+ [#'CosPropertyService_PropertyMode'{property_name = "num_children",
+ property_mode = fixed_readonly}]},
+ 'CosFileTransfer_Directory':get_property_modes(Dir1, ["num_children"])),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':set_property_mode(Dir1, "num_children", fixed_readonly)),
+
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':
+ set_property_modes(Dir1,
+ [#'CosPropertyService_PropertyMode'
+ {property_name = "num_children",
+ property_mode = fixed_readonly}])),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':
+ set_property_modes(Dir1,
+ [#'CosPropertyService_PropertyMode'
+ {property_name = "wrong",
+ property_mode = fixed_readonly}])),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':
+ set_property_modes(Dir1,
+ [#'CosPropertyService_PropertyMode'
+ {property_name = "num_children",
+ property_mode = fixed_normal}])),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':define_property(Dir1,
+ "num_children",
+ #any{typecode=tk_long, value=0})),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':define_property(Dir1,
+ "wrong",
+ #any{typecode=tk_long, value=0})),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':define_property(Dir1,
+ "num_children",
+ #any{typecode=tk_short, value=0})),
+
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':define_property(Dir1,
+ "num_children",
+ #any{typecode=tk_long, value=0})),
+
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':
+ define_properties(Dir1,
+ [#'CosPropertyService_Property'
+ {property_name = "num_children",
+ property_value = #any{typecode=tk_long,
+ value=0}}])),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':
+ define_properties(Dir1,
+ [#'CosPropertyService_Property'
+ {property_name = "wrong",
+ property_value = #any{typecode=tk_long,
+ value=0}}])),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':
+ define_properties(Dir1,
+ [#'CosPropertyService_Property'
+ {property_name = "num_children",
+ property_value = #any{typecode=tk_short,
+ value=0}}])),
+ ?line ?match(2, 'CosFileTransfer_Directory':get_number_of_properties(Dir1)),
+
+ ?line ?match({ok, ["num_children", "is_directory"], {'IOP_IOR',[],[]}},
+ 'CosFileTransfer_Directory':get_all_property_names(Dir1, 2)),
+ ?line ?match({ok, ["is_directory"], _},
+ 'CosFileTransfer_Directory':get_all_property_names(Dir1, 1)),
+
+ ?line ?match(#any{},
+ 'CosFileTransfer_Directory':get_property_value(Dir1, "num_children")),
+ ?line ?match(#any{},
+ 'CosFileTransfer_Directory':get_property_value(Dir1, "is_directory")),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':get_property_value(Dir1, "wrong")),
+
+ ?line ?match({true,
+ [#'CosPropertyService_Property'{property_name = "num_children"}]},
+ 'CosFileTransfer_Directory':get_properties(Dir1, ["num_children"])),
+ ?line ?match({false,
+ [#'CosPropertyService_Property'{property_name = "wrong"}]},
+ 'CosFileTransfer_Directory':get_properties(Dir1, ["wrong"])),
+
+ ?line ?match({ok, [_],_},
+ 'CosFileTransfer_Directory':get_all_properties(Dir1, 1)),
+ ?line ?match({ok, [_,_], {'IOP_IOR',[],[]}},
+ 'CosFileTransfer_Directory':get_all_properties(Dir1, 2)),
+
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':delete_property(Dir1, "num_children")),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':delete_property(Dir1, "wrong")),
+
+
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':delete_properties(Dir1, ["num_children"])),
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_Directory':delete_properties(Dir1, ["wrong"])),
+ ?line ?match(false, 'CosFileTransfer_Directory':delete_all_properties(Dir1)),
+ ?line ?match(true,
+ 'CosFileTransfer_Directory':is_property_defined(Dir1, "num_children")),
+ ?line ?match(false,
+ 'CosFileTransfer_Directory':is_property_defined(Dir1, "wrong")),
+
+ %% The Top Dir should be empty and ...
+ ?line ?match({ok,[],_}, 'CosFileTransfer_Directory':list(Dir1, 1000)),
+ ?line ?match( #any{value=0},
+ 'CosPropertyService_PropertySet':get_property_value(Dir1, "num_children")),
+ %% Create a sub-directory.
+ ?line Dir2 = 'CosFileTransfer_FileTransferSession':create_directory(FS,
+ TEST_DIR_LEVEL2),
+ ?line ?match( #any{value=1},
+ 'CosPropertyService_PropertySet':get_property_value(Dir1, "num_children")),
+
+ ?line ?match({ok, [_,_], {'IOP_IOR',[],[]}},
+ 'CosFileTransfer_Directory':get_all_properties(Dir1, 2)),
+ ?line {_,_,Iterator1} = ?match({ok, [_], _},
+ 'CosFileTransfer_Directory':get_all_properties(Dir1, 1)),
+ ?line ?match({false, [_]},
+ 'CosPropertyService_PropertiesIterator':next_n(Iterator1,4)),
+
+ ?line {_,_,Iterator0} = ?match({ok, [], _},
+ 'CosFileTransfer_Directory':get_all_properties(Dir1, 0)),
+
+ ?line ?match({false, [_, {'CosPropertyService_Property',
+ "num_children",{any,tk_long,1}}]},
+ 'CosPropertyService_PropertiesIterator':next_n(Iterator0,4)),
+
+ ?line ?match({true,
+ [#'CosPropertyService_Property'{property_name = "num_children"}]},
+ 'CosFileTransfer_Directory':get_properties(Dir1, ["num_children"])),
+
+ %% The Top Directory is not emtpy any more and ...
+ ?line {ok,[#'CosFileTransfer_FileWrapper'{the_file = DirRef}],_} =
+ ?matchnopr({ok,[{'CosFileTransfer_FileWrapper', _, ndirectory}],_},
+ 'CosFileTransfer_Directory':list(Dir1, 1000)),
+ %% ... its name eq. to 'TEST_DIR_LEVEL2'
+ ?line ?match(TEST_DIR_LEVEL2,
+ 'CosFileTransfer_Directory':'_get_complete_file_name'(DirRef)),
+
+ ?line #'CosFileTransfer_FileWrapper'{the_file = Dir3} =
+ ?matchnopr({'CosFileTransfer_FileWrapper', _, ndirectory},
+ 'CosFileTransfer_FileTransferSession':get_file(FS, TEST_DIR_LEVEL1)),
+
+ %% Must get the same result for the 'get_file' operation.
+ ?line {ok,[#'CosFileTransfer_FileWrapper'{the_file = DirRef2}],_} =
+ ?matchnopr({ok,[{'CosFileTransfer_FileWrapper', _, ndirectory}],_},
+ 'CosFileTransfer_Directory':list(Dir3,1000)),
+ ?line ?match(TEST_DIR_LEVEL2,
+ 'CosFileTransfer_Directory':'_get_complete_file_name'(DirRef2)),
+
+ %% Since the top directory isn't empty deleting it must fail.
+ ?line ?match({'EXCEPTION', _},
+ 'CosFileTransfer_FileTransferSession':delete(FS, Dir1)),
+
+ %% Delete the sub-directory and ...
+ ?line ?match(ok, 'CosFileTransfer_FileTransferSession':delete(FS, Dir2)),
+ %% ... see if the top directory realyy is empty.
+ ?line ?match({ok,[],_}, 'CosFileTransfer_Directory':list(Dir1, 1000)),
+
+ ?line ?match(ok, 'CosFileTransfer_FileTransferSession':delete(FS, Dir1)),
+ %% Test if the top directory been removed as intended.
+ ?line ?match({'EXCEPTION', {'CosFileTransfer_FileNotFoundException', _, _}},
+ 'CosFileTransfer_FileTransferSession':get_file(FS, TEST_DIR_LEVEL1)),
+
+ ?line ?match(false, corba_object:non_existent(FS)),
+ ?line ?match(ok, 'CosFileTransfer_FileTransferSession':logout(FS)),
+ %% To make sure Orber can remove it from mnesia.
+ timer:sleep(1000),
+ ?line ?match(true, corba_object:non_existent(FS)),
+ ?line ?match(ok, remote_apply(Node, ?MODULE, uninstall_data, [Name])),
+ stop_orber_remote(Node, normal),
+ ok
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
+ftp_host(Config) ->
+ case ?config(ftp_remote_host, Config) of
+ undefined ->
+ {skipped, "The configuration parameter 'ftp_remote_host' not defined."};
+ Host ->
+ Host
+ end.
+
+loop_files([]) ->
+ io:format("@@@ DONE @@@~n", []);
+loop_files([#'CosFileTransfer_FileWrapper'{the_file = H}|T]) ->
+ FullName = 'CosFileTransfer_File':'_get_complete_file_name'(H),
+ Name = 'CosFileTransfer_File':'_get_name'(H),
+ io:format("FULL NAME: ~p SHORT NAME: ~p~n", [FullName, Name]),
+ loop_files(T).
+
+
+create_file_on_source_node('FTP', _Config, Host, FileName, Path, Data) ->
+ io:format("<<<<<< CosFileTransfer Testing File >>>>>>~n",[]),
+ io:format("Host: ~p~nPath: ~p~nFile: ~p~n", [Host, Path, FileName]),
+ {ok, Pid} = ?match({ok, _}, inets:start(ftpc, [{host, Host}], stand_alone)),
+ ?match(ok, ftp:user(Pid, ?FTP_USER, ?FTP_PASS)),
+ ?match(ok, ftp:cd(Pid, Path)),
+ ?match(ok, ftp:send_bin(Pid, list_to_binary(Data), FileName)),
+ ?match(ok, inets:stop(ftpc, Pid));
+create_file_on_source_node({'NATIVE', _}, _Config, Host, FileName, Path, Data) ->
+ io:format("<<<<<< CosFileTransfer Testing File >>>>>>~n",[]),
+ io:format("Host: ~p~nPath: ~p~nFile: ~p~n", [Host, Path, FileName]),
+ ?match(ok, file:write_file(FileName, list_to_binary(Data))).
+
+create_name(Type) ->
+ {MSec, Sec, USec} = erlang:now(),
+ lists:concat([Type,'_',MSec, '_', Sec, '_', USec]).
+
+
+
+
+%%------------------------------------------------------------
+%% function : create_node/4
+%% Arguments: Name - the name of the new node (atom())
+%% Port - which iiop_port (integer())
+%% Domain - which domain.
+%% Type - if /4 used the types defines the extra arguments
+%% to be used.
+%% Returns : {ok, Node} | {error, _}
+%% Effect : Starts a new slave-node with given (optinally)
+%% extra arguments. If fails it retries 'Retries' times.
+%%------------------------------------------------------------
+create_node(Name, Port, normal) ->
+ Args = basic_args(Name),
+ create_node(Name, Port, 10, normal, Args, []);
+create_node(Name, {Port, _Depth}, ssl) ->
+ Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
+ Args = basic_args(Name),
+ {ok, Node} = create_node(list_to_atom(Name), Port, 10, ssl, Args, []),
+ %% Client
+ rpc:call(Node, application, set_env, [cosFileTransfer, ssl_client_certfile,
+ filename:join([Dir, "client", "cert.pem"])]),
+ rpc:call(Node, application, set_env, [cosFileTransfer, ssl_client_cacertfile,
+ filename:join([Dir, "client", "cacerts.pem"])]),
+ rpc:call(Node, application, set_env, [cosFileTransfer, ssl_client_keyfile,
+ filename:join([Dir, "client", "key.pem"])]),
+ rpc:call(Node, application, set_env, [cosFileTransfer, ssl_client_verify, 1]),
+ rpc:call(Node, application, set_env, [cosFileTransfer, ssl_client_depth, 0]),
+
+ %% Server
+ rpc:call(Node, application, set_env, [cosFileTransfer, ssl_server_certfile,
+ filename:join([Dir, "server", "cert.pem"])]),
+ rpc:call(Node, application, set_env, [cosFileTransfer, ssl_server_cacertfile,
+ filename:join([Dir, "server", "cacerts.pem"])]),
+ rpc:call(Node, application, set_env, [cosFileTransfer, ssl_server_keyfile,
+ filename:join([Dir, "server", "key.pem"])]),
+ rpc:call(Node, application, set_env, [cosFileTransfer, ssl_server_verify, 1]),
+ rpc:call(Node, application, set_env, [cosFileTransfer, ssl_server_depth, 0]),
+ {ok, Node}.
+
+%create_node(Name, {Port, Depth}, ssl) ->
+% TestLibs = filename:join(filename:dirname(code:which(?MODULE)), "ssl_data"),
+% Args = basic_args(Name),
+% SArgs = basic_ssl_args(TestLibs, Args),
+% LArgs = level_based_ssl(Depth, TestLibs, SArgs),
+% create_node(list_to_atom(Name), Port, 10, ssl, LArgs, [{sslpath, TestLibs}]).
+
+create_node(Name, Port, Retries, Type, Args, Options) ->
+ [_, Host] = ?match([_,_],string:tokens(atom_to_list(node()), [$@])),
+ case starter(Host, Name, Args) of
+ {ok, NewNode} ->
+ ?line ?match(pong, net_adm:ping(NewNode)),
+ {ok, Cwd} = file:get_cwd(),
+ Path = code:get_path(),
+ ?line ?match(ok, rpc:call(NewNode, file, set_cwd, [Cwd])),
+ true = rpc:call(NewNode, code, set_path, [Path]),
+ ?match(ok, start_orber_remote(NewNode, Type, Options, Port)),
+ spawn_link(NewNode, ?MODULE, slave_sup, []),
+ rpc:multicall([node() | nodes()], global, sync, []),
+ {ok, NewNode};
+ {error, Reason} when Retries == 0->
+ {error, Reason};
+ {error, Reason} ->
+ io:format("Could not start slavenode ~p ~p retrying~n",
+ [{Host, Name, Args}, Reason]),
+ timer:sleep(500),
+ create_node(Name, Port, Retries - 1, Type, Args, Options)
+ end.
+
+starter(Host, Name, Args) ->
+ case os:type() of
+ vxworks ->
+ test_server:start_node(Name, slave, [{args,Args}]);
+ _ ->
+ slave:start(Host, Name, Args)
+ end.
+
+slave_sup() ->
+ process_flag(trap_exit, true),
+ receive
+ {'EXIT', _, _} ->
+ case os:type() of
+ vxworks ->
+ erlang:halt();
+ _ ->
+ ignore
+ end
+ end.
+
+
+%%------------------------------------------------------------
+%% function : destroy_node
+%% Arguments: Node - which node to destroy.
+%% Type - normal | ssl
+%% Returns :
+%% Effect :
+%%------------------------------------------------------------
+-ifdef(false).
+destroy_node(Node, Type) ->
+ stopper(Node, Type).
+
+stopper(Node, Type) ->
+ catch stop_orber_remote(Node, Type),
+ case os:type() of
+ vxworks ->
+ test_server:stop_node(Node);
+ _ ->
+ slave:stop(Node)
+ end.
+-endif.
+
+%%------------------------------------------------------------
+%% function : remote_apply
+%% Arguments: N - Node, M - Module,
+%% F - Function, A - Arguments (list)
+%% Returns :
+%% Effect :
+%%------------------------------------------------------------
+remote_apply(N, M,F,A) ->
+ case rpc:call(N, M, F, A) of
+ {badrpc, Reason} ->
+ exit(Reason);
+ Other ->
+ Other
+ end.
+
+%%------------------------------------------------------------
+%% function : stop_orber_remote
+%% Arguments: Node - which node to stop orber on.
+%% Type - normal | ssl | light | .......
+%% Returns : ok
+%% Effect : Stops orber on given node and, if specified,
+%% other applications or programs.
+%%------------------------------------------------------------
+stop_orber_remote(Node, ssl) ->
+ rpc:call(Node, ssl, stop, []),
+ rpc:call(Node, crypto, stop, []),
+ orb_rpc_blast(Node, ssl);
+stop_orber_remote(Node, Type) ->
+ orb_rpc_blast(Node, Type).
+
+orb_rpc_blast(Node, _) ->
+ rpc:call(Node, cosFileTransferApp, stop, []),
+ rpc:call(Node, cosProperty, stop, []),
+ rpc:call(Node, cosFileTransferApp, uninstall, []),
+ rpc:call(Node, cosProperty, uninstall, []),
+ rpc:call(Node, orber, jump_stop, []).
+
+%%------------------------------------------------------------
+%% function : start_orber_remote
+%% Arguments: Node - which node to start orber on.
+%% Type - normal | ssl | light | .......
+%% Returns : ok
+%% Effect : Starts orber on given node and, if specified,
+%% other applications or programs.
+%%------------------------------------------------------------
+start_orber_remote(Node, ssl, _Options, Port) ->
+ rpc:call(Node, ssl, start, []),
+ rpc:call(Node, crypto, start, []),
+ rpc:call(Node, ssl, seed, ["testing"]),
+ orb_rpc_setup(Node, ssl, Port);
+start_orber_remote(Node, Type, _, Port) ->
+ orb_rpc_setup(Node, Type, Port).
+
+orb_rpc_setup(Node, _, Port) ->
+ rpc:call(Node, orber, jump_start, [Port]),
+ rpc:call(Node, cosProperty, install, []),
+ rpc:call(Node, cosProperty, start, []),
+ rpc:call(Node, cosFileTransferApp, install, []).
+
+%%--------------- MISC FUNCTIONS -----------------------------
+basic_args(_Name) ->
+ TestLibs = filename:dirname(code:which(?MODULE)),
+ " -orber orber_debug_level 10" ++
+ " -pa " ++
+ TestLibs ++
+ " -pa " ++
+ filename:join(TestLibs, "all_SUITE_data") ++
+ " -pa " ++
+ filename:dirname(code:which(cosFileTransferApp)).
+
+-ifdef(false).
+basic_ssl_args(TestLibs, Args) ->
+% Args ++
+% " -cosFileTransfer ssl_client_certfile \\\"" ++
+% filename:join(TestLibs, "ssl_client_cert.pem") ++
+% "\\\" -cosFileTransfer ssl_server_certfile \\\""++
+% filename:join(TestLibs, "ssl_server_cert.pem")++"\\\"".
+
+ io:format("<<<<<< SSL LIBS ~p >>>>>>~n",[TestLibs]),
+ NewArgs = Args ++
+ " -cosFileTransfer ssl_client_certfile \\\"" ++
+ filename:join(TestLibs, "ssl_client_cert.pem") ++
+ "\\\" -cosFileTransfer ssl_server_certfile \\\""++
+ filename:join(TestLibs, "ssl_server_cert.pem")++"\\\"",
+ io:format("<<<<<< SSL LIBS ARGS ~p >>>>>>~n",[NewArgs]),
+ NewArgs.
+
+level_based_ssl(1, _TestLibs, Args) ->
+ Args;
+level_based_ssl(2, _TestLibs, Args) ->
+ Args.% ++
+% " -cosFileTransfer ssl_server_depth 2 " ++
+% " -cosFileTransfer ssl_client_depth 2 " ++
+% " -cosFileTransfer ssl_server_verify " ++
+% " -cosFileTransfer ssl_client_verify " ++
+% " -cosFileTransfer ssl_server_cacertfile " ++
+% " -cosFileTransfer ssl_client_cacertfile " ++
+
+-endif.
+
+install_data(Protocol, {WhichType, Host, Name}) ->
+ io:format("<<<<<< Starting ~p/~p VFS at ~p/~p>>>>>>~n",
+ [Protocol, WhichType, Host, Name]),
+ %% Create a Virtual File System.
+ ?line VFS = ?match({_,_,_,_,_,_},
+ cosFileTransferApp:create_VFS(WhichType, [], Host, ?FTP_PORT,
+ [{protocol, Protocol}])),
+ NS = corba:resolve_initial_references("NameService"),
+ NC1 = lname_component:set_id(lname_component:create(), Name),
+ N = lname:insert_component(lname:create(), 1, NC1),
+ 'CosNaming_NamingContext':rebind(NS, N, VFS).
+
+uninstall_data(Name) ->
+ ?line VFS = ?match({_,_,_,_,_,_},
+ corba:string_to_object("corbaname:rir:/NameService#"++Name)),
+ ?line ?match(ok, corba:dispose(VFS)),
+ ok.
+
+
+
+%%------------------- EOF MODULE-----------------------------------
diff --git a/lib/cosNotification/doc/src/notes.xml b/lib/cosNotification/doc/src/notes.xml
index de5a3e5f4c..04c0c2accd 100644
--- a/lib/cosNotification/doc/src/notes.xml
+++ b/lib/cosNotification/doc/src/notes.xml
@@ -31,6 +31,46 @@
<file>notes.xml</file>
</header>
+ <section><title>cosNotification 1.1.15</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Switched from using the deprecated regexp to re instead.</p>
+ <p>
+ Own Id: OTP-8846</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section>
+ <title>cosNotification 1.1.14</title>
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>
+ Test suites published.</p>
+ <p>
+ Own Id: OTP-8543 Aux Id:</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Added missing trailing bracket to define in hrl-file.</p>
+ <p>Own Id: OTP-8489 Aux Id:</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
<section>
<title>cosNotification 1.1.14</title>
<section>
@@ -64,15 +104,15 @@
<list type="bulleted">
<item>
<p>Removed superfluous VT in the documentation.</p>
- <p>Own id: OTP-8353 Aux Id:</p>
+ <p>Own Id: OTP-8353 Aux Id:</p>
</item>
<item>
<p>Removed superfluous backslash in the documentation.</p>
- <p>Own id: OTP-8354 Aux Id:</p>
+ <p>Own Id: OTP-8354 Aux Id:</p>
</item>
<item>
<p>The documentation EIX file was not generated.</p>
- <p>Own id: OTP-8355 Aux Id:</p>
+ <p>Own Id: OTP-8355 Aux Id:</p>
</item>
</list>
</section>
@@ -104,7 +144,7 @@
<item>
<p>Obsolete guards, e.g. record vs is_record, has been changed
to avoid compiler warnings.</p>
- <p>Own id: OTP-7987</p>
+ <p>Own Id: OTP-7987</p>
</item>
</list>
</section>
@@ -118,7 +158,7 @@
<list type="bulleted">
<item>
<p>Updated file headers.</p>
- <p>Own id: OTP-7837 Aux Id:</p>
+ <p>Own Id: OTP-7837 Aux Id:</p>
</item>
</list>
</section>
@@ -132,7 +172,7 @@
<list type="bulleted">
<item>
<p>Documentation source included in open source releases.</p>
- <p>Own id: OTP-7595 Aux Id:</p>
+ <p>Own Id: OTP-7595 Aux Id:</p>
</item>
</list>
</section>
@@ -147,7 +187,7 @@
<item>
<p>The CosNotification proxy objects ignored the gcLimit option, instead
the gcTime value was used.</p>
- <p>Own id: OTP-7553 Aux Id:</p>
+ <p>Own Id: OTP-7553 Aux Id:</p>
</item>
</list>
</section>
@@ -161,7 +201,7 @@
<list type="bulleted">
<item>
<p>Updated file headers.</p>
- <p>Own id: OTP-7011</p>
+ <p>Own Id: OTP-7011</p>
</item>
</list>
</section>
@@ -175,7 +215,7 @@
<list type="bulleted">
<item>
<p>The documentation source has been converted from SGML to XML.</p>
- <p>Own id: OTP-6754</p>
+ <p>Own Id: OTP-6754</p>
</item>
</list>
</section>
@@ -189,7 +229,7 @@
<list type="bulleted">
<item>
<p>Minor Makefile changes.</p>
- <p>Own id: OTP-6701</p>
+ <p>Own Id: OTP-6701</p>
</item>
</list>
</section>
@@ -203,7 +243,7 @@
<list type="bulleted">
<item>
<p>Removed some unused code.</p>
- <p>Own id: OTP-6527</p>
+ <p>Own Id: OTP-6527</p>
</item>
</list>
</section>
@@ -219,7 +259,7 @@
<p>A user can now define the QoS EventReliability to be
Persistent. Note, this is only a lightweight version
and events will be lost if a proxy is terminated.</p>
- <p>Own id: OTP-5923</p>
+ <p>Own Id: OTP-5923</p>
</item>
</list>
</section>
@@ -235,7 +275,7 @@
<p>Possible to configure cosNotification not to type check,
by invoking corba_object:is_a/2, supplied IOR:s. When
a type check fails, the feedback has been improved.</p>
- <p>Own id: OTP-5823 Aux Id: seq10143</p>
+ <p>Own Id: OTP-5823 Aux Id: seq10143</p>
</item>
</list>
</section>
@@ -249,7 +289,7 @@
<list type="bulleted">
<item>
<p>The app-file contained duplicated modules.</p>
- <p>Own id: OTP-4976</p>
+ <p>Own Id: OTP-4976</p>
</item>
</list>
</section>
@@ -268,7 +308,7 @@
Interface Repository. It is necessary to re-compile all IDL-files
and use COS-applications, including Orber, compiled with
IC-4.2.</p>
- <p>Own id: OTP-4576</p>
+ <p>Own Id: OTP-4576</p>
</item>
</list>
</section>
diff --git a/lib/cosNotification/src/cosNotification_Filter.erl b/lib/cosNotification/src/cosNotification_Filter.erl
index dd3b5beb93..7201f7d6e2 100644
--- a/lib/cosNotification/src/cosNotification_Filter.erl
+++ b/lib/cosNotification/src/cosNotification_Filter.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2010. 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
@@ -877,9 +877,9 @@ check_wildcard(Types, Which, WC, Domain, Type) ->
end,
check_types(Types, Which, NewWC).
-%% Change '*' to '.*', see regexp:parse/2 documentation.
+%% Change '*' to '.*', see re:compile/1 documentation.
convert_wildcard([], Acc) ->
- case regexp:parse(lists:reverse(Acc)) of
+ case re:compile(lists:reverse(Acc)) of
{ok, Expr} ->
Expr;
_ ->
@@ -900,37 +900,37 @@ match_types(_, _, []) ->
false;
match_types(Domain, Type, [{domain, WCDomain, Type}|T]) ->
L=length(Domain),
- case catch regexp:matches(Domain, WCDomain) of
- {match, []} ->
+ case catch re:run(Domain, WCDomain) of
+ nomatch ->
match_types(Domain, Type, T);
- {match, [{1, L}]} ->
+ {match, [{0, L}]} ->
true;
_->
match_types(Domain, Type, T)
end;
match_types(Domain, Type, [{type, Domain, WCType}|T]) ->
L=length(Type),
- case catch regexp:matches(Type, WCType) of
- {match, []} ->
+ case catch re:run(Type, WCType) of
+ nomatch ->
match_types(Domain, Type, T);
- {match, [{1, L}]} ->
+ {match, [{0, L}]} ->
true;
_->
match_types(Domain, Type, T)
end;
match_types(Domain, Type, [{both, WCDomain, WCType}|T]) ->
L1=length(Domain),
- case catch regexp:matches(Domain, WCDomain) of
- {match, []} ->
+ case catch re:run(Domain, WCDomain) of
+ nomatch ->
match_types(Domain, Type, T);
- {match, [{1, L1}]} ->
+ {match, [{0, L1}]} ->
L2=length(Type),
- case catch regexp:matches(Type, WCType) of
- {match, []} ->
+ case catch re:run(Type, WCType) of
+ nomatch ->
match_types(Domain, Type, T);
- {match, [{1, L2}]} ->
+ {match, [{0, L2}]} ->
true;
- _->
+ _ ->
match_types(Domain, Type, T)
end;
_->
diff --git a/lib/cosNotification/vsn.mk b/lib/cosNotification/vsn.mk
index c03f0ef161..cfd5948dfc 100644
--- a/lib/cosNotification/vsn.mk
+++ b/lib/cosNotification/vsn.mk
@@ -1 +1 @@
-COSNOTIFICATION_VSN = 1.1.14
+COSNOTIFICATION_VSN = 1.1.15
diff --git a/lib/dialyzer/RELEASE_NOTES b/lib/dialyzer/RELEASE_NOTES
index a05b3ac52b..08f274a996 100644
--- a/lib/dialyzer/RELEASE_NOTES
+++ b/lib/dialyzer/RELEASE_NOTES
@@ -5,6 +5,13 @@
Version 2.x.x (in Erlang/OTP R14B01)
------------------------------------
+ - Fixed pretty rare infinite loop when refining the types of an SCC whose
+ functions all returned none() (thanks to Stavros Aronis).
+ - Fixed pretty rare crash when taking the infimum of two tuple_sets.
+ - Fixed pretty rare crash when using parameterized types containing unbound
+ variables (thanks to Nicolas Trangez for reporting it).
+ - Deeper unfolding of recursive types (thanks to Maria Christakis).
+ - Fixed some incomplete and erroneous specs in modules of kernel and stdlib.
- Fixed problems in the handling of remote types in records used as types
(thanks to Nico Kruber for the report and to Maria Christakis for the fix).
- Fixed handling of nested opaque types (thanks to Thorsten Schuett for
diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml
index 1ec2ce830a..29308885fd 100644
--- a/lib/dialyzer/doc/src/dialyzer.xml
+++ b/lib/dialyzer/doc/src/dialyzer.xml
@@ -101,9 +101,9 @@
<tag><c><![CDATA[--output_plt file]]></c></tag>
<item>Store the PLT at the specified location after building it.</item>
<tag><c><![CDATA[--plt plt]]></c></tag>
- <item>Use the specified plt as the initial persistent lookup table.</item>
+ <item>Use the specified PLT as the initial persistent lookup table.</item>
<tag><c><![CDATA[-Wwarn]]></c></tag>
- <item>a family of option which selectively turn on/off warnings.
+ <item>a family of options which selectively turn on/off warnings.
(for help on the names of warnings use <c><![CDATA[dialyzer -Whelp]]></c>)</item>
<tag><c><![CDATA[--shell]]></c></tag>
<item>do not disable the Erlang shell while running the GUI</item>
@@ -158,9 +158,16 @@
<tag><c><![CDATA[-Wno_match]]></c></tag>
<item>Suppress warnings for patterns that are unused or cannot
match.</item>
+ <tag><c><![CDATA[-Wno_opaque]]></c></tag>
+ <item>Suppress warnings for violations of opaqueness of data types.</item>
<tag><c><![CDATA[-Werror_handling]]></c>***</tag>
<item>Include warnings for functions that only return by means of an
exception.</item>
+ <tag><c><![CDATA[-Wrace_conditions]]></c>***</tag>
+ <item>Include warnings for possible race conditions.</item>
+ <tag><c><![CDATA[-Wbehaviours]]></c>***</tag>
+ <item>Include warnings about behaviour callbacks which drift from the
+ published recommended interfaces.</item>
<tag><c><![CDATA[-Wunmatched_returns]]></c>***</tag>
<item>Include warnings for function calls which ignore a structured return
value or do not match against one of many possible return value(s).</item>
@@ -215,8 +222,11 @@ WarnOpts : no_return
| no_improper_lists
| no_fun_app
| no_match
+ | no_opaque
| no_fail_call
| error_handling
+ | race_conditions
+ | behaviours
| unmatched_returns
| overspecs
| underspecs
diff --git a/lib/dialyzer/src/dialyzer_races.erl b/lib/dialyzer/src/dialyzer_races.erl
index ec8d613b96..ee9d5e88a3 100644
--- a/lib/dialyzer/src/dialyzer_races.erl
+++ b/lib/dialyzer/src/dialyzer_races.erl
@@ -118,7 +118,7 @@
var_map :: dict()}).
-type case_tags() :: 'beg_case' | #beg_clause{} | #end_clause{} | #end_case{}.
--type code() :: [#dep_call{} | #warn_call{} | #fun_call{} |
+-type code() :: [#dep_call{} | #fun_call{} | #warn_call{} |
#curr_fun{} | #let_tag{} | case_tags() | race_tag()].
-type table_var() :: label() | ?no_label.
@@ -479,23 +479,11 @@ fixup_race_forward(CurrFun, CurrFunLabel, Calls, Code, RaceList,
_Other ->
{RaceList, [], NestingLevel, false}
end;
- #dep_call{call_name = ets_lookup, args = DepCallArgs} ->
+ #dep_call{call_name = ets_lookup} ->
case RaceWarnTag of
?WARN_ETS_LOOKUP_INSERT ->
- [Tab, Names, _, _] = DepCallArgs,
- case compare_var_list(Tab,
- dialyzer_callgraph:get_public_tables(Callgraph),
- RaceVarMap)
- orelse
- length(Names --
- dialyzer_callgraph:get_named_tables(Callgraph)) <
- length(Names) of
- true ->
- {[Head#dep_call{var_map = RaceVarMap}|RaceList],
- [], NestingLevel, false};
- false ->
- {RaceList, [], NestingLevel, false}
- end;
+ {[Head#dep_call{var_map = RaceVarMap}|RaceList],
+ [], NestingLevel, false};
_Other ->
{RaceList, [], NestingLevel, false}
end;
@@ -517,23 +505,11 @@ fixup_race_forward(CurrFun, CurrFunLabel, Calls, Code, RaceList,
_Other ->
{RaceList, [], NestingLevel, false}
end;
- #warn_call{call_name = ets_insert, args = WarnCallArgs} ->
+ #warn_call{call_name = ets_insert} ->
case RaceWarnTag of
?WARN_ETS_LOOKUP_INSERT ->
- [Tab, Names, _, _] = WarnCallArgs,
- case compare_var_list(Tab,
- dialyzer_callgraph:get_public_tables(Callgraph),
- RaceVarMap)
- orelse
- length(Names --
- dialyzer_callgraph:get_named_tables(Callgraph)) <
- length(Names) of
- true ->
- {[Head#warn_call{var_map = RaceVarMap}|RaceList],
- [], NestingLevel, false};
- false ->
- {RaceList, [], NestingLevel, false}
- end;
+ {[Head#warn_call{var_map = RaceVarMap}|RaceList],
+ [], NestingLevel, false};
_Other ->
{RaceList, [], NestingLevel, false}
end;
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
index 8e379463ad..ff89802599 100644
--- a/lib/erl_interface/doc/src/notes.xml
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -30,6 +30,20 @@
</header>
<p>This document describes the changes made to the Erl_interface application.</p>
+<section><title>Erl_Interface 3.7.1.1</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The <c>erl_interface</c> tracelevel for erlang messages was incorrect. This has now been fixed.
+ </p>
+ <p>
+ Own Id: OTP-8874</p>
+ </item>
+ </list>
+ </section>
+
+</section>
<section><title>Erl_Interface 3.7.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/erl_interface/src/connect/eirecv.c b/lib/erl_interface/src/connect/eirecv.c
index 51fc32d65c..7d72ddeeae 100644
--- a/lib/erl_interface/src/connect/eirecv.c
+++ b/lib/erl_interface/src/connect/eirecv.c
@@ -107,7 +107,7 @@ ei_recv_internal (int fd,
switch (msg->msgtype) {
case ERL_SEND: /* { SEND, Cookie, ToPid } */
- if (ei_tracelevel > 0) show_this_msg = 1;
+ if (ei_tracelevel >= 4) show_this_msg = 1;
if (ei_decode_atom(header,&index,msg->cookie)
|| ei_decode_pid(header,&index,&msg->to))
{
@@ -118,7 +118,7 @@ ei_recv_internal (int fd,
break;
case ERL_REG_SEND: /* { REG_SEND, From, Cookie, ToName } */
- if (ei_tracelevel > 0) show_this_msg = 1;
+ if (ei_tracelevel >= 4) show_this_msg = 1;
if (ei_decode_pid(header,&index,&msg->from)
|| ei_decode_atom(header,&index,msg->cookie)
|| ei_decode_atom(header,&index,msg->toname))
@@ -133,7 +133,7 @@ ei_recv_internal (int fd,
case ERL_LINK: /* { LINK, From, To } */
case ERL_UNLINK: /* { UNLINK, From, To } */
case ERL_GROUP_LEADER: /* { GROUP_LEADER, From, To } */
- if (ei_tracelevel > 1) show_this_msg = 1;
+ if (ei_tracelevel >= 4) show_this_msg = 1;
if (ei_decode_pid(header,&index,&msg->from)
|| ei_decode_pid(header,&index,&msg->to))
{
@@ -145,7 +145,7 @@ ei_recv_internal (int fd,
case ERL_EXIT: /* { EXIT, From, To, Reason } */
case ERL_EXIT2: /* { EXIT2, From, To, Reason } */
- if (ei_tracelevel > 1) show_this_msg = 1;
+ if (ei_tracelevel >= 4) show_this_msg = 1;
if (ei_decode_pid(header,&index,&msg->from)
|| ei_decode_pid(header,&index,&msg->to))
{
@@ -156,7 +156,7 @@ ei_recv_internal (int fd,
break;
case ERL_SEND_TT: /* { SEND_TT, Cookie, ToPid, TraceToken } */
- if (ei_tracelevel > 0) show_this_msg = 1;
+ if (ei_tracelevel >= 4) show_this_msg = 1;
if (ei_decode_atom(header,&index,msg->cookie)
|| ei_decode_pid(header,&index,&msg->to)
|| ei_decode_trace(header,&index,&msg->token))
@@ -169,7 +169,7 @@ ei_recv_internal (int fd,
break;
case ERL_REG_SEND_TT: /* { REG_SEND_TT, From, Cookie, ToName, TraceToken } */
- if (ei_tracelevel > 0) show_this_msg = 1;
+ if (ei_tracelevel >= 4) show_this_msg = 1;
if (ei_decode_pid(header,&index,&msg->from)
|| ei_decode_atom(header,&index,msg->cookie)
|| ei_decode_atom(header,&index,msg->toname)
@@ -184,7 +184,7 @@ ei_recv_internal (int fd,
case ERL_EXIT_TT: /* { EXIT_TT, From, To, TraceToken, Reason } */
case ERL_EXIT2_TT: /* { EXIT2_TT, From, To, TraceToken, Reason } */
- if (ei_tracelevel > 1) show_this_msg = 1;
+ if (ei_tracelevel >= 4) show_this_msg = 1;
if (ei_decode_pid(header,&index,&msg->from)
|| ei_decode_pid(header,&index,&msg->to)
|| ei_decode_trace(header,&index,&msg->token))
@@ -197,7 +197,7 @@ ei_recv_internal (int fd,
break;
case ERL_NODE_LINK: /* { NODE_LINK } */
- if (ei_tracelevel > 1) show_this_msg = 1;
+ if (ei_tracelevel >= 4) show_this_msg = 1;
break;
default:
diff --git a/lib/erl_interface/src/connect/send.c b/lib/erl_interface/src/connect/send.c
index cd832db4ea..57e32903cf 100644
--- a/lib/erl_interface/src/connect/send.c
+++ b/lib/erl_interface/src/connect/send.c
@@ -87,8 +87,7 @@ int ei_send_encoded_tmo(int fd, const erlang_pid *to,
put8(s, ERL_PASS_THROUGH); /* 1 */
/*** sum: 1070 */
- /* FIXME incorrect level */
- if (ei_tracelevel > 0)
+ if (ei_tracelevel >= 4)
ei_show_sendmsg(stderr,header,msg);
#ifdef HAVE_WRITEV
diff --git a/lib/erl_interface/src/connect/send_exit.c b/lib/erl_interface/src/connect/send_exit.c
index 098797c96d..d4e6605a2c 100644
--- a/lib/erl_interface/src/connect/send_exit.c
+++ b/lib/erl_interface/src/connect/send_exit.c
@@ -88,8 +88,7 @@ int ei_send_exit_tmo(int fd, const erlang_pid *from, const erlang_pid *to,
put32be(s, index - 4); /* 4 */
put8(s, ERL_PASS_THROUGH); /* 1 */
/*** sum: len + 1080 */
- /* FIXME incorrect level */
- if (ei_tracelevel > 1)
+ if (ei_tracelevel >= 4)
ei_show_sendmsg(stderr,msgbuf,NULL);
ei_write_fill_t(fd,msgbuf,index,ms);
diff --git a/lib/erl_interface/src/connect/send_reg.c b/lib/erl_interface/src/connect/send_reg.c
index 8f0e40309c..779b1b8359 100644
--- a/lib/erl_interface/src/connect/send_reg.c
+++ b/lib/erl_interface/src/connect/send_reg.c
@@ -82,8 +82,7 @@ int ei_send_reg_encoded_tmo(int fd, const erlang_pid *from,
put32be(s, index + msglen - 4); /* 4 */
put8(s, ERL_PASS_THROUGH); /* 1 */
/*** sum: 1336 */
- /* FIXME incorrect level.... */
- if (ei_tracelevel > 0)
+ if (ei_tracelevel >= 4)
ei_show_sendmsg(stderr,header,msg);
#ifdef HAVE_WRITEV
diff --git a/lib/erl_interface/src/epmd/epmd_publish.c b/lib/erl_interface/src/epmd/epmd_publish.c
index a9b8727747..d45fe644c0 100644
--- a/lib/erl_interface/src/epmd/epmd_publish.c
+++ b/lib/erl_interface/src/epmd/epmd_publish.c
@@ -69,6 +69,12 @@ static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms)
int n;
int res, creation;
+ if (len > sizeof(buf)-2)
+ {
+ erl_errno = ERANGE;
+ return -1;
+ }
+
s = buf;
put16be(s,len);
diff --git a/lib/erl_interface/src/epmd/epmd_unpublish.c b/lib/erl_interface/src/epmd/epmd_unpublish.c
index 08662fe1ec..495cbab44c 100644
--- a/lib/erl_interface/src/epmd/epmd_unpublish.c
+++ b/lib/erl_interface/src/epmd/epmd_unpublish.c
@@ -59,6 +59,11 @@ int ei_unpublish_tmo(const char *alive, unsigned ms)
int len = 1 + strlen(alive);
int fd, res;
+ if (len > sizeof(buf)-3) {
+ erl_errno = ERANGE;
+ return -1;
+ }
+
put16be(s,len);
put8(s,EI_EPMD_STOP_REQ);
strcpy(s, alive);
diff --git a/lib/erl_interface/src/misc/ei_format.c b/lib/erl_interface/src/misc/ei_format.c
index 08235d0ebe..b35421d4b2 100644
--- a/lib/erl_interface/src/misc/ei_format.c
+++ b/lib/erl_interface/src/misc/ei_format.c
@@ -106,6 +106,8 @@ static int eiformat(const char** fmt, union arg** args, ei_x_buff* x)
default:
if (isdigit((int)*p))
res = pdigit(&p, x);
+ else if ((*p == '-' || *p == '+') && isdigit((int)*(p+1)))
+ res = pdigit(&p, x);
else if (islower((int)*p))
res = patom(&p, x);
else
@@ -149,6 +151,8 @@ static int pdigit(const char** fmt, ei_x_buff* x)
double d;
long l;
+ if (**fmt == '-' || **fmt == '+')
+ (*fmt)++;
for (;;) {
c = *(*fmt)++;
if (isdigit((int)c))
diff --git a/lib/erl_interface/src/prog/erl_call.c b/lib/erl_interface/src/prog/erl_call.c
index 448de9aa23..33ff6da7c9 100644
--- a/lib/erl_interface/src/prog/erl_call.c
+++ b/lib/erl_interface/src/prog/erl_call.c
@@ -118,7 +118,6 @@ static void usage_arg(const char *progname, const char *switchname);
static void usage_error(const char *progname, const char *switchname);
static void usage(const char *progname);
static int get_module(char **mbuf, char **mname);
-static struct hostent* get_hostent(char *host);
static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags);
static int read_stdin(char **buf);
static void split_apply_string(char *str, char **mod,
@@ -367,8 +366,8 @@ int erl_call(int argc, char **argv)
* Expand name to a real name (may be ip-address)
*/
/* FIXME better error string */
- if ((hp = get_hostent(host)) == 0) {
- fprintf(stderr,"erl_call: can't get_hostent(%s)\n", host);
+ if ((hp = ei_gethostbyname(host)) == 0) {
+ fprintf(stderr,"erl_call: can't ei_gethostbyname(%s)\n", host);
exit(1);
}
/* If shortnames, cut off the name at first '.' */
@@ -604,32 +603,6 @@ int erl_call(int argc, char **argv)
*
***************************************************************************/
-/*
- * Get host entry (by address or name)
- */
-/* FIXME: will fail on names like '2fun4you'. */
-static struct hostent* get_hostent(char *host)
-{
- if (isdigit((int)*host)) {
- struct in_addr ip_addr;
- int b1, b2, b3, b4;
- long addr;
-
- /* FIXME: Use inet_aton() (or inet_pton() and get v6 for free). */
- if (sscanf(host, "%d.%d.%d.%d", &b1, &b2, &b3, &b4) != 4) {
- return NULL;
- }
- addr = inet_addr(host);
- ip_addr.s_addr = htonl(addr);
-
- return ei_gethostbyaddr((char *)&ip_addr,sizeof(struct in_addr), AF_INET);
- }
-
- return ei_gethostbyname(host);
-} /* get_hostent */
-
-
-
/*
* This function does only return on success.
diff --git a/lib/erl_interface/src/registry/reg_dump.c b/lib/erl_interface/src/registry/reg_dump.c
index 50a6949177..dfec96b43c 100644
--- a/lib/erl_interface/src/registry/reg_dump.c
+++ b/lib/erl_interface/src/registry/reg_dump.c
@@ -157,7 +157,7 @@ static int mn_send_delete(int fd, erlang_pid *mnesia, const char *key)
int len = strlen(key) + 32; /* 32 is a slight overestimate */
if (len > EISMALLBUF)
- if (!(dbuf = malloc(index)))
+ if (!(dbuf = malloc(len)))
return -1;
msgbuf = (dbuf ? dbuf : sbuf);
@@ -187,7 +187,7 @@ static int mn_send_write(int fd, erlang_pid *mnesia, const char *key, ei_reg_obj
int len = 32 + keylen + obj->size;
if (len > EISMALLBUF)
- if (!(dbuf = malloc(index)))
+ if (!(dbuf = malloc(len)))
return -1;
msgbuf = (dbuf ? dbuf : sbuf);
diff --git a/lib/erl_interface/src/registry/reg_restore.c b/lib/erl_interface/src/registry/reg_restore.c
index 27918d2364..aeb33c784a 100644
--- a/lib/erl_interface/src/registry/reg_restore.c
+++ b/lib/erl_interface/src/registry/reg_restore.c
@@ -266,7 +266,7 @@ int ei_reg_restore(int fd, ei_reg *reg, const char *mntab)
/* make sure receive buffer can handle largest expected message */
len = maxkey + maxobj + 512;
if (len > EISMALLBUF)
- if (!(dbuf = malloc(index))) {
+ if (!(dbuf = malloc(len))) {
ei_send_exit(fd,&self,&mnesia,"cannot allocate space for incoming data");
return -1;
}
diff --git a/lib/erl_interface/test/ei_format_SUITE.erl b/lib/erl_interface/test/ei_format_SUITE.erl
index 7871f07ae9..cbe9fa52d7 100644
--- a/lib/erl_interface/test/ei_format_SUITE.erl
+++ b/lib/erl_interface/test/ei_format_SUITE.erl
@@ -155,7 +155,7 @@ format_wo_ver(suite) -> [];
format_wo_ver(Config) when is_list(Config) ->
?line P = runner:start(?format_wo_ver),
- ?line {term, [{a, "b"}, {c, 10}]} = get_term(P),
+ ?line {term, [-1, 2, {a, "b"}, {c, 10}]} = get_term(P),
?line runner:recv_eot(P),
ok.
diff --git a/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c b/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c
index a969ded3dc..ecdce402f5 100644
--- a/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c
+++ b/lib/erl_interface/test/ei_format_SUITE_data/ei_format_test.c
@@ -176,7 +176,7 @@ TESTCASE(format_wo_ver) {
ei_x_buff x;
ei_x_new (&x);
- ei_x_format(&x, "[{~a,~s},{~a,~i}]", "a", "b", "c", 10);
+ ei_x_format(&x, "[-1, +2, {~a,~s},{~a,~i}]", "a", "b", "c", 10);
send_bin_term(&x);
free(x.buff);
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index c642cc5002..6c664959a3 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1 +1 @@
-EI_VSN = 3.7.1
+EI_VSN = 3.7.1.1
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 9bc56c99ff..1ed85af172 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -29,7 +29,7 @@
%% In late 2008, Manouk Manoukian and Kostis Sagonas added support for
%% opaque types to the structure-based representation of types.
%% During February and March 2009, Kostis Sagonas significantly
-%% cleaned up the type representation added spec declarations.
+%% cleaned up the type representation and added spec declarations.
%%
%% ======================================================================
@@ -714,12 +714,13 @@ t_solve_remote_type(#remote{mod = RemMod, name = Name, args = Args} = RemType,
case lookup_type(Name, RemDict) of
{type, {_Mod, Type, ArgNames}} when ArgsLen =:= length(ArgNames) ->
{NewType, NewCycle, NewRR} =
- case unfold(RemType, C) of
+ case can_unfold_more(RemType, C) of
true ->
List = lists:zip(ArgNames, Args),
TmpVarDict = dict:from_list(List),
{t_from_form(Type, RemDict, TmpVarDict), [RemType|C], []};
- false -> {t_any(), C, [RemType]}
+ false ->
+ {t_any(), C, [RemType]}
end,
{RT, RR} = t_solve_remote(NewType, ET, R, NewCycle),
RetRR = NewRR ++ RR,
@@ -733,9 +734,11 @@ t_solve_remote_type(#remote{mod = RemMod, name = Name, args = Args} = RemType,
List = lists:zip(ArgNames, Args),
TmpVarDict = dict:from_list(List),
{Rep, NewCycle, NewRR} =
- case unfold(RemType, C) of
- true -> {t_from_form(Type, RemDict, TmpVarDict), [RemType|C], []};
- false -> {t_any(), C, [RemType]}
+ case can_unfold_more(RemType, C) of
+ true ->
+ {t_from_form(Type, RemDict, TmpVarDict), [RemType|C], []};
+ false ->
+ {t_any(), C, [RemType]}
end,
{NewRep, RR} = t_solve_remote(Rep, ET, R, NewCycle),
RetRR = NewRR ++ RR,
@@ -2124,7 +2127,8 @@ t_elements(?identifier(IDs)) ->
t_elements(?list(_, _, _) = T) -> [T];
t_elements(?number(_, _) = T) ->
case T of
- ?number(?any, ?unknown_qual) -> [T];
+ ?number(?any, ?unknown_qual) ->
+ [?float, ?integer(?any)];
?float -> [T];
?integer(?any) -> [T];
?int_range(_, _) -> [T];
@@ -2171,10 +2175,10 @@ t_inf(?var(_), T, _Mode) -> subst_all_vars_to_any(T);
t_inf(T, ?var(_), _Mode) -> subst_all_vars_to_any(T);
t_inf(?any, T, _Mode) -> subst_all_vars_to_any(T);
t_inf(T, ?any, _Mode) -> subst_all_vars_to_any(T);
-t_inf(?unit, _, _Mode) -> ?unit;
-t_inf(_, ?unit, _Mode) -> ?unit;
t_inf(?none, _, _Mode) -> ?none;
t_inf(_, ?none, _Mode) -> ?none;
+t_inf(?unit, _, _Mode) -> ?unit; % ?unit cases should appear below ?none
+t_inf(_, ?unit, _Mode) -> ?unit;
t_inf(T, T, _Mode) -> subst_all_vars_to_any(T);
t_inf(?atom(Set1), ?atom(Set2), _) ->
case set_intersection(Set1, Set2) of
@@ -2383,14 +2387,16 @@ inf_tuple_sets(L1, L2, Mode) ->
List -> ?tuple_set(List)
end.
-inf_tuple_sets([{Arity, Tuples1}|Left1], [{Arity, Tuples2}|Left2], Acc, Mode) ->
+inf_tuple_sets([{Arity, Tuples1}|Ts1], [{Arity, Tuples2}|Ts2], Acc, Mode) ->
case inf_tuples_in_sets(Tuples1, Tuples2, Mode) of
- [] -> inf_tuple_sets(Left1, Left2, Acc, Mode);
- NewTuples -> inf_tuple_sets(Left1, Left2, [{Arity, NewTuples}|Acc], Mode)
+ [] -> inf_tuple_sets(Ts1, Ts2, Acc, Mode);
+ [?tuple_set([{Arity, NewTuples}])] ->
+ inf_tuple_sets(Ts1, Ts2, [{Arity, NewTuples}|Acc], Mode);
+ NewTuples -> inf_tuple_sets(Ts1, Ts2, [{Arity, NewTuples}|Acc], Mode)
end;
-inf_tuple_sets(L1 = [{Arity1, _}|Left1], L2 = [{Arity2, _}|Left2], Acc, Mode) ->
- if Arity1 < Arity2 -> inf_tuple_sets(Left1, L2, Acc, Mode);
- Arity1 > Arity2 -> inf_tuple_sets(L1, Left2, Acc, Mode)
+inf_tuple_sets([{Arity1, _}|Ts1] = L1, [{Arity2, _}|Ts2] = L2, Acc, Mode) ->
+ if Arity1 < Arity2 -> inf_tuple_sets(Ts1, L2, Acc, Mode);
+ Arity1 > Arity2 -> inf_tuple_sets(L1, Ts2, Acc, Mode)
end;
inf_tuple_sets([], _, Acc, _Mode) -> lists:reverse(Acc);
inf_tuple_sets(_, [], Acc, _Mode) -> lists:reverse(Acc).
@@ -2406,17 +2412,17 @@ inf_tuples_in_sets(L1, [?tuple(Elements2, _, ?any)], Mode) ->
inf_tuples_in_sets(L1, L2, Mode) ->
inf_tuples_in_sets(L1, L2, [], Mode).
-inf_tuples_in_sets([?tuple(Elements1, Arity, Tag)|Left1],
- [?tuple(Elements2, Arity, Tag)|Left2], Acc, Mode) ->
+inf_tuples_in_sets([?tuple(Elements1, Arity, Tag)|Ts1],
+ [?tuple(Elements2, Arity, Tag)|Ts2], Acc, Mode) ->
case t_inf_lists_strict(Elements1, Elements2, Mode) of
- bottom -> inf_tuples_in_sets(Left1, Left2, Acc, Mode);
- NewElements ->
- inf_tuples_in_sets(Left1, Left2, [?tuple(NewElements, Arity, Tag)|Acc], Mode)
+ bottom -> inf_tuples_in_sets(Ts1, Ts2, Acc, Mode);
+ NewElements ->
+ inf_tuples_in_sets(Ts1, Ts2, [?tuple(NewElements, Arity, Tag)|Acc], Mode)
end;
-inf_tuples_in_sets([?tuple(_, _, Tag1)|Left1] = L1,
- [?tuple(_, _, Tag2)|Left2] = L2, Acc, Mode) ->
- if Tag1 < Tag2 -> inf_tuples_in_sets(Left1, L2, Acc, Mode);
- Tag1 > Tag2 -> inf_tuples_in_sets(L1, Left2, Acc, Mode)
+inf_tuples_in_sets([?tuple(_, _, Tag1)|Ts1] = L1,
+ [?tuple(_, _, Tag2)|Ts2] = L2, Acc, Mode) ->
+ if Tag1 < Tag2 -> inf_tuples_in_sets(Ts1, L2, Acc, Mode);
+ Tag1 > Tag2 -> inf_tuples_in_sets(L1, Ts2, Acc, Mode)
end;
inf_tuples_in_sets([], _, Acc, _Mode) -> lists:reverse(Acc);
inf_tuples_in_sets(_, [], Acc, _Mode) -> lists:reverse(Acc).
@@ -2763,7 +2769,9 @@ t_subtract_list(T, []) ->
-spec t_subtract(erl_type(), erl_type()) -> erl_type().
t_subtract(_, ?any) -> ?none;
+t_subtract(_, ?var(_)) -> ?none;
t_subtract(?any, _) -> ?any;
+t_subtract(?var(_) = T, _) -> T;
t_subtract(T, ?unit) -> T;
t_subtract(?unit, _) -> ?unit;
t_subtract(?none, _) -> ?none;
@@ -2791,13 +2799,13 @@ t_subtract(?opaque(Set1), ?opaque(Set2)) ->
Set -> ?opaque(Set)
end;
t_subtract(?matchstate(Pres1, Slots1), ?matchstate(Pres2, _Slots2)) ->
- Pres = t_subtract(Pres1,Pres2),
+ Pres = t_subtract(Pres1, Pres2),
case t_is_none(Pres) of
true -> ?none;
- false -> ?matchstate(Pres,Slots1)
+ false -> ?matchstate(Pres, Slots1)
end;
-t_subtract(?matchstate(Present,Slots),_) ->
- ?matchstate(Present,Slots);
+t_subtract(?matchstate(Present, Slots), _) ->
+ ?matchstate(Present, Slots);
t_subtract(?nil, ?nil) ->
?none;
t_subtract(?nil, ?nonempty_list(_, _)) ->
@@ -2919,7 +2927,7 @@ t_subtract(T, ?product(_)) ->
T;
t_subtract(?union(U1), ?union(U2)) ->
subtract_union(U1, U2);
-t_subtract(T1, T2) ->
+t_subtract(T1, T2) ->
?union(U1) = force_union(T1),
?union(U2) = force_union(T2),
subtract_union(U1, U2).
@@ -3634,7 +3642,7 @@ t_from_form({type, _L, union, Args}, TypeNames, InOpaque, RecDict, VarDict) ->
t_from_form({type, _L, Name, Args}, TypeNames, InOpaque, RecDict, VarDict) ->
case lookup_type(Name, RecDict) of
{type, {_Module, Type, ArgNames}} when length(Args) =:= length(ArgNames) ->
- case unfold({type, Name}, TypeNames) of
+ case can_unfold_more({type, Name}, TypeNames) of
true ->
List = lists:zipwith(
fun(ArgName, ArgType) ->
@@ -3655,7 +3663,7 @@ t_from_form({type, _L, Name, Args}, TypeNames, InOpaque, RecDict, VarDict) ->
end;
{opaque, {Module, Type, ArgNames}} when length(Args) =:= length(ArgNames) ->
{Rep, Rret} =
- case unfold({opaque, Name}, TypeNames) of
+ case can_unfold_more({opaque, Name}, TypeNames) of
true ->
List = lists:zipwith(
fun(ArgName, ArgType) ->
@@ -3698,7 +3706,7 @@ t_from_form({opaque, _L, Name, {Mod, Args, Rep}}, _TypeNames, _InOpaque,
record_from_form({atom, _, Name}, ModFields, TypeNames, InOpaque, RecDict,
VarDict) ->
- case unfold({record, Name}, TypeNames) of
+ case can_unfold_more({record, Name}, TypeNames) of
true ->
case lookup_record(Name, RecDict) of
{ok, DeclFields} ->
@@ -3716,7 +3724,7 @@ record_from_form({atom, _, Name}, ModFields, TypeNames, InOpaque, RecDict,
RecDict, VarDict),
case GetModRec of
{error, FieldName} ->
- throw({error, io_lib:format("Illegal declaration of ~w#{~w}\n",
+ throw({error, io_lib:format("Illegal declaration of #~w{~w}\n",
[Name, FieldName])});
{ok, NewFields} ->
{t_tuple(
@@ -3724,8 +3732,7 @@ record_from_form({atom, _, Name}, ModFields, TypeNames, InOpaque, RecDict,
R1 ++ R2}
end;
error ->
- throw({error, erlang:error(io_lib:format("Unknown record #~w{}\n",
- [Name]))})
+ throw({error, io_lib:format("Unknown record #~w{}\n", [Name])})
end;
false -> {t_any(), []}
end.
@@ -3946,8 +3953,9 @@ lookup_type(Name, RecDict) ->
type_is_defined(TypeOrOpaque, Name, RecDict) ->
dict:is_key({TypeOrOpaque, Name}, RecDict).
-unfold(TypeName, TypeNames) ->
- not lists:member(TypeName, TypeNames).
+can_unfold_more(TypeName, TypeNames) ->
+ Fun = fun(E, Acc) -> case E of TypeName -> Acc + 1; _ -> Acc end end,
+ lists:foldl(Fun, 0, TypeNames) < ?REC_TYPE_LIMIT.
%% -----------------------------------
%% Set
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index 1f8be4040e..920c94d85c 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -369,6 +369,10 @@ trans_fun([{bif,BifName,{f,Lbl},[_] = Args,Reg}|Instructions], Env) ->
trans_fun([{bif,BifName,{f,Lbl},[_,_] = Args,Reg}|Instructions], Env) ->
{BifInsts,Env1} = trans_bif(2,BifName,Lbl,Args,Reg,Env),
[hipe_icode:mk_comment({bif2,BifName})|BifInsts] ++ trans_fun(Instructions,Env1);
+%%--- bif3 ---
+trans_fun([{bif,BifName,{f,Lbl},[_,_,_] = Args,Reg}|Instructions], Env) ->
+ {BifInsts,Env1} = trans_bif(3,BifName,Lbl,Args,Reg,Env),
+ [hipe_icode:mk_comment({bif3,BifName})|BifInsts] ++ trans_fun(Instructions,Env1);
%%--- allocate
trans_fun([{allocate,StackSlots,_}|Instructions], Env) ->
trans_allocate(StackSlots) ++ trans_fun(Instructions,Env);
diff --git a/lib/hipe/icode/hipe_icode_callgraph.erl b/lib/hipe/icode/hipe_icode_callgraph.erl
index 95182fc002..3dba8e1071 100644
--- a/lib/hipe/icode/hipe_icode_callgraph.erl
+++ b/lib/hipe/icode/hipe_icode_callgraph.erl
@@ -25,8 +25,6 @@
%% in hipe_icode_type.erl.
%%
%% Created : 7 Jun 2004 by Tobias Lindahl <[email protected]>
-%%
-%% $Id$
%%-----------------------------------------------------------------------
-module(hipe_icode_callgraph).
@@ -48,7 +46,7 @@
-type mfa_icode() :: {mfa(), #icode{}}.
--record(icode_callgraph, {codedict :: dict(), ordered_sccs :: [[atom()]]}).
+-record(icode_callgraph, {codedict :: dict(), ordered_sccs :: [[mfa()]]}).
%%------------------------------------------------------------------------
%% Exported functions
@@ -78,7 +76,7 @@ construct_callgraph(List) ->
to_list(#icode_callgraph{codedict = Dict, ordered_sccs = SCCs}) ->
FlatList = lists:flatten(SCCs),
- [{Mod, dict:fetch(Mod, Dict)} || Mod <- FlatList].
+ [{MFA, dict:fetch(MFA, Dict)} || MFA <- FlatList].
%%------------------------------------------------------------------------
diff --git a/lib/hipe/icode/hipe_icode_range.erl b/lib/hipe/icode/hipe_icode_range.erl
index bcc857acf4..c7e6a451af 100644
--- a/lib/hipe/icode/hipe_icode_range.erl
+++ b/lib/hipe/icode/hipe_icode_range.erl
@@ -843,7 +843,7 @@ compare_with_integer(N, OldVarRange) ->
%%== Ranges ==================================================================
--spec pp_ann(#ann{} | erl_types:erl_type()) -> [string()].
+-spec pp_ann(#ann{} | erl_types:erl_type()) -> string().
pp_ann(#ann{range=#range{range=R, other=false}}) ->
pp_range(R);
@@ -1365,7 +1365,7 @@ range_bnot(Range) ->
Minus_one = range_init({-1,-1}, false),
range_add(range_mult(Range, Minus_one), Minus_one).
--spec width(range_rep() | integer()) -> 'pos_inf' | non_neg_integer().
+-spec width(range_rep() | inf_integer()) -> 'pos_inf' | non_neg_integer().
width({Min, Max}) -> inf_max([width(Min), width(Max)]);
width(pos_inf) -> pos_inf;
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index c80fb6a0a2..570e4d9d17 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2001-2010. 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
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%% ====================================================================
@@ -25,7 +25,6 @@
%% Purpose :
%% Notes :
%% History : * 1998-01-28 Erik Johansson ([email protected]): Created.
-%% CVS : $Id$
%% ====================================================================
%% @doc This is the direct interface to the HiPE compiler.
%%
@@ -506,7 +505,7 @@ compile(Name, File, Opts0) ->
run_compiler(Name, DisasmFun, IcodeFun, NewOpts)
end.
--spec compile_core(mod(), _, compile_file(), comp_options()) ->
+-spec compile_core(mod(), cerl:c_module(), compile_file(), comp_options()) ->
{'ok', compile_ret()} | {'error', term()}.
compile_core(Name, Core0, File, Opts) ->
@@ -535,7 +534,7 @@ compile_core(Name, Core0, File, Opts) ->
%%
%% @see compile/3
--spec compile(mod(), _, compile_file(), comp_options()) ->
+-spec compile(mod(), cerl:c_module() | [], compile_file(), comp_options()) ->
{'ok', compile_ret()} | {'error', term()}.
compile(Name, [], File, Opts) ->
@@ -790,7 +789,7 @@ finalize_fun(MfaIcodeList, Exports, Opts) ->
FalseVal when (FalseVal =:= undefined) orelse (FalseVal =:= false) ->
[finalize_fun_sequential(MFAIcode, Opts, #comp_servers{})
|| {_MFA, _Icode} = MFAIcode <- MfaIcodeList];
- TrueVal when (TrueVal =:= true) or (TrueVal =:= debug) ->
+ TrueVal when (TrueVal =:= true) orelse (TrueVal =:= debug) ->
finalize_fun_concurrent(MfaIcodeList, Exports, Opts)
end.
@@ -939,6 +938,8 @@ assemble(CompiledCode, Closures, Exports, Options) ->
hipe_sparc_assemble:assemble(CompiledCode, Closures, Exports, Options);
powerpc ->
hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
+ ppc64 ->
+ hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
arm ->
hipe_arm_assemble:assemble(CompiledCode, Closures, Exports, Options);
x86 ->
@@ -1048,7 +1049,7 @@ post(Res, Icode, Options) ->
%% --------------------------------------------------------------------
%% @doc Returns the current HiPE version as a string().
--spec version() -> string().
+-spec version() -> nonempty_string().
version() ->
?VERSION_STRING().
@@ -1390,6 +1391,8 @@ o1_opts() ->
Common;
powerpc ->
Common;
+ ppc64 ->
+ Common;
arm ->
Common -- [inline_fp]; % Pointless optimising for absent hardware
x86 ->
@@ -1411,6 +1414,8 @@ o2_opts() ->
Common;
powerpc ->
Common;
+ ppc64 ->
+ Common;
arm ->
Common;
x86 ->
@@ -1429,6 +1434,8 @@ o3_opts() ->
Common;
powerpc ->
Common;
+ ppc64 ->
+ Common;
arm ->
Common;
x86 ->
diff --git a/lib/hipe/main/hipe_main.erl b/lib/hipe/main/hipe_main.erl
index fe9bc83fd2..e81642fb33 100644
--- a/lib/hipe/main/hipe_main.erl
+++ b/lib/hipe/main/hipe_main.erl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2001-2010. 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
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%% @doc This is the HiPE compiler's main "loop".
@@ -102,7 +102,7 @@ compile_icode(MFA, LinearIcode0, Options, Servers, DebugState) ->
?opt_start_timer("Icode"),
LinearIcode1 = icode_no_comment(LinearIcode0, Options),
IcodeCfg0 = icode_linear_to_cfg(LinearIcode1, Options),
- %%hipe_icode_cfg:pp(IcodeCfg1),
+ %% hipe_icode_cfg:pp(IcodeCfg0),
IcodeCfg1 = icode_handle_exceptions(IcodeCfg0, MFA, Options),
IcodeCfg3 = icode_inline_bifs(IcodeCfg1, Options),
pp(IcodeCfg3, MFA, icode, pp_icode, Options, Servers),
diff --git a/lib/hipe/rtl/hipe_rtl.erl b/lib/hipe/rtl/hipe_rtl.erl
index ef06b2abf8..d93f423f0c 100644
--- a/lib/hipe/rtl/hipe_rtl.erl
+++ b/lib/hipe/rtl/hipe_rtl.erl
@@ -354,6 +354,8 @@
phi_arglist_update/2,
phi_redirect_pred/3]).
+-export_type([alub_cond/0]).
+
%%
%% RTL
%%
@@ -590,6 +592,9 @@ branch_pred(#branch{p=P}) -> P.
%% alub
%%
+-type alub_cond() :: 'eq' | 'ne' | 'ge' | 'geu' | 'gt' | 'gtu' | 'le'
+ | 'leu' | 'lt' | 'ltu' | 'overflow' | 'not_overflow'.
+
mk_alub(Dst, Src1, Op, Src2, Cond, True, False) ->
mk_alub(Dst, Src1, Op, Src2, Cond, True, False, 0.5).
mk_alub(Dst, Src1, Op, Src2, Cond, True, False, P) ->
diff --git a/lib/hipe/rtl/hipe_rtl_arith.inc b/lib/hipe/rtl/hipe_rtl_arith.inc
index 31fedd927e..9e80fa5e13 100644
--- a/lib/hipe/rtl/hipe_rtl_arith.inc
+++ b/lib/hipe/rtl/hipe_rtl_arith.inc
@@ -119,7 +119,8 @@ eval_alu(Op, Arg1, Arg2) ->
%% there are cases where we can evaluate a subset of the bits, but can
%% not do a full eval-alub call (eg. a + 0 gives no carry)
%%
--spec eval_cond_bits(atom(), boolean(), boolean(), boolean(), boolean()) -> boolean().
+-spec eval_cond_bits(hipe_rtl:alub_cond(), boolean(),
+ boolean(), boolean(), boolean()) -> boolean().
eval_cond_bits(Cond, N, Z, V, C) ->
case Cond of
@@ -146,9 +147,7 @@ eval_cond_bits(Cond, N, Z, V, C) ->
'overflow' ->
V;
'not_overflow' ->
- not V;
- _ ->
- ?EXIT({'condition code not handled',Cond})
+ not V
end.
eval_alub(Op, Cond, Arg1, Arg2) ->
diff --git a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
index 76c0a88933..64d723d15d 100644
--- a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
+++ b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
@@ -93,8 +93,6 @@
-include("../ssa/hipe_ssa_const_prop.inc").
-type bool_lattice() :: 'true' | 'false' | 'top' | 'bottom'.
--type conditional() :: 'eq' | 'ne' | 'ge' | 'geu' | 'gt' | 'gtu' | 'le'
- | 'leu' | 'lt' | 'ltu' | 'overflow' | 'not_overflow'.
%%-----------------------------------------------------------------------------
%% Procedure : visit_expression/2
@@ -400,7 +398,7 @@ maybe_top_or_bottom([top | Rest], _) -> maybe_top_or_bottom(Rest, top);
maybe_top_or_bottom([bottom | _], _) -> bottom;
maybe_top_or_bottom([_ | Rest], TB) -> maybe_top_or_bottom(Rest, TB).
--spec partial_eval_branch(conditional(), bool_lattice(), bool_lattice(),
+-spec partial_eval_branch(hipe_rtl:alub_cond(), bool_lattice(), bool_lattice(),
bool_lattice() | 0, bool_lattice() | 0) ->
bool_lattice().
partial_eval_branch(Cond, N0, Z0, V0, C0) ->
@@ -441,14 +439,14 @@ visit_alub(Inst, Env) ->
hipe_rtl:alub_false_label(Inst)];
top -> [];
_ ->
- %if the partial branch cannot be evaluated we must execute the
- % instruction at runtime.
+ %% if the partial branch cannot be evaluated we must execute the
+ %% instruction at runtime.
case partial_eval_branch(hipe_rtl:alub_cond(Inst), N, Z, C, V) of
bottom -> [hipe_rtl:alub_true_label(Inst),
hipe_rtl:alub_false_label(Inst)];
top -> [];
- true -> [hipe_rtl:alub_true_label(Inst) ];
- false -> [hipe_rtl:alub_false_label(Inst) ]
+ true -> [hipe_rtl:alub_true_label(Inst)];
+ false -> [hipe_rtl:alub_false_label(Inst)]
end
end,
{[], NewSSA, NewEnv} = set_to(hipe_rtl:alub_dst(Inst), NewVal, Env),
@@ -944,8 +942,8 @@ update_branch(Inst, Env) ->
%% some small helpers.
alub_to_move(Inst, Res, Lab) ->
- [ hipe_rtl:mk_move(hipe_rtl:alub_dst(Inst), Res),
- hipe_rtl:mk_goto(Lab) ].
+ [hipe_rtl:mk_move(hipe_rtl:alub_dst(Inst), Res),
+ hipe_rtl:mk_goto(Lab)].
make_alub_subst_list(bottom, _, Tail) -> Tail;
make_alub_subst_list(top, Src, _) ->
@@ -970,13 +968,13 @@ update_alub(Inst, Env) ->
%% move and the branch. We can however replace variable with constants:
S1 = make_alub_subst_list(Val1, Src1, []),
S2 = make_alub_subst_list(Val2, Src2, S1),
- [ hipe_rtl:subst_uses(S2, Inst) ];
- _ -> % we know where we will be going, let's find out what Dst should be.
- % knowing where we are going means that at most one of the values is
- % bottom, hence we can replace the alu-instr with a move.
- % remember, a = b + 0 can give us enough info to know what jump to
- % do without knowing the value of a. (I wonder if this will ever
- % actualy happen ;)
+ [hipe_rtl:subst_uses(S2, Inst)];
+ _ -> %% we know where we will be going, let's find out what Dst should be.
+ %% knowing where we are going means that at most one of the values is
+ %% bottom, hence we can replace the alu-instr with a move.
+ %% remember, a = b + 0 can give us enough info to know what jump to
+ %% do without knowing the value of a. (I wonder if this will ever
+ %% actualy happen ;)
Res = case ResVal of
bottom -> % something nonconstant.
if (Val1 =:= bottom) -> Src1;
@@ -985,11 +983,12 @@ update_alub(Inst, Env) ->
_ -> hipe_rtl:mk_imm(ResVal)
end,
case CondRes of
- top -> io:format("oops. something VERY bad: ~w ~w V1 & 2 ~w ~w\n",
- [Inst, {ResVal, N, Z, C, V} , Val1, Val2]),
- [Inst ];
- true -> alub_to_move(Inst, Res, hipe_rtl:alub_true_label(Inst));
- false -> alub_to_move(Inst, Res, hipe_rtl:alub_false_label(Inst))
+ top ->
+ io:format("oops. something VERY bad: ~w ~w V1 & 2 ~w ~w\n",
+ [Inst, {ResVal, N, Z, C, V} , Val1, Val2]),
+ [Inst];
+ true -> alub_to_move(Inst, Res, hipe_rtl:alub_true_label(Inst));
+ false -> alub_to_move(Inst, Res, hipe_rtl:alub_false_label(Inst))
end
end.
@@ -1050,7 +1049,7 @@ update_phi(Instruction, Environment) ->
%%-----------------------------------------------------------------------------
-%% make sure that all precoloured rgisters are taken out of the equation.
+%% make sure that all precoloured registers are taken out of the equation.
lookup_lattice_value(X, Environment) ->
case hipe_rtl_arch:is_precoloured(X) or hipe_rtl:is_const_label(X) of
true ->
diff --git a/lib/hipe/tools/hipe_tool.erl b/lib/hipe/tools/hipe_tool.erl
index a1bd79895d..990805ceca 100644
--- a/lib/hipe/tools/hipe_tool.erl
+++ b/lib/hipe/tools/hipe_tool.erl
@@ -56,9 +56,9 @@
-record(state, {win_created = false :: boolean(),
mindex = 0 :: integer(),
- mod :: module(),
+ mod :: atom(),
funs = [] :: [fa()],
- mods = [] :: [module()],
+ mods = [] :: [atom()],
options = [o2] :: comp_options(),
compiling = false :: 'false' | pid()
}).
@@ -291,8 +291,7 @@ update_code_listbox(State) ->
integer_to_list(length(Mods))++")"),
catch gs:config(code_listbox, [{data, Mods},
{items, Mods},
- {selection, 0}
- ]),
+ {selection, 0}]),
update_module_box(State#state{mods = Mods}, 0, Mods, "")
end
end.
@@ -367,7 +366,7 @@ update_text(Lab, Text) ->
%% @doc Returns a list of all loaded modules.
%%---------------------------------------------------------------------
--spec mods() -> [module()].
+-spec mods() -> [atom()].
mods() ->
[Mod || {Mod,_File} <- code:all_loaded()].
@@ -382,25 +381,26 @@ funs(Mod) ->
native_code(Mod) ->
Mod:module_info(native_addresses).
--spec mfas(module(), [fa()]) -> [mfa()].
+-spec mfas(atom(), [fa()]) -> [mfa()].
mfas(Mod, Funs) ->
[{Mod,F,A} || {F,A} <- Funs].
--spec fun_names(module(), [fa()], [fa_address()], boolean()) -> string().
+-spec fun_names(atom(), [fa()], [fa_address()], boolean()) -> [string()].
fun_names(M, Funs, NativeCode, Prof) ->
- [list_to_atom(atom_to_list(F) ++ "/" ++ integer_to_list(A) ++
- (case in_native(F, A, NativeCode) of
- true -> " [native] ";
- false -> ""
- end)
- ++
- if Prof ->
- (catch integer_to_list(hipe_bifs:call_count_get({M,F,A})));
- true -> ""
- end) ||
- {F,A} <- Funs].
+ [atom_to_list(F) ++ "/" ++ integer_to_list(A)
+ ++
+ (case in_native(F, A, NativeCode) of
+ true -> " [native] ";
+ false -> ""
+ end)
+ ++
+ if Prof ->
+ (catch integer_to_list(hipe_bifs:call_count_get({M,F,A})));
+ true -> ""
+ end
+ || {F,A} <- Funs].
-spec in_native(atom(), arity(), [fa_address()]) -> boolean().
@@ -461,7 +461,7 @@ get_compile(Info) ->
false -> []
end.
--spec is_profiled(module()) -> boolean().
+-spec is_profiled(atom()) -> boolean().
is_profiled(Mod) ->
case hipe_bifs:call_count_get({Mod,module_info,0}) of
@@ -478,7 +478,7 @@ compile(State) ->
P = spawn(fun() -> c(Parent, State#state.mod, State#state.options) end),
State#state{compiling = P}.
--spec c(pid(), module(), comp_options()) -> 'ok'.
+-spec c(pid(), atom(), comp_options()) -> 'ok'.
c(Parent, Mod, Options) ->
Res = hipe:c(Mod, Options),
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 2ae230152c..a22c0a8346 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -220,6 +220,69 @@ fe80::204:acff:fe17:bf38
<p>Returns the local hostname. Will never fail.</p>
</desc>
</func>
+
+ <func>
+ <name>getifaddrs() -> {ok,Iflist} | {error,posix}</name>
+ <fsummary>Return a list of interfaces and their addresses</fsummary>
+ <type>
+ <v>Iflist = {Ifname,[Ifopt]}</v>
+ <v>Ifname = string()</v>
+ <v>Ifopt = {flag,[Flag]} | {addr,Addr} | {netmask,Netmask}
+ | {broadaddr,Broadaddr} | {dstaddr,Dstaddr}
+ | {hwaddr,Hwaddr}</v>
+ <v>Flag = up | broadcast | loopback | pointtopoint
+ | running | multicast</v>
+ <v>Addr = Netmask = Broadadddr = Dstaddr = ip_address()</v>
+ <v>Hwaddr = [byte()]</v>
+ </type>
+ </func>
+ <desc>
+ <p>
+ Returns a list of 2-tuples containing interface names and the
+ interface's addresses. <c>Ifname</c> is a Unicode string.
+ <c>Hwaddr</c> is hardware dependent, e.g on Ethernet interfaces
+ it is the 6-byte Ethernet address (MAC address (EUI-48 address)).
+ </p>
+ <p>
+ The <c>{addr,Addr}</c>, <c>{netmask,_}</c> and <c>{broadaddr,_}</c>
+ tuples are repeated in the result list iff the interface has multiple
+ addresses. If you come across an interface that has
+ multiple <c>{flag,_}</c> or <c>{hwaddr,_}</c> tuples you have
+ a really strange interface or possibly a bug in this function.
+ The <c>{flag,_}</c> tuple is mandatory, all other optional.
+ </p>
+ <p>
+ Do not rely too much on the order of <c>Flag</c> atoms or
+ <c>Ifopt</c> tuples. There are some rules, though:
+ <list>
+ <item>
+ Immediately after <c>{addr,_}</c> follows <c>{netmask,_}</c>
+ </item>
+ <item>
+ Immediately thereafter follows <c>{broadaddr,_}</c> if
+ the <c>broadcast</c> flag is <em>not</em> set and the
+ <c>pointtopoint</c>flag <em>is</em> set.
+ </item>
+ <item>
+ Any <c>{netmask,_}</c>, <c>{broadaddr,_}</c> or
+ <c>{dstaddr,_}</c> tuples that follow an <c>{addr,_}</c>
+ tuple concerns that address.
+ </item>
+ </list>
+ </p>
+ <p>
+ The <c>{hwaddr,_}</c> tuple is not returned on Solaris since the
+ hardware address historically belongs to the link layer and only
+ the superuser can read such addresses.
+ </p>
+ <p>
+ On Windows, the data is fetched from quite different OS API
+ functions, so the <c>Netmask</c> and <c>Broadaddr</c>
+ values may be calculated, just as some <c>Flag</c> values.
+ You have been warned. Report flagrant bugs.
+ </p>
+ </desc>
+
<func>
<name>getopts(Socket, Options) -> {ok, OptionValues} | {error, posix()}</name>
<fsummary>Get one or more options for a socket</fsummary>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 9859183390..edd6ea52b0 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -30,6 +30,29 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 2.14.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>In embedded mode, on_load handlers that called
+ <c>code:priv_dir/1</c> or other functions in <c>code</c>
+ would hang the system. Since the <c>crypto</c>
+ application now contains an on_loader handler that calls
+ <c>code:priv_dir/1</c>, including the <c>crypto</c>
+ application in the boot file would prevent the system
+ from starting.</p>
+ <p>Also extended the <c>-init_debug</c> option to print
+ information about on_load handlers being run to
+ facilitate debugging.</p>
+ <p>
+ Own Id: OTP-8902 Aux Id: seq11703 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 2.14.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 93d75321ba..327e0f93f1 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -25,6 +25,7 @@
%% socket
-export([peername/1, sockname/1, port/1, send/2,
setopts/2, getopts/2,
+ getifaddrs/0, getifaddrs/1,
getif/1, getif/0, getiflist/0, getiflist/1,
ifget/3, ifget/2, ifset/3, ifset/2,
getstat/1, getstat/2,
@@ -265,6 +266,17 @@ setopts(Socket, Opts) ->
getopts(Socket, Opts) ->
prim_inet:getopts(Socket, Opts).
+-spec getifaddrs(Socket :: socket()) ->
+ {'ok', [string()]} | {'error', posix()}.
+
+getifaddrs(Socket) ->
+ prim_inet:getifaddrs(Socket).
+
+-spec getifaddrs() -> {'ok', [string()]} | {'error', posix()}.
+
+getifaddrs() ->
+ withsocket(fun(S) -> prim_inet:getifaddrs(S) end).
+
-spec getiflist(Socket :: socket()) ->
{'ok', [string()]} | {'error', posix()}.
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index cf357b7fba..6f1688c6a2 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2010. 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
@@ -82,6 +82,7 @@
-define(INET_REQ_IFGET, 22).
-define(INET_REQ_IFSET, 23).
-define(INET_REQ_SUBSCRIBE, 24).
+-define(INET_REQ_GETIFADDRS, 25).
%% TCP requests
-define(TCP_REQ_ACCEPT, 40).
-define(TCP_REQ_LISTEN, 41).
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index 92ee7b441a..1e07620a3e 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2010. 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
@@ -143,6 +143,13 @@ init(safe) ->
Boot = start_boot_server(),
DiskLog = start_disk_log(),
Pg2 = start_pg2(),
+
+ %% Run the on_load handlers for all modules that have been
+ %% loaded so far. Running them at this point means that
+ %% on_load handlers can safely call kernel processes
+ %% (and in particular call code:priv_dir/1 or code:lib_dir/1).
+ init:run_on_load_handlers(),
+
{ok, {SupFlags, Boot ++ DiskLog ++ Pg2}}.
get_code_args() ->
diff --git a/lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl b/lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl
index a39332f81d..b7fdd4d9ae 100644
--- a/lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl
+++ b/lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl
@@ -3,6 +3,15 @@
-on_load(run_me/0).
run_me() ->
+ %% An onload handler typically calls code:priv_dir/1
+ %% or code:lib_dir/1, so make sure that it works.
+ LibDir = code:lib_dir(on_load_app),
+ PrivDir = code:priv_dir(on_load_app),
+ LibDir = filename:dirname(PrivDir),
+ ModPath = code:which(?MODULE),
+ LibDir = filename:dirname(filename:dirname(ModPath)),
+
+ %% Start a process to remember that the on_load was called.
spawn(fun() ->
register(everything_is_fine, self()),
receive Any ->
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index f4f27933a5..ec05bf99b9 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -27,7 +27,7 @@
ipv4_to_ipv6/1, host_and_addr/1, parse/1, t_gethostnative/1,
gethostnative_parallell/1, cname_loop/1,
gethostnative_soft_restart/1,gethostnative_debug_level/1,getif/1,
- getif_ifr_name_overflow/1,getservbyname_overflow/1]).
+ getif_ifr_name_overflow/1,getservbyname_overflow/1,getifaddrs/1]).
-export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1,
kill_gethost/0, parallell_gethost/0]).
@@ -40,7 +40,7 @@ all(suite) ->
ipv4_to_ipv6, host_and_addr, parse,t_gethostnative,
gethostnative_parallell, cname_loop,
gethostnative_debug_level,gethostnative_soft_restart,
- getif,getif_ifr_name_overflow,getservbyname_overflow].
+ getif,getif_ifr_name_overflow,getservbyname_overflow,getifaddrs].
init_per_testcase(_Func, Config) ->
Dog = test_server:timetrap(test_server:seconds(60)),
@@ -873,6 +873,14 @@ getif(suite) ->
getif(doc) ->
["Tests basic functionality of getiflist, getif, and ifget"];
getif(Config) when is_list(Config) ->
+ ?line case os:type() of
+ {unix,Osname} ->
+ ?line do_getif(Osname);
+ {_,_} ->
+ {skip,"inet:getif/0 probably not supported"}
+ end.
+
+do_getif(Osname) ->
?line {ok,Hostname} = inet:gethostname(),
?line {ok,Address} = inet:getaddr(Hostname, inet),
?line {ok,Loopback} = inet:getaddr("localhost", inet),
@@ -887,7 +895,8 @@ getif(Config) when is_list(Config) ->
end
end, [], Interfaces)),
?line io:format("HWAs = ~p~n", [HWAs]),
- ?line length(HWAs) > 0 orelse ?t:fail(no_HWAs),
+ ?line (Osname =/= sunos)
+ andalso ((length(HWAs) > 0) orelse (?t:fail(no_HWAs))),
?line Addresses =
lists:sort(
lists:foldl(
@@ -906,6 +915,14 @@ getif(Config) when is_list(Config) ->
getif_ifr_name_overflow(doc) ->
"Test long interface names do not overrun buffer";
getif_ifr_name_overflow(Config) when is_list(Config) ->
+ ?line case os:type() of
+ {unix,Osname} ->
+ ?line do_getif_ifr_name_overflow(Osname);
+ {_,_} ->
+ {skip,"inet:ifget/2 probably not supported"}
+ end.
+
+do_getif_ifr_name_overflow(_) ->
%% emulator should not crash
?line {ok,[]} = inet:ifget(lists:duplicate(128, "x"), [addr]),
ok.
@@ -917,6 +934,112 @@ getservbyname_overflow(Config) when is_list(Config) ->
?line {error,einval} = inet:getservbyname(list_to_atom(lists:flatten(lists:duplicate(128, "x"))), tcp),
ok.
+getifaddrs(doc) ->
+ "Test inet:gifaddrs/0";
+getifaddrs(Config) when is_list (Config) ->
+ ?line {ok,IfAddrs} = inet:getifaddrs(),
+ ?line ?t:format("IfAddrs = ~p.~n", [IfAddrs]),
+ ?line
+ case
+ {os:type(),
+ [If ||
+ {If,Opts} <- IfAddrs,
+ lists:keymember(hwaddr, 1, Opts)]} of
+ {{unix,sunos},[]} -> ok;
+ {OT,[]} ->
+ ?t:fail({should_have_hwaddr,OT});
+ _ -> ok
+ end,
+ ?line Addrs =
+ [element(1, A) || A <- ifaddrs(IfAddrs)],
+ ?line ?t:format("Addrs = ~p.~n", [Addrs]),
+ ?line [check_addr(Addr) || Addr <- Addrs],
+ ok.
+
+check_addr(Addr)
+ when tuple_size(Addr) =:= 8,
+ element(1, Addr) band 16#FFC0 =:= 16#FE80 ->
+ ?line ?t:format("Addr: ~p link local; SKIPPED!~n", [Addr]),
+ ok;
+check_addr(Addr) ->
+ ?line ?t:format("Addr: ~p.~n", [Addr]),
+ ?line Ping = "ping",
+ ?line Pong = "pong",
+ ?line {ok,L} = gen_tcp:listen(0, [{ip,Addr},{active,false}]),
+ ?line {ok,P} = inet:port(L),
+ ?line {ok,S1} = gen_tcp:connect(Addr, P, [{active,false}]),
+ ?line {ok,S2} = gen_tcp:accept(L),
+ ?line ok = gen_tcp:send(S2, Ping),
+ ?line {ok,Ping} = gen_tcp:recv(S1, length(Ping)),
+ ?line ok = gen_tcp:send(S1, Pong),
+ ?line ok = gen_tcp:close(S1),
+ ?line {ok,Pong} = gen_tcp:recv(S2, length(Pong)),
+ ?line ok = gen_tcp:close(S2),
+ ?line ok = gen_tcp:close(L),
+ ok.
+
+-record(ifopts, {name,flags,addrs=[],hwaddr}).
+
+ifaddrs([]) -> [];
+ifaddrs([{If,Opts}|IOs]) ->
+ ?line #ifopts{flags=Flags} = Ifopts =
+ check_ifopts(Opts, #ifopts{name=If}),
+ ?line case Flags =/= undefined andalso lists:member(up, Flags) of
+ true ->
+ Ifopts#ifopts.addrs;
+ false ->
+ []
+ end++ifaddrs(IOs).
+
+check_ifopts([], #ifopts{name=If,flags=Flags,addrs=Raddrs}=Ifopts) ->
+ Addrs = lists:reverse(Raddrs),
+ R = Ifopts#ifopts{addrs=Addrs},
+ ?t:format("~p.~n", [R]),
+ %% See how we did...
+ if is_list(Flags) -> ok;
+ true ->
+ ?t:fail({flags_undefined,If})
+ end,
+ case lists:member(broadcast, Flags) of
+ true ->
+ [case A of
+ {_,_,_} -> A;
+ {T,_} when tuple_size(T) =:= 8 -> A;
+ _ ->
+ ?t:fail({broaddr_missing,If,A})
+ end || A <- Addrs];
+ false ->
+ [case A of {_,_} -> A;
+ _ ->
+ ?t:fail({should_have_netmask,If,A})
+ end || A <- Addrs]
+ end,
+ R;
+check_ifopts([{flags,Flags}|Opts], #ifopts{flags=undefined}=Ifopts) ->
+ check_ifopts(Opts, Ifopts#ifopts{flags=Flags});
+check_ifopts([{flags,Fs}|Opts], #ifopts{flags=Flags}=Ifopts) ->
+ case Fs of
+ Flags ->
+ check_ifopts(Opts, Ifopts#ifopts{});
+ _ ->
+ ?t:fail({multiple_flags,Fs,Ifopts})
+ end;
+check_ifopts(
+ [{addr,Addr},{netmask,Netmask},{broadaddr,Broadaddr}|Opts],
+ #ifopts{addrs=Addrs}=Ifopts) ->
+ check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr,Netmask,Broadaddr}|Addrs]});
+check_ifopts(
+ [{addr,Addr},{netmask,Netmask}|Opts],
+ #ifopts{addrs=Addrs}=Ifopts) ->
+ check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr,Netmask}|Addrs]});
+check_ifopts([{addr,Addr}|Opts], #ifopts{addrs=Addrs}=Ifopts) ->
+ check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr}|Addrs]});
+check_ifopts([{hwaddr,Hwaddr}|Opts], #ifopts{hwaddr=undefined}=Ifopts)
+ when is_list(Hwaddr) ->
+ check_ifopts(Opts, Ifopts#ifopts{hwaddr=Hwaddr});
+check_ifopts([{hwaddr,HwAddr}|_], #ifopts{}=Ifopts) ->
+ ?t:fail({multiple_hwaddrs,HwAddr,Ifopts}).
+
%% Works just like lists:member/2, except that any {127,_,_,_} tuple
%% matches any other {127,_,_,_}. We do this to handle Linux systems
%% that use (for instance) 127.0.1.1 as the IP address for the hostname.
diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c
index c9627e9d05..077d78bfe5 100644
--- a/lib/odbc/c_src/odbcserver.c
+++ b/lib/odbc/c_src/odbcserver.c
@@ -108,8 +108,8 @@
#if defined WIN32
#include <winsock2.h>
-/* #include <ws2tcpip.h > When we can support a newer c-compiler*/
#include <windows.h>
+#include <ws2tcpip.h >
#include <fcntl.h>
#include <sql.h>
#include <sqlext.h>
@@ -1599,7 +1599,7 @@ static Boolean decode_params(db_state *state, byte *buffer, int *index, param_ar
break;
case SQL_C_TYPE_TIMESTAMP:
ts = (TIMESTAMP_STRUCT*) param->values.string;
- ei_decode_tuple_header(buffer, index, &val);
+ ei_decode_tuple_header(buffer, index, &size);
ei_decode_long(buffer, index, &val);
ts[j].year = (SQLUSMALLINT)val;
ei_decode_long(buffer, index, &val);
@@ -1727,74 +1727,48 @@ static byte * receive_erlang_port_msg(void)
}
/* ------------- Socket communication functions --------------------------*/
-#define USE_IPV4
-#ifdef UNIX
-#define SOCKET int
-#endif
-#if defined WIN32 || defined USE_IPV4
-/* Currently only an old windows compiler is supported so we do not have ipv6
- capabilities */
+#if defined(WIN32)
static SOCKET connect_to_erlang(const char *port)
-{
- SOCKET sock;
- struct sockaddr_in sin;
-
- sock = socket(AF_INET, SOCK_STREAM, 0);
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_port = htons ((unsigned short)atoi(port));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = inet_addr("127.0.0.1");
-
- if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
- close_socket(sock);
- DO_EXIT(EXIT_SOCKET_CONNECT);
- }
- return sock;
-}
#elif defined(UNIX)
static int connect_to_erlang(const char *port)
+#endif
{
- int sock;
-
- struct addrinfo hints;
- struct addrinfo *erlang_ai, *first;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_UNSPEC; /* PF_INET or PF_INET6 */
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
-
- if (getaddrinfo("localhost", port, &hints, &first) != 0) {
- DO_EXIT(EXIT_FAILURE);
- }
+#if defined(WIN32)
+ SOCKET sock;
+#elif defined(UNIX)
+ int sock;
+#endif
+ struct sockaddr_in sin;
+
+#if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_ADDR) && defined(AF_INET6)
+ struct sockaddr_in6 sin6;
+
+ sock = socket(AF_INET6, SOCK_STREAM, 0);
+
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_port = htons ((unsigned short)atoi(port));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = in6addr_loopback;
- for (erlang_ai = first; erlang_ai; erlang_ai = erlang_ai->ai_next) {
+ if (connect(sock, (struct sockaddr*)&sin6, sizeof(sin6)) == 0) {
+ return sock;
+ }
+ close_socket(sock);
+#endif
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_port = htons ((unsigned short)atoi(port));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- sock = socket(erlang_ai->ai_family, erlang_ai->ai_socktype,
- erlang_ai->ai_protocol);
- if (sock < 0)
- continue;
- if (connect(sock, (struct sockaddr*)erlang_ai->ai_addr,
- erlang_ai->ai_addrlen) < 0) {
- close(sock);
- sock = -1;
- continue;
- } else {
- break;
+ if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
+ close_socket(sock);
+ DO_EXIT(EXIT_SOCKET_CONNECT);
}
- }
- freeaddrinfo(first);
-
- if (sock < 0){
- close_socket(sock);
- DO_EXIT(EXIT_SOCKET_CONNECT);
- }
-
- return sock;
+ return sock;
}
-#endif
#ifdef WIN32
static void close_socket(SOCKET socket)
@@ -2177,9 +2151,9 @@ static void init_param_column(param_array *params, byte *buffer, int *index,
params->type.sql = SQL_TYPE_TIMESTAMP;
params->type.len = sizeof(TIMESTAMP_STRUCT);
params->type.c = SQL_C_TYPE_TIMESTAMP;
- params->type.col_size = (SQLUINTEGER)19;//;sizeof(TIMESTAMP_STRUCT);
+ params->type.col_size = (SQLUINTEGER)COL_SQL_TIMESTAMP;
params->values.string =
- (TIMESTAMP_STRUCT *)safe_malloc(num_param_values * params->type.len);
+ (byte *)safe_malloc(num_param_values * params->type.len);
break;
case USER_FLOAT:
params->type.sql = SQL_FLOAT;
diff --git a/lib/odbc/c_src/odbcserver.h b/lib/odbc/c_src/odbcserver.h
index e6d8df1f58..3e2b22ab7d 100644
--- a/lib/odbc/c_src/odbcserver.h
+++ b/lib/odbc/c_src/odbcserver.h
@@ -98,6 +98,7 @@
#define COL_SQL_REAL 7
#define COL_SQL_DOUBLE 15
#define COL_SQL_TINYINT 4
+#define COL_SQL_TIMESTAMP 19
/* Types of parameters given to param_query*/
#define USER_SMALL_INT 1
diff --git a/lib/odbc/configure.in b/lib/odbc/configure.in
index 94e8a214d4..2369e16813 100644
--- a/lib/odbc/configure.in
+++ b/lib/odbc/configure.in
@@ -118,11 +118,18 @@ AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, main, [LIBS="$LIBS -lnsl"]))
dnl Checks for header files.
AC_HEADER_STDC
-AC_CHECK_HEADERS([fcntl.h netdb.h stdlib.h string.h sys/socket.h])
+AC_CHECK_HEADERS([fcntl.h netdb.h stdlib.h string.h sys/socket.h winsock2.h])
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_SIZE_T
+AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_addr], [], [],
+ [#if HAVE_WINSOCK2_H
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+ #else
+ #include <netinet/in.h>
+ #endif])
dnl Checks for library functions.
AC_CHECK_FUNCS([memset socket])
diff --git a/lib/odbc/src/odbc.erl b/lib/odbc/src/odbc.erl
index eb27a471ec..83d9f33102 100644
--- a/lib/odbc/src/odbc.erl
+++ b/lib/odbc/src/odbc.erl
@@ -441,10 +441,12 @@ init(Args) ->
{ok, ListenSocketSup} =
gen_tcp:listen(0, [Inet, binary, {packet, ?LENGTH_INDICATOR_SIZE},
- {active, false}, {nodelay, true}]),
+ {active, false}, {nodelay, true},
+ {ip, loopback}]),
{ok, ListenSocketOdbc} =
gen_tcp:listen(0, [Inet, binary, {packet, ?LENGTH_INDICATOR_SIZE},
- {active, false}, {nodelay, true}]),
+ {active, false}, {nodelay, true},
+ {ip, loopback}]),
%% Start the port program (a c program) that utilizes the odbc driver
case os:find_executable(?SERVERPROG, ?SERVERDIR) of
diff --git a/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl b/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl
index 7792839e22..768653c898 100644
--- a/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl
+++ b/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2010. 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
@@ -536,8 +536,15 @@ lookup(_, _Ctx) ->
receive_msg(Socket, Acc, Timeout) ->
receive
{tcp_closed, Socket} ->
- [_Header, Body] = re:split(Acc,"\r\n\r\n",[{return,list}]),
- Body;
+ case re:split(Acc,"\r\n\r\n",[{return,list}]) of
+ [_Header, Body] ->
+ Body;
+ What ->
+ orber:dbg("[~p] orber_cosnaming_utils:receive_msg();~n"
+ "HTTP server closed the connection before sending a complete reply: ~p.",
+ [?LINE, What], ?DEBUG_LEVEL),
+ corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
+ end;
{tcp, Socket, Response} ->
receive_msg(Socket, Acc ++ Response, Timeout);
{tcp_error, Socket, Reason} ->
diff --git a/lib/orber/doc/src/notes.xml b/lib/orber/doc/src/notes.xml
index 17f7ac8270..6eda16a517 100644
--- a/lib/orber/doc/src/notes.xml
+++ b/lib/orber/doc/src/notes.xml
@@ -32,23 +32,41 @@
<file>notes.xml</file>
</header>
- <section><title>Orber 3.6.17</title>
+ <section>
+ <title>Orber 3.6.18</title>
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>A corbaloc http string could return an EXIT message, instead
+ of a system exception, if the HTTP server closed the socket
+ without returning a complete message. I.e. header and a body
+ containing a stringified IOR.</p>
+ <p>Own Id: OTP-8900 Aux Id: seq11704</p>
+ </item>
+ </list>
+ </section>
+ </section>
- <section><title>Improvements and New Features</title>
- <list>
+ <section>
+ <title>Orber 3.6.17</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
<item>
<p>
- Eliminated warnings for auto-imported BIF clashes.</p>
+ Eliminated warnings for auto-imported BIF clashes.</p>
<p>
- Own Id: OTP-8840</p>
+ Own Id: OTP-8840</p>
</item>
</list>
</section>
+ </section>
-</section>
-
-<section>
+ <section>
<title>Orber 3.6.16</title>
+
<section>
<title>Improvements and New Features</title>
<list type="bulleted">
@@ -56,16 +74,17 @@
<p>
Test suites published.</p>
<p>
- Own Id: OTP-8543 Aux Id:</p>
+ Own Id: OTP-8543O Aux Id:</p>
</item>
</list>
</section>
+
<section>
<title>Fixed Bugs and Malfunctions</title>
<list type="bulleted">
<item>
<p>Added missing trailing bracket to define in hrl-file.</p>
- <p>Own id: OTP-8489 Aux Id:</p>
+ <p>Own Id: OTP-8489 Aux Id:</p>
</item>
</list>
</section>
@@ -104,11 +123,11 @@
<list type="bulleted">
<item>
<p>Removed superfluous VT in the documentation.</p>
- <p>Own id: OTP-8353 Aux Id:</p>
+ <p>Own Id: OTP-8353 Aux Id:</p>
</item>
<item>
<p>Removed superfluous backslash in the documentation.</p>
- <p>Own id: OTP-8354 Aux Id:</p>
+ <p>Own Id: OTP-8354 Aux Id:</p>
</item>
</list>
</section>
@@ -140,7 +159,7 @@
<item>
<p>Obsolete guards, e.g. record vs is_record, has been changed
to avoid compiler warnings.</p>
- <p>Own id: OTP-7987</p>
+ <p>Own Id: OTP-7987</p>
</item>
</list>
</section>
@@ -158,7 +177,7 @@
Naming Service (INS) instead. INS is a part of the OMG
standard specification.</p>
<p>*** POTENTIAL INCOMPATIBILITY ***</p>
- <p>Own id: OTP-7906 Aux Id: seq11243</p>
+ <p>Own Id: OTP-7906 Aux Id: seq11243</p>
</item>
</list>
</section>
@@ -172,7 +191,7 @@
<list type="bulleted">
<item>
<p>Updated file headers.</p>
- <p>Own id: OTP-7837</p>
+ <p>Own Id: OTP-7837</p>
</item>
</list>
</section>
@@ -186,7 +205,7 @@
<list type="bulleted">
<item>
<p>Documentation source included in open source releases.</p>
- <p>Own id: OTP-7595</p>
+ <p>Own Id: OTP-7595</p>
</item>
</list>
</section>
@@ -200,11 +219,11 @@
<list type="bulleted">
<item>
<p>Updated file headers.</p>
- <p>Own id: OTP-7011</p>
+ <p>Own Id: OTP-7011</p>
</item>
<item>
<p>Now compliant with the new behavior of stdlib.</p>
- <p>Own id: OTP-7030 Aux Id: seq10827</p>
+ <p>Own Id: OTP-7030 Aux Id: seq10827</p>
</item>
</list>
</section>
diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk
index 681b82b51b..584a52ab84 100644
--- a/lib/orber/vsn.mk
+++ b/lib/orber/vsn.mk
@@ -1 +1 @@
-ORBER_VSN = 3.6.17
+ORBER_VSN = 3.6.18
diff --git a/lib/parsetools/include/yeccpre.hrl b/lib/parsetools/include/yeccpre.hrl
index 39dea0552d..80a3afbdb6 100644
--- a/lib/parsetools/include/yeccpre.hrl
+++ b/lib/parsetools/include/yeccpre.hrl
@@ -167,7 +167,7 @@ yecctoken2string({char,_,C}) -> io_lib:write_char(C);
yecctoken2string({var,_,V}) -> io_lib:format("~s", [V]);
yecctoken2string({string,_,S}) -> io_lib:write_unicode_string(S);
yecctoken2string({reserved_symbol, _, A}) -> io_lib:write(A);
-yecctoken2string({_Cat, _, Val}) -> io_lib:write(Val);
+yecctoken2string({_Cat, _, Val}) -> io_lib:format("~p",[Val]);
yecctoken2string({dot, _}) -> "'.'";
yecctoken2string({'$end', _}) ->
[];
diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl
index 93949a074a..8153be7e61 100644
--- a/lib/parsetools/test/yecc_SUITE.erl
+++ b/lib/parsetools/test/yecc_SUITE.erl
@@ -46,7 +46,7 @@
bugs/1,
otp_5369/1, otp_6362/1, otp_7945/1, otp_8483/1, otp_8486/1,
improvements/1,
- otp_7292/1, otp_7969/1]).
+ otp_7292/1, otp_7969/1, otp_8919/1]).
% Default timetrap timeout (set in init_per_testcase).
-define(default_timeout, ?t:minutes(1)).
@@ -1541,7 +1541,7 @@ otp_8486(Config) when is_list(Config) ->
ok.
improvements(suite) ->
- [otp_7292, otp_7969].
+ [otp_7292, otp_7969, otp_8919].
otp_7292(doc) ->
"OTP-7292. Header declarations for edoc.";
@@ -1773,6 +1773,14 @@ otp_7969(Config) when is_list(Config) ->
?line {error,{{1,11},erl_parse,_}} = erl_parse:parse_and_scan({F6, []}),
ok.
+otp_8919(doc) ->
+ "OTP-8919. Improve formating of Yecc error messages.";
+otp_8919(suite) -> [];
+otp_8919(Config) when is_list(Config) ->
+ {error,{1,Mod,Mess}} = erl_parse:parse([{cat,1,"hello"}]),
+ "syntax error before: \"hello\"" = lists:flatten(Mod:format_error(Mess)),
+ ok.
+
yeccpre_size() ->
yeccpre_size(default_yeccpre()).
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index c467e24741..c8953c6818 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -295,7 +295,7 @@ is_fixed_dh_cert(#'OTPCertificate'{tbsCertificate =
%%--------------------------------------------------------------------
--spec verify_fun(#'OTPTBSCertificate'{}, {bad_cert, atom()} | {extension, #'Extension'{}}|
+-spec verify_fun(#'OTPCertificate'{}, {bad_cert, atom()} | {extension, #'Extension'{}}|
valid | valid_peer, term(), fun()) -> term().
%%
%% Description: Gives the user application the opportunity handle path
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 950c249e72..9bedd446f4 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -29,8 +29,52 @@
<file>notes.xml</file>
</header>
- <section><title>Ssh 2.0.1</title>
+<section><title>Ssh 2.0.3</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The fix regarding OTP-8849 was not included in the
+ previous version as stated.</p>
+ <p>
+ Own Id: OTP-8918</p>
+ </item>
+ </list>
+ </section>
+</section>
+<section><title>Ssh 2.0.2</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The ssh_system_sup did not catch noproc and shutdown
+ messages.</p>
+ <p>
+ Own Id: OTP-8863</p>
+ </item>
+ <item>
+ <p>
+ In some cases a crash report was generated when a
+ connection was closing down. This was caused by a race
+ condition between two processes.</p>
+ <p>
+ Own Id: OTP-8881 Aux Id: seq11656, seq11648 </p>
+ </item>
+ </list>
+ </section>
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ SSH no longer use deprecated public_key functions.</p>
+ <p>
+ Own Id: OTP-8849</p>
+ </item>
+ </list>
+ </section>
+ </section>
+ <section><title>Ssh 2.0.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
<item>
diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src
index 21f7508555..9c806bcd03 100644
--- a/lib/ssh/src/ssh.appup.src
+++ b/lib/ssh/src/ssh.appup.src
@@ -19,9 +19,13 @@
{"%VSN%",
[
+ {"2.0.2", [{load_module, ssh_file, soft_purge, soft_purge, []}]},
+ {"2.0.1", [{restart_application, ssh}]}
],
[
- ]
+ {"2.0.2", [{load_module, ssh_file, soft_purge, soft_purge, []}]},
+ {"2.0.1", [{restart_application, ssh}]}
+ ]
}.
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index d46002c494..0ba11b0a26 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -705,11 +705,19 @@ generate_event(<<?BYTE(Byte), _/binary>> = Msg, StateName,
Byte == ?SSH_MSG_CHANNEL_REQUEST;
Byte == ?SSH_MSG_CHANNEL_SUCCESS;
Byte == ?SSH_MSG_CHANNEL_FAILURE ->
- ssh_connection_manager:event(Pid, Msg),
- State = generate_event_new_state(State0, EncData),
- next_packet(State),
- {next_state, StateName, State};
+ try
+ ssh_connection_manager:event(Pid, Msg),
+ State = generate_event_new_state(State0, EncData),
+ next_packet(State),
+ {next_state, StateName, State}
+ catch
+ exit:{noproc, _Reason} ->
+ Report = io_lib:format("~p Connection Handler terminated: ~p~n",
+ [self(), Pid]),
+ error_logger:info_report(Report),
+ {stop, normal, State0}
+ end;
generate_event(Msg, StateName, State0, EncData) ->
Event = ssh_bits:decode(Msg),
State = generate_event_new_state(State0, EncData),
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 5572349fe7..13722656db 100755
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -198,12 +198,17 @@ read_public_key_v1(File) ->
%% pem_type("ssh-rsa") -> "RSA".
read_private_key_v2(File, Type) ->
- case catch (public_key:pem_to_der(File)) of
- {ok, [{_, Bin, not_encrypted}]} ->
- decode_private_key_v2(Bin, Type);
- Error -> %% Note we do not handle password encrypted keys at the moment
- {error, Error}
- end.
+ case file:read_file(File) of
+ {ok, PemBin} ->
+ case catch (public_key:pem_decode(PemBin)) of
+ [{_, Bin, not_encrypted}] ->
+ decode_private_key_v2(Bin, Type);
+ Error -> %% Note we do not handle password encrypted keys at the moment
+ {error, Error}
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end.
%% case file:read_file(File) of
%% {ok,Bin} ->
%% case read_pem(binary_to_list(Bin), pem_type(Type)) of
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index f4570b8a48..920baaadef 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -85,7 +85,7 @@ start_subsystem(SystemSup, Options) ->
supervisor:start_child(SystemSup, Spec).
stop_subsystem(SystemSup, SubSys) ->
- case lists:keyfind(SubSys, 2, supervisor:which_children(SystemSup)) of
+ case catch lists:keyfind(SubSys, 2, supervisor:which_children(SystemSup)) of
false ->
{error, not_found};
{Id, _, _, _} ->
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 79fd36cd83..db03168ad9 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,4 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 2.0.1
+SSH_VSN = 2.0.3
APP_VSN = "ssh-$(SSH_VSN)"
+
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 413703deca..511f1e0bb2 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -114,7 +114,7 @@
<p><c>ciphersuite() =
{key_exchange(), cipher(), hash()}</c></p>
- <p><c>key_exchange() = rsa | dhe_dss | dhe_rsa
+ <p><c>key_exchange() = rsa | dhe_dss | dhe_rsa | dh_anon
</c></p>
<p><c>cipher() = rc4_128 | des_cbc | '3des_ede_cbc'
@@ -170,8 +170,13 @@
<tag>{ciphers, ciphers()}</tag>
<item>The cipher suites that should be supported. The function
- <c>ciphers_suites/0</c> can be used to find all available
- ciphers.
+ <c>cipher_suites/0</c> can be used to find all available
+ ciphers. Additionally some anonymous cipher suites ({dh_anon,
+ rc4_128, md5}, {dh_anon, des_cbc, sha}, {dh_anon,
+ '3des_ede_cbc', sha}, {dh_anon, aes_128_cbc, sha}, {dh_anon,
+ aes_256_cbc, sha}) are supported for testing purposes and will
+ only work if explicitly enabled by this option and they are supported/enabled
+ by the peer also.
</item>
<tag>{ssl_imp, ssl_imp()}</tag>
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index ef94750d02..7e5929d708 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -747,7 +747,7 @@ validate_option(depth, Value) when is_integer(Value),
validate_option(cert, Value) when Value == undefined;
is_binary(Value) ->
Value;
-validate_option(certfile, Value) when is_list(Value) ->
+validate_option(certfile, Value) when Value == undefined; is_list(Value) ->
Value;
validate_option(key, undefined) ->
@@ -890,7 +890,7 @@ cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
cipher_suites(Version, Ciphers);
cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- Supported = ssl_cipher:suites(Version),
+ Supported = ssl_cipher:suites(Version) ++ ssl_cipher:anonymous_suites(),
case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of
[] ->
Supported;
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 8230149304..175d589931 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -34,7 +34,7 @@
-export([security_parameters/2, suite_definition/1,
decipher/5, cipher/4,
- suite/1, suites/1,
+ suite/1, suites/1, anonymous_suites/0,
openssl_suite/1, openssl_suite_name/1, filter/2]).
-compile(inline).
@@ -164,22 +164,22 @@ decipher(?AES, HashSz, CipherState, Fragment, Version) ->
block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
HashSz, Fragment, Version) ->
- ?DBG_HEX(Key),
- ?DBG_HEX(IV),
- ?DBG_HEX(Fragment),
- T = Fun(Key, IV, Fragment),
- ?DBG_HEX(T),
- GBC = generic_block_cipher_from_bin(T, HashSz),
- case is_correct_padding(GBC, Version) of
- true ->
- Content = GBC#generic_block_cipher.content,
- Mac = GBC#generic_block_cipher.mac,
- CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)},
- {Content, Mac, CipherState1};
- false ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ try Fun(Key, IV, Fragment) of
+ Text ->
+ GBC = generic_block_cipher_from_bin(Text, HashSz),
+ case is_correct_padding(GBC, Version) of
+ true ->
+ Content = GBC#generic_block_cipher.content,
+ Mac = GBC#generic_block_cipher.mac,
+ CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)},
+ {Content, Mac, CipherState1};
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end
+ catch
+ _:_ ->
+ ?ALERT_REC(?FATAL, ?DECRYPTION_FAILED)
end.
-
%%--------------------------------------------------------------------
-spec suites(tls_version()) -> [cipher_suite()].
%%
@@ -191,6 +191,19 @@ suites({3, N}) when N == 1; N == 2 ->
ssl_tls1:suites().
%%--------------------------------------------------------------------
+-spec anonymous_suites() -> [cipher_suite()].
+%%
+%% Description: Returns a list of the anonymous cipher suites, only supported
+%% if explicitly set by user. Intended only for testing.
+%%--------------------------------------------------------------------
+anonymous_suites() ->
+ [?TLS_DH_anon_WITH_RC4_128_MD5,
+ ?TLS_DH_anon_WITH_DES_CBC_SHA,
+ ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DH_anon_WITH_AES_128_CBC_SHA,
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA].
+
+%%--------------------------------------------------------------------
-spec suite_definition(cipher_suite()) -> erl_cipher_suite().
%%
%% Description: Return erlang cipher suite definition.
@@ -235,7 +248,20 @@ suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA) ->
suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
{dhe_dss, aes_256_cbc, sha};
suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
- {dhe_rsa, aes_256_cbc, sha}.
+ {dhe_rsa, aes_256_cbc, sha};
+
+%%% DH-ANON deprecated by TLS spec and not available
+%%% by default, but good for testing purposes.
+suite_definition(?TLS_DH_anon_WITH_RC4_128_MD5) ->
+ {dh_anon, rc4_128, md5};
+suite_definition(?TLS_DH_anon_WITH_DES_CBC_SHA) ->
+ {dh_anon, des_cbc, sha};
+suite_definition(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) ->
+ {dh_anon, '3des_ede_cbc', sha};
+suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA) ->
+ {dh_anon, aes_128_cbc, sha};
+suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) ->
+ {dh_anon, aes_256_cbc, sha}.
%%--------------------------------------------------------------------
-spec suite(erl_cipher_suite()) -> cipher_suite().
@@ -266,12 +292,12 @@ suite({dhe_rsa, des_cbc, sha}) ->
?TLS_DHE_RSA_WITH_DES_CBC_SHA;
suite({dhe_rsa, '3des_ede_cbc', sha}) ->
?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
-%% suite({dh_anon, rc4_128, md5}) ->
-%% ?TLS_DH_anon_WITH_RC4_128_MD5;
-%% suite({dh_anon, des40_cbc, sha}) ->
-%% ?TLS_DH_anon_WITH_DES_CBC_SHA;
-%% suite({dh_anon, '3des_ede_cbc', sha}) ->
-%% ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
+suite({dh_anon, rc4_128, md5}) ->
+ ?TLS_DH_anon_WITH_RC4_128_MD5;
+suite({dh_anon, des_cbc, sha}) ->
+ ?TLS_DH_anon_WITH_DES_CBC_SHA;
+suite({dh_anon, '3des_ede_cbc', sha}) ->
+ ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
%%% TSL V1.1 AES suites
suite({rsa, aes_128_cbc, sha}) ->
@@ -280,16 +306,16 @@ suite({dhe_dss, aes_128_cbc, sha}) ->
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
suite({dhe_rsa, aes_128_cbc, sha}) ->
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
-%% suite({dh_anon, aes_128_cbc, sha}) ->
-%% ?TLS_DH_anon_WITH_AES_128_CBC_SHA;
+suite({dh_anon, aes_128_cbc, sha}) ->
+ ?TLS_DH_anon_WITH_AES_128_CBC_SHA;
suite({rsa, aes_256_cbc, sha}) ->
?TLS_RSA_WITH_AES_256_CBC_SHA;
suite({dhe_dss, aes_256_cbc, sha}) ->
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
suite({dhe_rsa, aes_256_cbc, sha}) ->
- ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA.
-%% suite({dh_anon, aes_256_cbc, sha}) ->
-%% ?TLS_DH_anon_WITH_AES_256_CBC_SHA.
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+suite({dh_anon, aes_256_cbc, sha}) ->
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA.
%%--------------------------------------------------------------------
-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
@@ -580,5 +606,3 @@ filter_rsa_suites(Use, KeyUse, CipherSuits, RsaSuites) ->
false ->
CipherSuits -- RsaSuites
end.
-
-
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index bd1ba6978a..3a9cada81e 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -374,7 +374,7 @@ hello(#server_hello{cipher_suite = CipherSuite,
case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
{Version, NewId, ConnectionStates} ->
- {KeyAlgorithm, _, _} =
+ {KeyAlgorithm, _, _} =
ssl_cipher:suite_definition(CipherSuite),
PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
@@ -512,7 +512,7 @@ certify(#certificate{} = Cert,
certify(#server_key_exchange{} = KeyExchangeMsg,
#state{role = client, negotiated_version = Version,
key_algorithm = Alg} = State0)
- when Alg == dhe_dss; Alg == dhe_rsa ->
+ when Alg == dhe_dss; Alg == dhe_rsa; Alg == dh_anon ->
case handle_server_key(KeyExchangeMsg, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
@@ -613,25 +613,10 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl
#state{negotiated_version = Version,
diffie_hellman_params = #'DHParameter'{prime = P,
base = G},
- diffie_hellman_keys = {_, ServerDhPrivateKey},
- role = Role,
- session = Session,
- connection_states = ConnectionStates0} = State0) ->
-
- PMpint = crypto:mpint(P),
- GMpint = crypto:mpint(G),
- PremasterSecret = crypto:dh_compute_key(mpint_binary(ClientPublicDhKey),
- ServerDhPrivateKey,
- [PMpint, GMpint]),
-
- case ssl_handshake:master_secret(Version, PremasterSecret,
- ConnectionStates0, Role) of
- {MasterSecret, ConnectionStates} ->
- State1 = State0#state{session =
- Session#session{master_secret
- = MasterSecret},
- connection_states = ConnectionStates},
+ diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
+ case dh_master_secret(crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ #state{} = State1 ->
{Record, State} = next_record(State1),
next_state(cipher, Record, State);
#alert{} = Alert ->
@@ -653,12 +638,10 @@ cipher(#certificate_verify{signature = Signature},
public_key_info = PublicKeyInfo,
negotiated_version = Version,
session = #session{master_secret = MasterSecret},
- key_algorithm = Algorithm,
tls_handshake_hashes = Hashes
} = State0) ->
case ssl_handshake:certificate_verify(Signature, PublicKeyInfo,
- Version, MasterSecret,
- Algorithm, Hashes) of
+ Version, MasterSecret, Hashes) of
valid ->
{Record, State} = next_record(State0),
next_state(cipher, Record, State);
@@ -1058,6 +1041,8 @@ init_certificates(#ssl_options{cacerts = CaCerts,
end,
init_certificates(Cert, CertDbRef, CacheRef, CertFile, Role).
+init_certificates(undefined, CertDbRef, CacheRef, "", _) ->
+ {ok, CertDbRef, CacheRef, undefined};
init_certificates(undefined, CertDbRef, CacheRef, CertFile, client) ->
try
@@ -1068,18 +1053,18 @@ init_certificates(undefined, CertDbRef, CacheRef, CertFile, client) ->
end;
init_certificates(undefined, CertDbRef, CacheRef, CertFile, server) ->
- try
+ try
[OwnCert] = ssl_certificate:file_to_certificats(CertFile),
{ok, CertDbRef, CacheRef, OwnCert}
- catch
- Error:Reason ->
- handle_file_error(?LINE, Error, Reason, CertFile, ecertfile,
- erlang:get_stacktrace())
- end;
+ catch
+ Error:Reason ->
+ handle_file_error(?LINE, Error, Reason, CertFile, ecertfile,
+ erlang:get_stacktrace())
+ end;
init_certificates(Cert, CertDbRef, CacheRef, _, _) ->
{ok, CertDbRef, CacheRef, Cert}.
-init_private_key(undefined, "", _Password, client) ->
+init_private_key(undefined, "", _Password, _Client) ->
undefined;
init_private_key(undefined, KeyFile, Password, _) ->
try
@@ -1182,16 +1167,15 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
negotiated_version = Version,
own_cert = OwnCert,
socket = Socket,
- key_algorithm = KeyAlg,
private_key = PrivateKey,
session = #session{master_secret = MasterSecret},
tls_handshake_hashes = Hashes0} = State) ->
+
case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret,
- Version, KeyAlg,
- PrivateKey, Hashes0) of
+ Version, PrivateKey, Hashes0) of
#certificate_verify{} = Verified ->
{BinVerified, ConnectionStates1, Hashes1} =
- encode_handshake(Verified, KeyAlg, Version,
+ encode_handshake(Verified, Version,
ConnectionStates0, Hashes0),
Transport:send(Socket, BinVerified),
State#state{connection_states = ConnectionStates1,
@@ -1340,15 +1324,17 @@ server_hello_done(#state{transport_cb = Transport,
Transport:send(Socket, BinHelloDone),
State#state{connection_states = NewConnectionStates,
tls_handshake_hashes = NewHashes}.
-
-certify_server(#state{transport_cb = Transport,
- socket = Socket,
- negotiated_version = Version,
- connection_states = ConnectionStates,
- tls_handshake_hashes = Hashes,
- cert_db_ref = CertDbRef,
- own_cert = OwnCert} = State) ->
+certify_server(#state{key_algorithm = dh_anon} = State) ->
+ State;
+
+certify_server(#state{transport_cb = Transport,
+ socket = Socket,
+ negotiated_version = Version,
+ connection_states = ConnectionStates,
+ tls_handshake_hashes = Hashes,
+ cert_db_ref = CertDbRef,
+ own_cert = OwnCert} = State) ->
case ssl_handshake:certificate(OwnCert, CertDbRef, server) of
CertMsg = #certificate{} ->
{BinCertMsg, NewConnectionStates, NewHashes} =
@@ -1373,7 +1359,8 @@ key_exchange(#state{role = server, key_algorithm = Algo,
transport_cb = Transport
} = State)
when Algo == dhe_dss;
- Algo == dhe_rsa ->
+ Algo == dhe_rsa;
+ Algo == dh_anon ->
Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
ConnectionState =
@@ -1392,11 +1379,6 @@ key_exchange(#state{role = server, key_algorithm = Algo,
diffie_hellman_keys = Keys,
tls_handshake_hashes = Hashes1};
-
-%% key_algorithm = dh_anon is not supported. Should be by default disabled
-%% if support is implemented and then we need a key_exchange clause for it
-%% here.
-
key_exchange(#state{role = client,
connection_states = ConnectionStates0,
key_algorithm = rsa,
@@ -1419,7 +1401,8 @@ key_exchange(#state{role = client,
socket = Socket, transport_cb = Transport,
tls_handshake_hashes = Hashes0} = State)
when Algorithm == dhe_dss;
- Algorithm == dhe_rsa ->
+ Algorithm == dhe_rsa;
+ Algorithm == dh_anon ->
Msg = ssl_handshake:key_exchange(client, {dh, DhPubKey}),
{BinMsg, ConnectionStates1, Hashes1} =
encode_handshake(Msg, Version, ConnectionStates0, Hashes0),
@@ -1497,23 +1480,30 @@ save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, abbrev
save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, abbreviated) ->
ssl_record:set_server_verify_data(current_write, Data, ConnectionStates).
+handle_server_key(#server_key_exchange{params =
+ #server_dh_params{dh_p = P,
+ dh_g = G,
+ dh_y = ServerPublicDhKey},
+ signed_params = <<>>},
+ #state{key_algorithm = dh_anon} = State) ->
+ dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
+
handle_server_key(
#server_key_exchange{params =
#server_dh_params{dh_p = P,
dh_g = G,
dh_y = ServerPublicDhKey},
signed_params = Signed},
- #state{session = Session, negotiated_version = Version, role = Role,
- public_key_info = PubKeyInfo,
+ #state{public_key_info = PubKeyInfo,
key_algorithm = KeyAlgo,
- connection_states = ConnectionStates0} = State) ->
+ connection_states = ConnectionStates} = State) ->
PLen = size(P),
GLen = size(G),
YLen = size(ServerPublicDhKey),
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
@@ -1527,29 +1517,11 @@ handle_server_key(
case verify_dh_params(Signed, Hash, PubKeyInfo) of
true ->
- PMpint = mpint_binary(P),
- GMpint = mpint_binary(G),
- Keys = {_, ClientDhPrivateKey} =
- crypto:dh_generate_key([PMpint,GMpint]),
- PremasterSecret =
- crypto:dh_compute_key(mpint_binary(ServerPublicDhKey),
- ClientDhPrivateKey, [PMpint, GMpint]),
- case ssl_handshake:master_secret(Version, PremasterSecret,
- ConnectionStates0, Role) of
- {MasterSecret, ConnectionStates} ->
- State#state{diffie_hellman_keys = Keys,
- session =
- Session#session{master_secret
- = MasterSecret},
- connection_states = ConnectionStates};
- #alert{} = Alert ->
- Alert
- end;
+ dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
false ->
?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)
end.
-
verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) ->
case public_key:decrypt_public(Signed, PubKey,
[{rsa_pad, rsa_pkcs1_padding}]) of
@@ -1561,6 +1533,30 @@ verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) ->
verify_dh_params(Signed, Hash, {?'id-dsa', PublicKey, PublicKeyParams}) ->
public_key:verify(Hash, none, Signed, {PublicKey, PublicKeyParams}).
+dh_master_secret(Prime, Base, PublicDhKey, undefined, State) ->
+ PMpint = mpint_binary(Prime),
+ GMpint = mpint_binary(Base),
+ Keys = {_, PrivateDhKey} =
+ crypto:dh_generate_key([PMpint,GMpint]),
+ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
+
+dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey,
+ #state{session = Session,
+ negotiated_version = Version, role = Role,
+ connection_states = ConnectionStates0} = State) ->
+ PremasterSecret =
+ crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
+ [PMpint, GMpint]),
+ case ssl_handshake:master_secret(Version, PremasterSecret,
+ ConnectionStates0, Role) of
+ {MasterSecret, ConnectionStates} ->
+ State#state{
+ session =
+ Session#session{master_secret = MasterSecret},
+ connection_states = ConnectionStates};
+ #alert{} = Alert ->
+ Alert
+ end.
cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
@@ -1585,13 +1581,9 @@ encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
?DBG_TERM(#change_cipher_spec{}),
ssl_record:encode_change_cipher_spec(Version, ConnectionStates).
-encode_handshake(HandshakeRec, Version, ConnectionStates, Hashes) ->
- encode_handshake(HandshakeRec, null, Version,
- ConnectionStates, Hashes).
-
-encode_handshake(HandshakeRec, SigAlg, Version, ConnectionStates0, Hashes0) ->
+encode_handshake(HandshakeRec, Version, ConnectionStates0, Hashes0) ->
?DBG_TERM(HandshakeRec),
- Frag = ssl_handshake:encode_handshake(HandshakeRec, Version, SigAlg),
+ Frag = ssl_handshake:encode_handshake(HandshakeRec, Version),
Hashes1 = ssl_handshake:update_hashes(Hashes0, Frag),
{E, ConnectionStates1} =
ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
@@ -2179,7 +2171,7 @@ renegotiate(#state{role = server,
negotiated_version = Version,
connection_states = ConnectionStates0} = State0) ->
HelloRequest = ssl_handshake:hello_request(),
- Frag = ssl_handshake:encode_handshake(HelloRequest, Version, null),
+ Frag = ssl_handshake:encode_handshake(HelloRequest, Version),
Hs0 = ssl_handshake:init_hashes(),
{BinMsg, ConnectionStates} =
ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 5b1a510034..f8e5d585e7 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -33,11 +33,11 @@
-export([master_secret/4, client_hello/5, server_hello/4, hello/4,
hello_request/0, certify/6, certificate/3,
- client_certificate_verify/6, certificate_verify/6,
+ client_certificate_verify/5, certificate_verify/5,
certificate_request/2, key_exchange/2, server_key_exchange_hash/2,
finished/4, verify_connection/5, get_tls_handshake/2,
- decode_client_key/3, server_hello_done/0, sig_alg/1,
- encode_handshake/3, init_hashes/0, update_hashes/2,
+ decode_client_key/3, server_hello_done/0,
+ encode_handshake/2, init_hashes/0, update_hashes/2,
decrypt_premaster_secret/2]).
-type tls_handshake() :: #client_hello{} | #server_hello{} |
@@ -237,7 +237,7 @@ certificate(OwnCert, CertDbRef, client) ->
{error, _} ->
%% If no suitable certificate is available, the client
%% SHOULD send a certificate message containing no
- %% certificates. (chapter 7.4.6. rfc 4346)
+ %% certificates. (chapter 7.4.6. RFC 4346)
[]
end,
#certificate{asn1_certificates = Chain};
@@ -252,17 +252,17 @@ certificate(OwnCert, CertDbRef, server) ->
%%--------------------------------------------------------------------
-spec client_certificate_verify(undefined | der_cert(), binary(),
- tls_version(), key_algo(), private_key(),
+ tls_version(), private_key(),
{{binary(), binary()},{binary(), binary()}}) ->
#certificate_verify{} | ignore | #alert{}.
%%
%% Description: Creates a certificate_verify message, called by the client.
%%--------------------------------------------------------------------
-client_certificate_verify(undefined, _, _, _, _, _) ->
+client_certificate_verify(undefined, _, _, _, _) ->
ignore;
-client_certificate_verify(_, _, _, _, undefined, _) ->
+client_certificate_verify(_, _, _, undefined, _) ->
ignore;
-client_certificate_verify(OwnCert, MasterSecret, Version, Algorithm,
+client_certificate_verify(OwnCert, MasterSecret, Version,
PrivateKey, {Hashes0, _}) ->
case public_key:pkix_is_fixed_dh_cert(OwnCert) of
true ->
@@ -270,33 +270,30 @@ client_certificate_verify(OwnCert, MasterSecret, Version, Algorithm,
false ->
Hashes =
calc_certificate_verify(Version, MasterSecret,
- Algorithm, Hashes0),
+ alg_oid(PrivateKey), Hashes0),
Signed = digitally_signed(Hashes, PrivateKey),
#certificate_verify{signature = Signed}
end.
%%--------------------------------------------------------------------
-spec certificate_verify(binary(), public_key_info(), tls_version(),
- binary(), key_algo(),
- {_, {binary(), binary()}}) -> valid | #alert{}.
+ binary(), {_, {binary(), binary()}}) -> valid | #alert{}.
%%
%% Description: Checks that the certificate_verify message is valid.
%%--------------------------------------------------------------------
-certificate_verify(Signature, {_, PublicKey, _}, Version,
- MasterSecret, Algorithm, {_, Hashes0})
- when Algorithm == rsa;
- Algorithm == dhe_rsa ->
+certificate_verify(Signature, {?'rsaEncryption'= Algorithm, PublicKey, _}, Version,
+ MasterSecret, {_, Hashes0}) ->
Hashes = calc_certificate_verify(Version, MasterSecret,
Algorithm, Hashes0),
- case public_key:decrypt_public(Signature, PublicKey,
+ case public_key:decrypt_public(Signature, PublicKey,
[{rsa_pad, rsa_pkcs1_padding}]) of
Hashes ->
valid;
_ ->
?ALERT_REC(?FATAL, ?BAD_CERTIFICATE)
end;
-certificate_verify(Signature, {_, PublicKey, PublicKeyParams}, Version,
- MasterSecret, dhe_dss = Algorithm, {_, Hashes0}) ->
+certificate_verify(Signature, {?'id-dsa' = Algorithm, PublicKey, PublicKeyParams}, Version,
+ MasterSecret, {_, Hashes0}) ->
Hashes = calc_certificate_verify(Version, MasterSecret,
Algorithm, Hashes0),
case public_key:verify(Hashes, none, Signature, {PublicKey, PublicKeyParams}) of
@@ -355,15 +352,22 @@ key_exchange(server, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
YLen = byte_size(PublicKey),
ServerDHParams = #server_dh_params{dh_p = PBin,
dh_g = GBin, dh_y = PublicKey},
- Hash =
- server_key_exchange_hash(KeyAlgo, <<ClientRandom/binary,
- ServerRandom/binary,
- ?UINT16(PLen), PBin/binary,
- ?UINT16(GLen), GBin/binary,
- ?UINT16(YLen), PublicKey/binary>>),
- Signed = digitally_signed(Hash, PrivateKey),
- #server_key_exchange{params = ServerDHParams,
- signed_params = Signed}.
+
+ case KeyAlgo of
+ dh_anon ->
+ #server_key_exchange{params = ServerDHParams,
+ signed_params = <<>>};
+ _ ->
+ Hash =
+ server_key_exchange_hash(KeyAlgo, <<ClientRandom/binary,
+ ServerRandom/binary,
+ ?UINT16(PLen), PBin/binary,
+ ?UINT16(GLen), GBin/binary,
+ ?UINT16(YLen), PublicKey/binary>>),
+ Signed = digitally_signed(Hash, PrivateKey),
+ #server_key_exchange{params = ServerDHParams,
+ signed_params = Signed}
+ end.
%%--------------------------------------------------------------------
-spec master_secret(tls_version(), #session{} | binary(), #connection_states{},
@@ -441,13 +445,12 @@ server_hello_done() ->
#server_hello_done{}.
%%--------------------------------------------------------------------
--spec encode_handshake(tls_handshake(), tls_version(), key_algo()) -> iolist().
+-spec encode_handshake(tls_handshake(), tls_version()) -> iolist().
%%
%% Description: Encode a handshake packet to binary
%%--------------------------------------------------------------------
-encode_handshake(Package, Version, KeyAlg) ->
- SigAlg = sig_alg(KeyAlg),
- {MsgType, Bin} = enc_hs(Package, Version, SigAlg),
+encode_handshake(Package, Version) ->
+ {MsgType, Bin} = enc_hs(Package, Version),
Len = byte_size(Bin),
[MsgType, ?uint24(Len), Bin].
@@ -526,7 +529,7 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) ->
end.
%%--------------------------------------------------------------------
--spec server_key_exchange_hash(rsa | dhe_rsa| dhe_dss, binary()) -> binary().
+-spec server_key_exchange_hash(rsa | dhe_rsa| dhe_dss | dh_anon, binary()) -> binary().
%%
%% Description: Calculate server key exchange hash
@@ -541,21 +544,6 @@ server_key_exchange_hash(dhe_dss, Value) ->
crypto:sha(Value).
%%--------------------------------------------------------------------
--spec sig_alg(atom()) -> integer().
-
-%%
-%% Description: Translate atom representation to enum representation.
-%%--------------------------------------------------------------------
-sig_alg(dh_anon) ->
- ?SIGNATURE_ANONYMOUS;
-sig_alg(Alg) when Alg == dhe_rsa; Alg == rsa ->
- ?SIGNATURE_RSA;
-sig_alg(dhe_dss) ->
- ?SIGNATURE_DSA;
-sig_alg(_) ->
- ?NULL.
-
-%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
get_tls_handshake_aux(<<?BYTE(Type), ?UINT24(Length),
@@ -876,6 +864,13 @@ dec_hs(?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) ->
dec_hs(?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary,
?UINT16(GLen), G:GLen/binary,
?UINT16(YLen), Y:YLen/binary,
+ ?UINT16(0)>>) -> %% May happen if key_algorithm is dh_anon
+ #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G,
+ dh_y = Y},
+ signed_params = <<>>};
+dec_hs(?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary,
+ ?UINT16(GLen), G:GLen/binary,
+ ?UINT16(YLen), Y:YLen/binary,
?UINT16(Len), Sig:Len/binary>>) ->
#server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G,
dh_y = Y},
@@ -958,14 +953,14 @@ certs_from_list(ACList) ->
<<?UINT24(CertLen), Cert/binary>>
end || Cert <- ACList]).
-enc_hs(#hello_request{}, _Version, _) ->
+enc_hs(#hello_request{}, _Version) ->
{?HELLO_REQUEST, <<>>};
enc_hs(#client_hello{client_version = {Major, Minor},
random = Random,
session_id = SessionID,
cipher_suites = CipherSuites,
compression_methods = CompMethods,
- renegotiation_info = RenegotiationInfo}, _Version, _) ->
+ renegotiation_info = RenegotiationInfo}, _Version) ->
SIDLength = byte_size(SessionID),
BinCompMethods = list_to_binary(CompMethods),
CmLength = byte_size(BinCompMethods),
@@ -983,20 +978,20 @@ enc_hs(#server_hello{server_version = {Major, Minor},
session_id = Session_ID,
cipher_suite = Cipher_suite,
compression_method = Comp_method,
- renegotiation_info = RenegotiationInfo}, _Version, _) ->
+ renegotiation_info = RenegotiationInfo}, _Version) ->
SID_length = byte_size(Session_ID),
Extensions = hello_extensions(RenegotiationInfo),
ExtensionsBin = enc_hello_extensions(Extensions),
{?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID/binary,
Cipher_suite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
-enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version, _) ->
+enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) ->
ASN1Certs = certs_from_list(ASN1CertList),
ACLen = erlang:iolist_size(ASN1Certs),
{?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>};
enc_hs(#server_key_exchange{params = #server_dh_params{
dh_p = P, dh_g = G, dh_y = Y},
- signed_params = SignedParams}, _Version, _) ->
+ signed_params = SignedParams}, _Version) ->
PLen = byte_size(P),
GLen = byte_size(G),
YLen = byte_size(Y),
@@ -1008,21 +1003,21 @@ enc_hs(#server_key_exchange{params = #server_dh_params{
};
enc_hs(#certificate_request{certificate_types = CertTypes,
certificate_authorities = CertAuths},
- _Version, _) ->
+ _Version) ->
CertTypesLen = byte_size(CertTypes),
CertAuthsLen = byte_size(CertAuths),
{?CERTIFICATE_REQUEST,
<<?BYTE(CertTypesLen), CertTypes/binary,
?UINT16(CertAuthsLen), CertAuths/binary>>
};
-enc_hs(#server_hello_done{}, _Version, _) ->
+enc_hs(#server_hello_done{}, _Version) ->
{?SERVER_HELLO_DONE, <<>>};
-enc_hs(#client_key_exchange{exchange_keys = ExchangeKeys}, Version, _) ->
+enc_hs(#client_key_exchange{exchange_keys = ExchangeKeys}, Version) ->
{?CLIENT_KEY_EXCHANGE, enc_cke(ExchangeKeys, Version)};
-enc_hs(#certificate_verify{signature = BinSig}, _, _) ->
+enc_hs(#certificate_verify{signature = BinSig}, _) ->
EncSig = enc_bin_sig(BinSig),
{?CERTIFICATE_VERIFY, EncSig};
-enc_hs(#finished{verify_data = VerifyData}, _Version, _) ->
+enc_hs(#finished{verify_data = VerifyData}, _Version) ->
{?FINISHED, VerifyData}.
enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS},{3, 0}) ->
@@ -1152,7 +1147,7 @@ calc_certificate_verify({3, N}, _, Algorithm, Hashes)
key_exchange_alg(rsa) ->
?KEY_EXCHANGE_RSA;
key_exchange_alg(Alg) when Alg == dhe_rsa; Alg == dhe_dss;
- Alg == dh_dss; Alg == dh_rsa ->
+ Alg == dh_dss; Alg == dh_rsa; Alg == dh_anon ->
?KEY_EXCHANGE_DIFFIE_HELLMAN;
key_exchange_alg(_) ->
?NULL.
@@ -1166,3 +1161,8 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
{unknown, UserState} ->
{unknown, {SslState, UserState}}
end.
+
+alg_oid(#'RSAPrivateKey'{}) ->
+ ?'rsaEncryption';
+alg_oid(#'DSAPrivateKey'{}) ->
+ ?'id-dsa'.
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index ddb05e70f6..4148032cb7 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -104,11 +104,11 @@
-type tls_atom_version() :: sslv3 | tlsv1.
-type cache_ref() :: term().
-type certdb_ref() :: term().
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss.
--type enum_algo() :: integer().
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon.
+-type oid() :: tuple().
-type public_key() :: #'RSAPublicKey'{} | integer().
-type public_key_params() :: #'Dss-Parms'{} | term().
--type public_key_info() :: {enum_algo(), public_key(), public_key_params()}.
+-type public_key_info() :: {oid(), public_key(), public_key_params()}.
-type der_cert() :: binary().
-type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}.
-type issuer() :: tuple().
diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl
index 1add203fb0..f3cb6ad66e 100644
--- a/lib/ssl/src/ssl_ssl3.erl
+++ b/lib/ssl/src/ssl_ssl3.erl
@@ -79,10 +79,9 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) ->
SHA = handshake_hash(?SHA, MasterSecret, Sender, SHAHash),
<<MD5/binary, SHA/binary>>.
--spec certificate_verify(key_algo(), binary(), {binary(), binary()}) -> binary().
+-spec certificate_verify(OID::tuple(), binary(), {binary(), binary()}) -> binary().
-certificate_verify(Algorithm, MasterSecret, {MD5Hash, SHAHash})
- when Algorithm == rsa; Algorithm == dhe_rsa ->
+certificate_verify(?'rsaEncryption', MasterSecret, {MD5Hash, SHAHash}) ->
%% md5_hash
%% MD5(master_secret + pad_2 +
%% MD5(handshake_messages + master_secret + pad_1));
@@ -94,7 +93,7 @@ certificate_verify(Algorithm, MasterSecret, {MD5Hash, SHAHash})
SHA = handshake_hash(?SHA, MasterSecret, undefined, SHAHash),
<<MD5/binary, SHA/binary>>;
-certificate_verify(dhe_dss, MasterSecret, {_, SHAHash}) ->
+certificate_verify(?'id-dsa', MasterSecret, {_, SHAHash}) ->
%% sha_hash
%% SHA(master_secret + pad_2 +
%% SHA(handshake_messages + master_secret + pad_1));
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index d1bc0730ba..dd66418dd8 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -60,15 +60,14 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) ->
SHA = hash_final(?SHA, SHAHash),
prf(MasterSecret, finished_label(Role), [MD5, SHA], 12).
--spec certificate_verify(key_algo(), {binary(), binary()}) -> binary().
+-spec certificate_verify(OID::tuple(), {binary(), binary()}) -> binary().
-certificate_verify(Algorithm, {MD5Hash, SHAHash}) when Algorithm == rsa;
- Algorithm == dhe_rsa ->
+certificate_verify(?'rsaEncryption', {MD5Hash, SHAHash}) ->
MD5 = hash_final(?MD5, MD5Hash),
SHA = hash_final(?SHA, SHAHash),
<<MD5/binary, SHA/binary>>;
-certificate_verify(dhe_dss, {_, SHAHash}) ->
+certificate_verify(?'id-dsa', {_, SHAHash}) ->
hash_final(?SHA, SHAHash).
-spec setup_keys(binary(), binary(), binary(), integer(),
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index 9e4aecac45..c0a7f8d257 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -40,6 +40,7 @@ MODULES = \
ssl_packet_SUITE \
ssl_payload_SUITE \
ssl_to_openssl_SUITE \
+ ssl_session_cache_SUITE \
ssl_test_MACHINE \
old_ssl_active_SUITE \
old_ssl_active_once_SUITE \
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index fade67f3ba..ea84b3c9d1 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -34,12 +34,6 @@
-define(EXPIRE, 10).
-define(SLEEP, 500).
--behaviour(ssl_session_cache_api).
-
-%% For the session cache tests
--export([init/1, terminate/1, lookup/2, update/3,
- delete/2, foldl/3, select_session/2]).
-
%% Test server callback functions
%%--------------------------------------------------------------------
%% Function: init_per_suite(Config) -> Config
@@ -89,13 +83,6 @@ end_per_suite(_Config) ->
%% variable, but should NOT alter/remove any existing entries.
%% Description: Initialization before each test case
%%--------------------------------------------------------------------
-init_per_testcase(session_cache_process_list, Config) ->
- init_customized_session_cache(list, Config);
-
-init_per_testcase(session_cache_process_mnesia, Config) ->
- mnesia:start(),
- init_customized_session_cache(mnesia, Config);
-
init_per_testcase(reuse_session_expired, Config0) ->
Config = lists:keydelete(watchdog, 1, Config0),
Dog = ssl_test_lib:timetrap(?EXPIRE * 1000 * 5),
@@ -142,16 +129,6 @@ init_per_testcase(_TestCase, Config0) ->
Dog = test_server:timetrap(?TIMEOUT),
[{watchdog, Dog} | Config].
-init_customized_session_cache(Type, Config0) ->
- Config = lists:keydelete(watchdog, 1, Config0),
- Dog = test_server:timetrap(?TIMEOUT),
- ssl:stop(),
- application:load(ssl),
- application:set_env(ssl, session_cb, ?MODULE),
- application:set_env(ssl, session_cb_init_args, [Type]),
- ssl:start(),
- [{watchdog, Dog} | Config].
-
%%--------------------------------------------------------------------
%% Function: end_per_testcase(TestCase, Config) -> _
%% Case - atom()
@@ -160,16 +137,6 @@ init_customized_session_cache(Type, Config0) ->
%% A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after each test case
%%--------------------------------------------------------------------
-end_per_testcase(session_cache_process_list, Config) ->
- application:unset_env(ssl, session_cb),
- end_per_testcase(default_action, Config);
-end_per_testcase(session_cache_process_mnesia, Config) ->
- application:unset_env(ssl, session_cb),
- application:unset_env(ssl, session_cb_init_args),
- mnesia:stop(),
- ssl:stop(),
- ssl:start(),
- end_per_testcase(default_action, Config);
end_per_testcase(reuse_session_expired, Config) ->
application:unset_env(ssl, session_lifetime),
end_per_testcase(default_action, Config);
@@ -216,6 +183,8 @@ all(suite) ->
ciphers_dsa_signed_certs_ssl3,
ciphers_dsa_signed_certs_openssl_names,
ciphers_dsa_signed_certs_openssl_names_ssl3,
+ anonymous_cipher_suites,
+ default_reject_anonymous,
send_close,
close_transport_accept, dh_params, server_verify_peer_passive,
server_verify_peer_active, server_verify_peer_active_once,
@@ -226,7 +195,6 @@ all(suite) ->
server_verify_client_once_active,
server_verify_client_once_active_once, client_verify_none_passive,
client_verify_none_active, client_verify_none_active_once,
- session_cache_process_list, session_cache_process_mnesia,
reuse_session, reuse_session_expired,
server_does_not_want_to_reuse_session, client_renegotiate,
server_renegotiate, client_renegotiate_reused_session,
@@ -1165,13 +1133,13 @@ ecertfile(Config) when is_list(Config) ->
Server =
ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
- {options, ServerBadOpts}]),
+ {options, ServerBadOpts}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client_error([{node, ClientNode},
- {port, Port}, {host, Hostname},
+ {port, Port}, {host, Hostname},
{from, self()},
{options, ClientOpts}]),
@@ -1522,6 +1490,14 @@ ciphers_dsa_signed_certs_openssl_names_ssl3(Config) when is_list(Config) ->
Ciphers = ssl_test_lib:openssl_dsa_suites(),
run_suites(Ciphers, Version, Config, dsa).
+anonymous_cipher_suites(doc)->
+ ["Test the anonymous ciphersuites"];
+anonymous_cipher_suites(suite) ->
+ [];
+anonymous_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:anonymous_suites(),
+ run_suites(Ciphers, Version, Config, anonymous).
run_suites(Ciphers, Version, Config, Type) ->
{ClientOpts, ServerOpts} =
@@ -1531,8 +1507,12 @@ run_suites(Ciphers, Version, Config, Type) ->
?config(server_opts, Config)};
dsa ->
{?config(client_opts, Config),
- ?config(server_dsa_opts, Config)}
- end,
+ ?config(server_dsa_opts, Config)};
+ anonymous ->
+ %% No certs in opts!
+ {?config(client_opts, Config),
+ ?config(server_anon, Config)}
+ end,
Result = lists:map(fun(Cipher) ->
cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
@@ -1593,6 +1573,32 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
end.
%%--------------------------------------------------------------------
+default_reject_anonymous(doc)->
+ ["Test that by default anonymous cipher suites are rejected "];
+default_reject_anonymous(suite) ->
+ [];
+default_reject_anonymous(Config) when is_list(Config) ->
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+
+ [Cipher | _] = ssl_test_lib:anonymous_suites(),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options,
+ [{ciphers,[Cipher]} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, {error, "insufficient security"},
+ Client, {error, "insufficient security"}).
+
+%%--------------------------------------------------------------------
reuse_session(doc) ->
["Test reuse of sessions (short handshake)"];
@@ -2952,7 +2958,7 @@ unknown_server_ca_accept_verify_peer(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
unknown_server_ca_accept_backwardscompatibilty(doc) ->
- ["Test that the client succeds if the ca is unknown in verify_none mode"];
+ ["Test that old style verify_funs will work"];
unknown_server_ca_accept_backwardscompatibilty(suite) ->
[];
unknown_server_ca_accept_backwardscompatibilty(Config) when is_list(Config) ->
@@ -3047,6 +3053,17 @@ der_input_opts(Opts) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+erlang_ssl_receive(Socket, Data) ->
+ receive
+ {ssl, Socket, Data} ->
+ io:format("Received ~p~n",[Data]),
+ ok;
+ Other ->
+ test_server:fail({unexpected_message, Other})
+ after ?SLEEP * 3 ->
+ test_server:fail({did_not_get, Data})
+ end.
+
send_recv_result(Socket) ->
ssl:send(Socket, "Hello world"),
{ok,"Hello world"} = ssl:recv(Socket, 11),
@@ -3086,162 +3103,3 @@ renegotiate_reuse_session(Socket, Data) ->
%% Make sure session is registerd
test_server:sleep(?SLEEP),
renegotiate(Socket, Data).
-
-session_cache_process_list(doc) ->
- ["Test reuse of sessions (short handshake)"];
-
-session_cache_process_list(suite) ->
- [];
-session_cache_process_list(Config) when is_list(Config) ->
- session_cache_process(list,Config).
-
-session_cache_process_mnesia(doc) ->
- ["Test reuse of sessions (short handshake)"];
-
-session_cache_process_mnesia(suite) ->
- [];
-session_cache_process_mnesia(Config) when is_list(Config) ->
- session_cache_process(mnesia,Config).
-
-session_cache_process(_Type,Config) when is_list(Config) ->
- reuse_session(Config).
-
-init([Type]) ->
- ets:new(ssl_test, [named_table, public, set]),
- ets:insert(ssl_test, {type, Type}),
- case Type of
- list ->
- spawn(fun() -> session_loop([]) end);
- mnesia ->
- mnesia:start(),
- {atomic,ok} = mnesia:create_table(sess_cache, []),
- sess_cache
- end.
-
-session_cb() ->
- [{type, Type}] = ets:lookup(ssl_test, type),
- Type.
-
-terminate(Cache) ->
- case session_cb() of
- list ->
- Cache ! terminate;
- mnesia ->
- catch {atomic,ok} =
- mnesia:delete_table(sess_cache)
- end.
-
-lookup(Cache, Key) ->
- case session_cb() of
- list ->
- Cache ! {self(), lookup, Key},
- receive {Cache, Res} -> Res end;
- mnesia ->
- case mnesia:transaction(fun() ->
- mnesia:read(sess_cache,
- Key, read)
- end) of
- {atomic, [{sess_cache, Key, Value}]} ->
- Value;
- _ ->
- undefined
- end
- end.
-
-update(Cache, Key, Value) ->
- case session_cb() of
- list ->
- Cache ! {update, Key, Value};
- mnesia ->
- {atomic, ok} =
- mnesia:transaction(fun() ->
- mnesia:write(sess_cache,
- {sess_cache, Key, Value}, write)
- end)
- end.
-
-delete(Cache, Key) ->
- case session_cb() of
- list ->
- Cache ! {delete, Key};
- mnesia ->
- {atomic, ok} =
- mnesia:transaction(fun() ->
- mnesia:delete(sess_cache, Key)
- end)
- end.
-
-foldl(Fun, Acc, Cache) ->
- case session_cb() of
- list ->
- Cache ! {self(),foldl,Fun,Acc},
- receive {Cache, Res} -> Res end;
- mnesia ->
- Foldl = fun() ->
- mnesia:foldl(Fun, Acc, sess_cache)
- end,
- {atomic, Res} = mnesia:transaction(Foldl),
- Res
- end.
-
-select_session(Cache, PartialKey) ->
- case session_cb() of
- list ->
- Cache ! {self(),select_session, PartialKey},
- receive
- {Cache, Res} ->
- Res
- end;
- mnesia ->
- Sel = fun() ->
- mnesia:select(Cache,
- [{{sess_cache,{PartialKey,'$1'}, '$2'},
- [],['$$']}])
- end,
- {atomic, Res} = mnesia:transaction(Sel),
- Res
- end.
-
-session_loop(Sess) ->
- receive
- terminate ->
- ok;
- {Pid, lookup, Key} ->
- case lists:keysearch(Key,1,Sess) of
- {value, {Key,Value}} ->
- Pid ! {self(), Value};
- _ ->
- Pid ! {self(), undefined}
- end,
- session_loop(Sess);
- {update, Key, Value} ->
- NewSess = [{Key,Value}| lists:keydelete(Key,1,Sess)],
- session_loop(NewSess);
- {delete, Key} ->
- session_loop(lists:keydelete(Key,1,Sess));
- {Pid,foldl,Fun,Acc} ->
- Res = lists:foldl(Fun, Acc,Sess),
- Pid ! {self(), Res},
- session_loop(Sess);
- {Pid,select_session,PKey} ->
- Sel = fun({{PKey0, Id},Session}, Acc) when PKey == PKey0 ->
- [[Id, Session]|Acc];
- (_,Acc) ->
- Acc
- end,
- Sessions = lists:foldl(Sel, [], Sess),
- Pid ! {self(), Sessions},
- session_loop(Sess)
- end.
-
-
-erlang_ssl_receive(Socket, Data) ->
- receive
- {ssl, Socket, Data} ->
- io:format("Received ~p~n",[Data]),
- ok;
- Other ->
- test_server:fail({unexpected_message, Other})
- after ?SLEEP * 3 ->
- test_server:fail({did_not_get, Data})
- end.
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
new file mode 100644
index 0000000000..7a441e4599
--- /dev/null
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -0,0 +1,305 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2010. 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
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.2
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_session_cache_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include("test_server.hrl").
+
+-define(SLEEP, 500).
+-define(TIMEOUT, 60000).
+-behaviour(ssl_session_cache_api).
+
+%% For the session cache tests
+-export([init/1, terminate/1, lookup/2, update/3,
+ delete/2, foldl/3, select_session/2]).
+
+%% Test server callback functions
+%%--------------------------------------------------------------------
+%% Function: init_per_suite(Config) -> Config
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Description: Initialization before the whole suite
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%%--------------------------------------------------------------------
+init_per_suite(Config0) ->
+ Dog = ssl_test_lib:timetrap(?TIMEOUT *2),
+ crypto:start(),
+ application:start(public_key),
+ ssl:start(),
+
+ %% make rsa certs using oppenssl
+ Result =
+ (catch make_certs:all(?config(data_dir, Config0),
+ ?config(priv_dir, Config0))),
+ test_server:format("Make certs ~p~n", [Result]),
+
+ Config1 = ssl_test_lib:make_dsa_cert(Config0),
+ Config = ssl_test_lib:cert_options(Config1),
+ [{watchdog, Dog} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_suite(Config) -> _
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Description: Cleanup after the whole suite
+%%--------------------------------------------------------------------
+end_per_suite(_Config) ->
+ ssl:stop(),
+ crypto:stop().
+
+%%--------------------------------------------------------------------
+%% Function: init_per_testcase(TestCase, Config) -> Config
+%% Case - atom()
+%% Name of the test case that is about to be run.
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%%
+%% Description: Initialization before each test case
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%% Description: Initialization before each test case
+%%--------------------------------------------------------------------
+init_per_testcase(session_cache_process_list, Config) ->
+ init_customized_session_cache(list, Config);
+
+init_per_testcase(session_cache_process_mnesia, Config) ->
+ mnesia:start(),
+ init_customized_session_cache(mnesia, Config);
+
+init_per_testcase(_TestCase, Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = test_server:timetrap(?TIMEOUT),
+ [{watchdog, Dog} | Config].
+
+init_customized_session_cache(Type, Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = test_server:timetrap(?TIMEOUT),
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, session_cb, ?MODULE),
+ application:set_env(ssl, session_cb_init_args, [Type]),
+ ssl:start(),
+ [{watchdog, Dog} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_testcase(TestCase, Config) -> _
+%% Case - atom()
+%% Name of the test case that is about to be run.
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Description: Cleanup after each test case
+%%--------------------------------------------------------------------
+end_per_testcase(session_cache_process_list, Config) ->
+ application:unset_env(ssl, session_cb),
+ end_per_testcase(default_action, Config);
+end_per_testcase(session_cache_process_mnesia, Config) ->
+ application:unset_env(ssl, session_cb),
+ application:unset_env(ssl, session_cb_init_args),
+ mnesia:stop(),
+ ssl:stop(),
+ ssl:start(),
+ end_per_testcase(default_action, Config);
+end_per_testcase(_TestCase, Config) ->
+ Dog = ?config(watchdog, Config),
+ case Dog of
+ undefined ->
+ ok;
+ _ ->
+ test_server:timetrap_cancel(Dog)
+ end.
+
+%%--------------------------------------------------------------------
+%% Function: all(Clause) -> TestCases
+%% Clause - atom() - suite | doc
+%% TestCases - [Case]
+%% Case - atom()
+%% Name of a test case.
+%% Description: Returns a list of all test cases in this test suite
+%%--------------------------------------------------------------------
+all(doc) ->
+ ["Test session cach API"];
+
+all(suite) ->
+ [
+ session_cache_process_list, session_cache_process_mnesia
+ ].
+
+session_cache_process_list(doc) ->
+ ["Test reuse of sessions (short handshake)"];
+
+session_cache_process_list(suite) ->
+ [];
+session_cache_process_list(Config) when is_list(Config) ->
+ session_cache_process(list,Config).
+%%--------------------------------------------------------------------
+session_cache_process_mnesia(doc) ->
+ ["Test reuse of sessions (short handshake)"];
+
+session_cache_process_mnesia(suite) ->
+ [];
+session_cache_process_mnesia(Config) when is_list(Config) ->
+ session_cache_process(mnesia,Config).
+
+
+%%--------------------------------------------------------------------
+%%% Session cache API callbacks
+%%--------------------------------------------------------------------
+
+init([Type]) ->
+ ets:new(ssl_test, [named_table, public, set]),
+ ets:insert(ssl_test, {type, Type}),
+ case Type of
+ list ->
+ spawn(fun() -> session_loop([]) end);
+ mnesia ->
+ mnesia:start(),
+ {atomic,ok} = mnesia:create_table(sess_cache, []),
+ sess_cache
+ end.
+
+session_cb() ->
+ [{type, Type}] = ets:lookup(ssl_test, type),
+ Type.
+
+terminate(Cache) ->
+ case session_cb() of
+ list ->
+ Cache ! terminate;
+ mnesia ->
+ catch {atomic,ok} =
+ mnesia:delete_table(sess_cache)
+ end.
+
+lookup(Cache, Key) ->
+ case session_cb() of
+ list ->
+ Cache ! {self(), lookup, Key},
+ receive {Cache, Res} -> Res end;
+ mnesia ->
+ case mnesia:transaction(fun() ->
+ mnesia:read(sess_cache,
+ Key, read)
+ end) of
+ {atomic, [{sess_cache, Key, Value}]} ->
+ Value;
+ _ ->
+ undefined
+ end
+ end.
+
+update(Cache, Key, Value) ->
+ case session_cb() of
+ list ->
+ Cache ! {update, Key, Value};
+ mnesia ->
+ {atomic, ok} =
+ mnesia:transaction(fun() ->
+ mnesia:write(sess_cache,
+ {sess_cache, Key, Value}, write)
+ end)
+ end.
+
+delete(Cache, Key) ->
+ case session_cb() of
+ list ->
+ Cache ! {delete, Key};
+ mnesia ->
+ {atomic, ok} =
+ mnesia:transaction(fun() ->
+ mnesia:delete(sess_cache, Key)
+ end)
+ end.
+
+foldl(Fun, Acc, Cache) ->
+ case session_cb() of
+ list ->
+ Cache ! {self(),foldl,Fun,Acc},
+ receive {Cache, Res} -> Res end;
+ mnesia ->
+ Foldl = fun() ->
+ mnesia:foldl(Fun, Acc, sess_cache)
+ end,
+ {atomic, Res} = mnesia:transaction(Foldl),
+ Res
+ end.
+
+select_session(Cache, PartialKey) ->
+ case session_cb() of
+ list ->
+ Cache ! {self(),select_session, PartialKey},
+ receive
+ {Cache, Res} ->
+ Res
+ end;
+ mnesia ->
+ Sel = fun() ->
+ mnesia:select(Cache,
+ [{{sess_cache,{PartialKey,'$1'}, '$2'},
+ [],['$$']}])
+ end,
+ {atomic, Res} = mnesia:transaction(Sel),
+ Res
+ end.
+
+session_loop(Sess) ->
+ receive
+ terminate ->
+ ok;
+ {Pid, lookup, Key} ->
+ case lists:keysearch(Key,1,Sess) of
+ {value, {Key,Value}} ->
+ Pid ! {self(), Value};
+ _ ->
+ Pid ! {self(), undefined}
+ end,
+ session_loop(Sess);
+ {update, Key, Value} ->
+ NewSess = [{Key,Value}| lists:keydelete(Key,1,Sess)],
+ session_loop(NewSess);
+ {delete, Key} ->
+ session_loop(lists:keydelete(Key,1,Sess));
+ {Pid,foldl,Fun,Acc} ->
+ Res = lists:foldl(Fun, Acc,Sess),
+ Pid ! {self(), Res},
+ session_loop(Sess);
+ {Pid,select_session,PKey} ->
+ Sel = fun({{PKey0, Id},Session}, Acc) when PKey == PKey0 ->
+ [[Id, Session]|Acc];
+ (_,Acc) ->
+ Acc
+ end,
+ Sessions = lists:foldl(Sel, [], Sess),
+ Pid ! {self(), Sessions},
+ session_loop(Sess)
+ end.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+
+session_cache_process(_Type,Config) when is_list(Config) ->
+ ssl_basic_SUITE:reuse_session(Config).
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index ce164f7e4c..e1e8214ed6 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -300,6 +300,7 @@ cert_options(Config) ->
{ssl_imp, new}]},
{server_opts, [{ssl_imp, new},{reuseaddr, true},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_anon, [{ssl_imp, new},{reuseaddr, true}, {ciphers, anonymous_suites()}]},
{server_verification_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -616,6 +617,13 @@ openssl_dsa_suites() ->
end
end, Ciphers).
+anonymous_suites() ->
+ [{dh_anon, rc4_128, md5},
+ {dh_anon, des_cbc, sha},
+ {dh_anon, '3des_ede_cbc', sha},
+ {dh_anon, aes_128_cbc, sha},
+ {dh_anon, aes_256_cbc, sha}].
+
pem_to_der(File) ->
{ok, PemBin} = file:read_file(File),
public_key:pem_decode(PemBin).
@@ -633,7 +641,7 @@ cipher_result(Socket, Result) ->
receive
{ssl, Socket, "Hello\n"} ->
ssl:send(Socket, " world\n"),
- receive
+ receive
{ssl, Socket, " world\n"} ->
ok
end;
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 7f512f2ab9..55a0100b1e 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -1116,8 +1116,6 @@ run_suites(Ciphers, Version, Config, Type) ->
test_server:fail(cipher_suite_failed_see_test_case_log)
end.
-
-
cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
process_flag(trap_exit, true),
test_server:format("Testing CipherSuite ~p~n", [CipherSuite]),
@@ -1128,8 +1126,8 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
KeyFile = proplists:get_value(keyfile, ServerOpts),
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
- " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
-
+ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
+
test_server:format("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1140,11 +1138,11 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
+ {from, self()},
+ {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
+ {options,
+ [{ciphers,[CipherSuite]} |
+ ClientOpts]}]),
port_command(OpenSslPort, "Hello\n"),
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index dd4a289c61..702e1b928e 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -56,8 +56,8 @@
Even if there are no references to a table from any process, it
will not automatically be destroyed unless the owner process
terminates. It can be destroyed explicitly by using
- <c>delete/1</c>.</p>
- <p>Since R13B01, table ownership can be transferred at process termination
+ <c>delete/1</c>. The default owner is the process that created the
+ table. Table ownership can be transferred at process termination
by using the <seealso marker="#heir">heir</seealso> option or explicitly
by calling <seealso marker="#give_away/3">give_away/3</seealso>.</p>
<p>Some implementation details:</p>
@@ -82,11 +82,15 @@
<c>float()</c> that extends to the same value, hence the key
<c>1</c> and the key <c>1.0</c> are regarded as equal in an
<c>ordered_set</c> table.</p>
- <p>In general, the functions below will exit with reason
- <c>badarg</c> if any argument is of the wrong format, or if the
- table identifier is invalid.</p>
</description>
-
+ <section>
+ <title>Failure</title>
+ <p>In general, the functions below will exit with reason
+ <c>badarg</c> if any argument is of the wrong format, if the
+ table identifier is invalid or if the operation is denied due to
+ table access rights (<seealso marker="#protected">protected</seealso>
+ or <seealso marker="#private">private</seealso>).</p>
+ </section>
<section><marker id="concurrency"></marker>
<title>Concurrency</title>
<p>This module provides some limited support for concurrent access.
@@ -947,7 +951,7 @@ ets:select(Table,MatchSpec),</code>
<type>
<v>Name = atom()</v>
<v>Options = [Option]</v>
- <v>&nbsp;Option = Type | Access | named_table | {keypos,Pos} | {heir,pid(),HeirData} | {heir,none} | {write_concurrency,bool()}</v>
+ <v>&nbsp;Option = Type | Access | named_table | {keypos,Pos} | {heir,pid(),HeirData} | {heir,none} | {write_concurrency,bool()} | {read_concurrency,bool()}</v>
<v>&nbsp;&nbsp;Type = set | ordered_set | bag | duplicate_bag</v>
<v>&nbsp;&nbsp;Access = public | protected | private</v>
<v>&nbsp;&nbsp;Pos = int()</v>
@@ -963,7 +967,7 @@ ets:select(Table,MatchSpec),</code>
table is named or not. If one or more options are left out,
the default values are used. This means that not specifying
any options (<c>[]</c>) is the same as specifying
- <c>[set,protected,{keypos,1},{heir,none},{write_concurrency,false}]</c>.</p>
+ <c>[set,protected,{keypos,1},{heir,none},{write_concurrency,false},{read_concurrency,false}]</c>.</p>
<list type="bulleted">
<item>
<p><c>set</c>
@@ -1002,12 +1006,14 @@ ets:select(Table,MatchSpec),</code>
Any process may read or write to the table.</p>
</item>
<item>
+ <marker id="protected"></marker>
<p><c>protected</c>
The owner process can read and write to the table. Other
processes can only read the table. This is the default
setting for the access rights.</p>
</item>
<item>
+ <marker id="private"></marker>
<p><c>private</c>
Only the owner process can read or write to the table.</p>
</item>
diff --git a/lib/stdlib/doc/src/filelib.xml b/lib/stdlib/doc/src/filelib.xml
index c1c4ca9350..4ff3b22f32 100644
--- a/lib/stdlib/doc/src/filelib.xml
+++ b/lib/stdlib/doc/src/filelib.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2003</year><year>2009</year>
+ <year>2003</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -160,6 +160,12 @@ DeepList = [char() | atom() | DeepList]</code>
<p>Matches any number of characters up to the end of
the filename, the next dot, or the next slash.</p>
</item>
+ <tag>[Character1,Character2,...]</tag>
+ <item>
+ <p>Matches any of the characters listed. Two characters
+ separated by a hyphen will match a range of characters.
+ Example: <c>[A-Z]</c> will match any uppercase letter.</p>
+ </item>
<tag>{Item,...}</tag>
<item>
<p>Alternation. Matches one of the alternatives.</p>
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index 4584b8184f..6c91f1efb7 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -147,6 +147,7 @@
bin, % small chunk not consumed, or 'eof' at end-of-file
alloc, % the part of the file not yet scanned, mostly a binary
tab,
+ proc, % the pid of the Dets process
match_program % true | compiled_match_spec() | undefined
}).
@@ -208,8 +209,6 @@ all() ->
bchunk(Tab, start) ->
badarg(treq(Tab, {bchunk_init, Tab}), [Tab, start]);
-bchunk(Tab, #dets_cont{bin = eof, tab = Tab}) ->
- '$end_of_table';
bchunk(Tab, #dets_cont{what = bchunk, tab = Tab} = State) ->
badarg(treq(Tab, {bchunk, State}), [Tab, State]);
bchunk(Tab, Term) ->
@@ -722,11 +721,14 @@ init_chunk_match(Tab, Pat, What, N) when is_integer(N), N >= 0;
N =:= default ->
case compile_match_spec(What, Pat) of
{Spec, MP} ->
- case req(dets_server:get_pid(Tab), {match, MP, Spec, N}) of
+ Proc = dets_server:get_pid(Tab),
+ case req(Proc, {match, MP, Spec, N}) of
{done, L} ->
- {L, #dets_cont{tab = Tab, what = What, bin = eof}};
+ {L, #dets_cont{tab = Tab, proc = Proc, what = What,
+ bin = eof}};
{cont, State} ->
- chunk_match(State#dets_cont{what = What, tab = Tab});
+ chunk_match(State#dets_cont{what = What, tab = Tab,
+ proc = Proc});
Error ->
Error
end;
@@ -736,34 +738,28 @@ init_chunk_match(Tab, Pat, What, N) when is_integer(N), N >= 0;
init_chunk_match(_Tab, _Pat, _What, _) ->
badarg.
-chunk_match(State) ->
- case catch dets_server:get_pid(State#dets_cont.tab) of
- {'EXIT', _Reason} ->
- badarg;
- _Proc when State#dets_cont.bin =:= eof ->
- '$end_of_table';
- Proc ->
- case req(Proc, {match_init, State}) of
- {cont, {Bins, NewState}} ->
- MP = NewState#dets_cont.match_program,
- case catch do_foldl_bins(Bins, MP) of
- {'EXIT', _} ->
- case ets:is_compiled_ms(MP) of
- true ->
- Bad = dets_utils:bad_object(chunk_match,
- Bins),
- req(Proc, {corrupt, Bad});
- false ->
- badarg
- end;
- [] ->
- chunk_match(NewState);
- Terms ->
- {Terms, NewState}
- end;
- Error ->
- Error
- end
+chunk_match(#dets_cont{proc = Proc}=State) ->
+ case req(Proc, {match_init, State}) of
+ '$end_of_table'=Reply ->
+ Reply;
+ {cont, {Bins, NewState}} ->
+ MP = NewState#dets_cont.match_program,
+ case catch do_foldl_bins(Bins, MP) of
+ {'EXIT', _} ->
+ case ets:is_compiled_ms(MP) of
+ true ->
+ Bad = dets_utils:bad_object(chunk_match, Bins),
+ req(Proc, {corrupt, Bad});
+ false ->
+ badarg
+ end;
+ [] ->
+ chunk_match(NewState);
+ Terms ->
+ {Terms, NewState}
+ end;
+ Error ->
+ Error
end.
do_foldl_bins(Bins, true) ->
@@ -1094,7 +1090,9 @@ do_apply_op(Op, From, Head, N) ->
{N2, H2} when is_record(H2, head), is_integer(N2) ->
open_file_loop(H2, N2);
H2 when is_record(H2, head) ->
- open_file_loop(H2, N)
+ open_file_loop(H2, N);
+ {{more,From1,Op1,N1}, NewHead} ->
+ do_apply_op(Op1, From1, NewHead, N1)
catch
exit:normal ->
exit(normal);
@@ -1363,37 +1361,35 @@ start_auto_save_timer(Head) ->
%% lookup requests in parallel. Evalute delete_object, delete and
%% insert as well.
stream_op(Op, Pid, Pids, Head, N) ->
- stream_op(Head, Pids, [], N, Pid, Op, Head#head.fixed).
+ #head{fixed = Fxd, update_mode = M} = Head,
+ stream_op(Head, Pids, [], N, Pid, Op, Fxd, M).
-stream_loop(Head, Pids, C, N, false = Fxd) ->
+stream_loop(Head, Pids, C, N, false = Fxd, M) ->
receive
?DETS_CALL(From, Message) ->
- stream_op(Head, Pids, C, N, From, Message, Fxd)
+ stream_op(Head, Pids, C, N, From, Message, Fxd, M)
after 0 ->
stream_end(Head, Pids, C, N, no_more)
end;
-stream_loop(Head, Pids, C, N, _Fxd) ->
+stream_loop(Head, Pids, C, N, _Fxd, _M) ->
stream_end(Head, Pids, C, N, no_more).
-stream_op(Head, Pids, C, N, Pid, {lookup_keys,Keys}, Fxd) ->
+stream_op(Head, Pids, C, N, Pid, {lookup_keys,Keys}, Fxd, M) ->
NC = [{{lookup,Pid},Keys} | C],
- stream_loop(Head, Pids, NC, N, Fxd);
-stream_op(Head, Pids, C, N, Pid, {insert, _Objects} = Op, Fxd) ->
- NC = [Op | C],
- stream_loop(Head, [Pid | Pids], NC, N, Fxd);
-stream_op(Head, Pids, C, N, Pid, {insert_new, _Objects} = Op, Fxd) ->
+ stream_loop(Head, Pids, NC, N, Fxd, M);
+stream_op(Head, Pids, C, N, Pid, {insert, _Objects} = Op, Fxd, dirty = M) ->
NC = [Op | C],
- stream_loop(Head, [Pid | Pids], NC, N, Fxd);
-stream_op(Head, Pids, C, N, Pid, {delete_key, _Keys} = Op, Fxd) ->
+ stream_loop(Head, [Pid | Pids], NC, N, Fxd, M);
+stream_op(Head, Pids, C, N, Pid, {delete_key, _Keys} = Op, Fxd, dirty = M) ->
NC = [Op | C],
- stream_loop(Head, [Pid | Pids], NC, N, Fxd);
-stream_op(Head, Pids, C, N, Pid, {delete_object, _Objects} = Op, Fxd) ->
+ stream_loop(Head, [Pid | Pids], NC, N, Fxd, M);
+stream_op(Head, Pids, C, N, Pid, {delete_object, _Os} = Op, Fxd, dirty = M) ->
NC = [Op | C],
- stream_loop(Head, [Pid | Pids], NC, N, Fxd);
-stream_op(Head, Pids, C, N, Pid, {member, Key}, Fxd) ->
+ stream_loop(Head, [Pid | Pids], NC, N, Fxd, M);
+stream_op(Head, Pids, C, N, Pid, {member, Key}, Fxd, M) ->
NC = [{{lookup,[Pid]},[Key]} | C],
- stream_loop(Head, Pids, NC, N, Fxd);
-stream_op(Head, Pids, C, N, Pid, Op, _Fxd) ->
+ stream_loop(Head, Pids, NC, N, Fxd, M);
+stream_op(Head, Pids, C, N, Pid, Op, _Fxd, _M) ->
stream_end(Head, Pids, C, N, {Pid,Op}).
stream_end(Head, Pids0, C, N, Next) ->
@@ -1438,7 +1434,7 @@ stream_end2([], Ps, no_more, N, C, Head, _Reply) ->
penalty(Head, Ps, C),
{N, Head};
stream_end2([], _Ps, {From, Op}, N, _C, Head, _Reply) ->
- apply_op(Op, From, Head, N).
+ {{more,From,Op,N},Head}.
penalty(H, _Ps, _C) when H#head.fixed =:= false ->
ok;
@@ -1578,13 +1574,18 @@ do_bchunk_init(Head, Tab) ->
L = dets_utils:all_allocated(H2),
C0 = #dets_cont{no_objs = default, bin = <<>>, alloc = L},
BinParms = term_to_binary(Parms),
- {H2, {C0#dets_cont{tab = Tab, what = bchunk}, [BinParms]}}
+ {H2, {C0#dets_cont{tab = Tab, proc = self(),what = bchunk},
+ [BinParms]}}
end;
{NewHead, _} = HeadError when is_record(NewHead, head) ->
HeadError
end.
%% -> {NewHead, {cont(), [binary()]}} | {NewHead, Error}
+do_bchunk(Head, #dets_cont{proc = Proc}) when Proc =/= self() ->
+ {Head, badarg};
+do_bchunk(Head, #dets_cont{bin = eof}) ->
+ {Head, '$end_of_table'};
do_bchunk(Head, State) ->
case dets_v9:read_bchunks(Head, State#dets_cont.alloc) of
{error, Reason} ->
@@ -1954,6 +1955,8 @@ flookup_keys(Head, Keys) ->
end.
%% -> {NewHead, Result}
+fmatch_init(Head, #dets_cont{bin = eof}) ->
+ {Head, '$end_of_table'};
fmatch_init(Head, C) ->
case scan(Head, C) of
{scan_error, Reason} ->
diff --git a/lib/stdlib/src/dets_v8.erl b/lib/stdlib/src/dets_v8.erl
index 1f9f84cd27..af36958c1c 100644
--- a/lib/stdlib/src/dets_v8.erl
+++ b/lib/stdlib/src/dets_v8.erl
@@ -1074,6 +1074,8 @@ wl([], _Type, Del, Lookup, I, Objs) ->
[{Del, Lookup, Objs} | I].
%% -> {NewHead, ok} | {NewHead, Error}
+may_grow(Head, 0, once) ->
+ {Head, ok};
may_grow(Head, _N, _How) when Head#head.fixed =/= false ->
{Head, ok};
may_grow(#head{access = read}=Head, _N, _How) ->
diff --git a/lib/stdlib/src/dets_v9.erl b/lib/stdlib/src/dets_v9.erl
index 53238e962f..132af01f79 100644
--- a/lib/stdlib/src/dets_v9.erl
+++ b/lib/stdlib/src/dets_v9.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2010. 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
@@ -1908,6 +1908,9 @@ write_cache(Head) ->
end.
%% -> {NewHead, ok} | {NewHead, Error}
+may_grow(Head, 0, once) ->
+ %% Do not re-hash if there is a chance that the file is not dirty.
+ {Head, ok};
may_grow(Head, _N, _How) when Head#head.fixed =/= false ->
{Head, ok};
may_grow(#head{access = read}=Head, _N, _How) ->
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 81b2431f40..e5ccaddbb4 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -33,7 +33,9 @@
%% Epp state record.
-record(epp, {file, %Current file
location, %Current location
+ delta, %Offset from Location (-file)
name="", %Current file name
+ name2="", %-"-, modified by -file
istk=[], %Ifdef stack
sstk=[], %State stack
path=[], %Include-path
@@ -234,8 +236,8 @@ init_server(Pid, Name, File, AtLocation, Path, Pdm, Pre) ->
case user_predef(Pdm, Ms0) of
{ok,Ms1} ->
epp_reply(Pid, {ok,self()}),
- St = #epp{file=File, location=AtLocation, name=Name,
- path=Path, macs=Ms1, pre_opened = Pre},
+ St = #epp{file=File, location=AtLocation, delta=0, name=Name,
+ name2=Name, path=Path, macs=Ms1, pre_opened = Pre},
From = wait_request(St),
enter_file_reply(From, Name, AtLocation, AtLocation),
wait_req_scan(St);
@@ -358,8 +360,8 @@ enter_file2(NewF, Pname, From, St, AtLocation, ExtraPath) ->
enter_file_reply(From, Pname, Loc, AtLocation),
Ms = dict:store({atom,'FILE'}, {none,[{string,Loc,Pname}]}, St#epp.macs),
Path = St#epp.path ++ ExtraPath,
- #epp{location=Loc,file=NewF,
- name=Pname,sstk=[St|St#epp.sstk],path=Path,macs=Ms}.
+ #epp{file=NewF,location=Loc,name=Pname,delta=0,
+ sstk=[St|St#epp.sstk],path=Path,macs=Ms}.
enter_file_reply(From, Name, Location, AtLocation) ->
Attr = loc_attr(AtLocation),
@@ -391,14 +393,23 @@ leave_file(From, St) ->
case St#epp.sstk of
[OldSt|Sts] ->
close_file(St),
- enter_file_reply(From, OldSt#epp.name,
- OldSt#epp.location, OldSt#epp.location),
+ #epp{location=OldLoc, delta=Delta, name=OldName,
+ name2=OldName2} = OldSt,
+ CurrLoc = add_line(OldLoc, Delta),
Ms = dict:store({atom,'FILE'},
- {none,
- [{string,OldSt#epp.location,
- OldSt#epp.name}]},
+ {none,[{string,CurrLoc,OldName2}]},
St#epp.macs),
- wait_req_scan(OldSt#epp{sstk=Sts,macs=Ms});
+ NextSt = OldSt#epp{sstk=Sts,macs=Ms},
+ enter_file_reply(From, OldName, CurrLoc, CurrLoc),
+ case OldName2 =:= OldName of
+ true ->
+ From;
+ false ->
+ NFrom = wait_request(NextSt),
+ enter_file_reply(NFrom, OldName2, OldLoc,
+ neg_line(CurrLoc))
+ end,
+ wait_req_scan(NextSt);
[] ->
epp_reply(From, {eof,St#epp.location}),
wait_req_scan(St)
@@ -768,7 +779,8 @@ scan_file([{'(',_Llp},{string,_Ls,Name},{',',_Lc},{integer,_Li,Ln},{')',_Lrp},
Ms = dict:store({atom,'FILE'}, {none,[{string,1,Name}]}, St#epp.macs),
Locf = loc(Tf),
NewLoc = new_location(Ln, St#epp.location, Locf),
- wait_req_scan(St#epp{name=Name,location=NewLoc,macs=Ms});
+ Delta = abs(get_line(element(2, Tf)))-Ln + St#epp.delta,
+ wait_req_scan(St#epp{name2=Name,location=NewLoc,delta=Delta,macs=Ms});
scan_file(_Toks, Tf, From, St) ->
epp_reply(From, {error,{loc(Tf),epp,{bad,file}}}),
wait_req_scan(St).
@@ -1132,6 +1144,9 @@ neg_line(L) ->
abs_line(L) ->
erl_scan:set_attribute(line, L, fun(Line) -> abs(Line) end).
+add_line(L, Offset) ->
+ erl_scan:set_attribute(line, L, fun(Line) -> Line+Offset end).
+
start_loc(Line) when is_integer(Line) ->
1;
start_loc({_Line, _Column}) ->
@@ -1191,10 +1206,10 @@ interpret_file_attr([{attribute,Loc,file,{File,Line}}=Form | Forms],
%% -include or -include_lib
% true = L =:= Line,
case Fs of
- [_, Delta1, File | Fs1] -> % end of included file
- [Form | interpret_file_attr(Forms, Delta1, [File | Fs1])];
+ [_, File | Fs1] -> % end of included file
+ [Form | interpret_file_attr(Forms, 0, [File | Fs1])];
_ -> % start of included file
- [Form | interpret_file_attr(Forms, 0, [File, Delta | Fs])]
+ [Form | interpret_file_attr(Forms, 0, [File | Fs])]
end
end;
interpret_file_attr([Form0 | Forms], Delta, Fs) ->
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 077621ac91..0c2d3db8ec 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -311,6 +311,8 @@ format_error({ill_defined_behaviour_callbacks,Behaviour}) ->
%% --- types and specs ---
format_error({singleton_typevar, Name}) ->
io_lib:format("type variable ~w is only used once (is unbound)", [Name]);
+format_error({bad_export_type, _ETs}) ->
+ io_lib:format("bad export_type declaration", []);
format_error({duplicated_export_type, {T, A}}) ->
io_lib:format("type ~w/~w already exported", [T, A]);
format_error({undefined_type, {TypeName, Arity}}) ->
@@ -1128,8 +1130,7 @@ export(Line, Es, #lint{exports = Es0, called = Called} = St0) ->
export_type(Line, ETs, #lint{usage = Usage, exp_types = ETs0} = St0) ->
UTs0 = Usage#usage.used_types,
- {ETs1,UTs1,St1} =
- foldl(fun (TA, {E,U,St2}) ->
+ try foldl(fun ({T,A}=TA, {E,U,St2}) when is_atom(T), is_integer(A) ->
St = case gb_sets:is_element(TA, E) of
true ->
Warn = {duplicated_export_type,TA},
@@ -1139,8 +1140,13 @@ export_type(Line, ETs, #lint{usage = Usage, exp_types = ETs0} = St0) ->
end,
{gb_sets:add_element(TA, E), dict:store(TA, Line, U), St}
end,
- {ETs0,UTs0,St0}, ETs),
- St1#lint{usage = Usage#usage{used_types = UTs1}, exp_types = ETs1}.
+ {ETs0,UTs0,St0}, ETs) of
+ {ETs1,UTs1,St1} ->
+ St1#lint{usage = Usage#usage{used_types = UTs1}, exp_types = ETs1}
+ catch
+ error:_ ->
+ add_error(Line, {bad_export_type, ETs}, St0)
+ end.
-type import() :: {module(), [fa()]} | module().
-spec import(line(), import(), lint_state()) -> lint_state().
diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl
index 431e5b114e..c669c1f7c1 100644
--- a/lib/stdlib/src/lists.erl
+++ b/lib/stdlib/src/lists.erl
@@ -358,7 +358,7 @@ merge(L) ->
%% merge3(X, Y, Z) -> L
%% merges three sorted lists X, Y and Z
--spec merge3([_], [_], [_]) -> [_].
+-spec merge3([X], [Y], [Z]) -> [(X | Y | Z)].
merge3(L1, [], L3) ->
merge(L1, L3);
@@ -370,7 +370,7 @@ merge3(L1, [H2 | T2], [H3 | T3]) ->
%% rmerge3(X, Y, Z) -> L
%% merges three reversed sorted lists X, Y and Z
--spec rmerge3([_], [_], [_]) -> [_].
+-spec rmerge3([X], [Y], [Z]) -> [(X | Y | Z)].
rmerge3(L1, [], L3) ->
rmerge(L1, L3);
@@ -382,7 +382,7 @@ rmerge3(L1, [H2 | T2], [H3 | T3]) ->
%% merge(X, Y) -> L
%% merges two sorted lists X and Y
--spec merge([_], [_]) -> [_].
+-spec merge([X], [Y]) -> [(X | Y)].
merge(T1, []) ->
T1;
@@ -394,7 +394,7 @@ merge(T1, [H2 | T2]) ->
%% reverse(rmerge(reverse(A),reverse(B))) is equal to merge(I,A,B).
--spec rmerge([_], [_]) -> [_].
+-spec rmerge([X], [Y]) -> [(X | Y)].
rmerge(T1, []) ->
T1;
@@ -420,12 +420,12 @@ thing_to_list(X) when is_list(X) -> X. %Assumed to be a string
%% flatten(List, Tail)
%% Flatten a list, adding optional tail.
--spec flatten([_]) -> [_].
+-spec flatten([term()]) -> [term()].
flatten(List) when is_list(List) ->
do_flatten(List, []).
--spec flatten([_], [_]) -> [_].
+-spec flatten([term()], [term()]) -> [term()].
flatten(List, Tail) when is_list(List), is_list(Tail) ->
do_flatten(List, Tail).
@@ -440,7 +440,7 @@ do_flatten([], Tail) ->
%% flatlength(List)
%% Calculate the length of a list of lists.
--spec flatlength([_]) -> non_neg_integer().
+-spec flatlength([term()]) -> non_neg_integer().
flatlength(List) ->
flatlength(List, 0).
@@ -481,7 +481,7 @@ flatlength([], L) -> L.
% keysearch3(Key, N, T);
%keysearch3(Key, N, []) -> false.
--spec keydelete(_, pos_integer(), [T]) -> [T].
+-spec keydelete(term(), pos_integer(), [T]) -> [T] when T :: tuple().
keydelete(K, N, L) when is_integer(N), N > 0 ->
keydelete3(K, N, L).
@@ -491,7 +491,7 @@ keydelete3(Key, N, [H|T]) ->
[H|keydelete3(Key, N, T)];
keydelete3(_, _, []) -> [].
--spec keyreplace(_, pos_integer(), [_], tuple()) -> [_].
+-spec keyreplace(term(), pos_integer(), [tuple()], tuple()) -> [tuple()].
keyreplace(K, N, L, New) when is_integer(N), N > 0, is_tuple(New) ->
keyreplace3(K, N, L, New).
@@ -502,7 +502,8 @@ keyreplace3(Key, Pos, [H|T], New) ->
[H|keyreplace3(Key, Pos, T, New)];
keyreplace3(_, _, [], _) -> [].
--spec keytake(_, pos_integer(), [_]) -> {'value', tuple(), [_]} | 'false'.
+-spec keytake(term(), pos_integer(), [tuple()]) ->
+ {'value', tuple(), [tuple()]} | 'false'.
keytake(Key, N, L) when is_integer(N), N > 0 ->
keytake(Key, N, L, []).
@@ -513,7 +514,8 @@ keytake(Key, N, [H|T], L) ->
keytake(Key, N, T, [H|L]);
keytake(_K, _N, [], _L) -> false.
--spec keystore(_, pos_integer(), [_], tuple()) -> [_].
+-spec keystore(term(), pos_integer(), [tuple()], tuple()) -> [tuple(),...].
+
keystore(K, N, L, New) when is_integer(N), N > 0, is_tuple(New) ->
keystore2(K, N, L, New).
@@ -524,7 +526,7 @@ keystore2(Key, N, [H|T], New) ->
keystore2(_Key, _N, [], New) ->
[New].
--spec keysort(pos_integer(), [T]) -> [T] when is_subtype(T, tuple()).
+-spec keysort(pos_integer(), [T]) -> [T] when T :: tuple().
keysort(I, L) when is_integer(I), I > 0 ->
case L of
@@ -582,7 +584,7 @@ keysort_1(_I, X, _EX, [], R) ->
lists:reverse(R, [X]).
-spec keymerge(pos_integer(), [X], [Y]) ->
- [R] when is_subtype(X, tuple()), is_subtype(Y, tuple()), is_subtype(R, tuple()).
+ [R] when X :: tuple(), Y :: tuple(), R :: tuple().
keymerge(Index, T1, L2) when is_integer(Index), Index > 0 ->
case L2 of
@@ -597,7 +599,7 @@ keymerge(Index, T1, L2) when is_integer(Index), Index > 0 ->
%% reverse(rkeymerge(I,reverse(A),reverse(B))) is equal to keymerge(I,A,B).
-spec rkeymerge(pos_integer(), [X], [Y]) ->
- [R] when is_subtype(X, tuple()), is_subtype(Y, tuple()), is_subtype(R, tuple()).
+ [R] when X :: tuple(), Y :: tuple(), R :: tuple().
rkeymerge(Index, T1, L2) when is_integer(Index), Index > 0 ->
case L2 of
@@ -609,7 +611,7 @@ rkeymerge(Index, T1, L2) when is_integer(Index), Index > 0 ->
lists:reverse(M, [])
end.
--spec ukeysort(pos_integer(), [T]) -> [T] when is_subtype(T, tuple()).
+-spec ukeysort(pos_integer(), [T]) -> [T] when T :: tuple().
ukeysort(I, L) when is_integer(I), I > 0 ->
case L of
@@ -675,7 +677,7 @@ ukeysort_1(_I, X, _EX, []) ->
[X].
-spec ukeymerge(pos_integer(), [X], [Y]) ->
- [(X | Y)] when is_subtype(X, tuple()), is_subtype(Y, tuple()).
+ [(X | Y)] when X :: tuple(), Y :: tuple().
ukeymerge(Index, L1, T2) when is_integer(Index), Index > 0 ->
case L1 of
@@ -690,7 +692,7 @@ ukeymerge(Index, L1, T2) when is_integer(Index), Index > 0 ->
%% reverse(rukeymerge(I,reverse(A),reverse(B))) is equal to ukeymerge(I,A,B).
-spec rukeymerge(pos_integer(), [X], [Y]) ->
- [(X | Y)] when is_subtype(X, tuple()), is_subtype(Y, tuple()).
+ [(X | Y)] when X :: tuple(), Y :: tuple().
rukeymerge(Index, T1, L2) when is_integer(Index), Index > 0 ->
case L2 of
@@ -702,7 +704,7 @@ rukeymerge(Index, T1, L2) when is_integer(Index), Index > 0 ->
lists:reverse(M, [])
end.
--spec keymap(fun((_) -> _), pos_integer(), [tuple()]) -> [tuple()].
+-spec keymap(fun((term()) -> term()), pos_integer(), [tuple()]) -> [tuple()].
keymap(Fun, Index, [Tup|Tail]) ->
[setelement(Index, Tup, Fun(element(Index, Tup)))|keymap(Fun, Index, Tail)];
@@ -725,7 +727,7 @@ sort(Fun, [X, Y | T]) ->
fsplit_2(Y, X, Fun, T, [], [])
end.
--spec merge(fun((X, Y) -> boolean()), [X], [Y]) -> [_].
+-spec merge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)].
merge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) ->
lists:reverse(fmerge2_1(T1, H2, Fun, T2, []), []);
@@ -734,7 +736,7 @@ merge(Fun, T1, []) when is_function(Fun, 2) ->
%% reverse(rmerge(F,reverse(A),reverse(B))) is equal to merge(F,A,B).
--spec rmerge(fun((X, Y) -> boolean()), [X], [Y]) -> [_].
+-spec rmerge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)].
rmerge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) ->
lists:reverse(rfmerge2_1(T1, H2, Fun, T2, []), []);
@@ -768,7 +770,7 @@ usort_1(Fun, X, [Y | L]) ->
ufsplit_2(Y, L, Fun, [X])
end.
--spec umerge(fun((X, Y) -> boolean()), [X], [Y]) -> [_].
+-spec umerge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)].
umerge(Fun, [], T2) when is_function(Fun, 2) ->
T2;
@@ -777,7 +779,7 @@ umerge(Fun, [H1 | T1], T2) when is_function(Fun, 2) ->
%% reverse(rumerge(F,reverse(A),reverse(B))) is equal to umerge(F,A,B).
--spec rumerge(fun((X, Y) -> boolean()), [X], [Y]) -> [_].
+-spec rumerge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)].
rumerge(Fun, T1, []) when is_function(Fun, 2) ->
T1;
@@ -851,7 +853,7 @@ umerge(L) ->
%% merges three sorted lists X, Y and Z without duplicates,
%% removes duplicates
--spec umerge3([_], [_], [_]) -> [_].
+-spec umerge3([X], [Y], [Z]) -> [(X | Y | Z)].
umerge3(L1, [], L3) ->
umerge(L1, L3);
@@ -864,7 +866,7 @@ umerge3(L1, [H2 | T2], [H3 | T3]) ->
%% merges three reversed sorted lists X, Y and Z without duplicates,
%% removes duplicates
--spec rumerge3([_], [_], [_]) -> [_].
+-spec rumerge3([X], [Y], [Z]) -> [(X | Y | Z)].
rumerge3(L1, [], L3) ->
rumerge(L1, L3);
@@ -876,7 +878,7 @@ rumerge3(L1, [H2 | T2], [H3 | T3]) ->
%% umerge(X, Y) -> L
%% merges two sorted lists X and Y without duplicates, removes duplicates
--spec umerge([_], [_]) -> [_].
+-spec umerge([X], [Y]) -> [(X | Y)].
umerge([], T2) ->
T2;
@@ -889,7 +891,7 @@ umerge([H1 | T1], T2) ->
%% reverse(rumerge(reverse(A),reverse(B))) is equal to umerge(I,A,B).
--spec rumerge([_], [_]) -> [_].
+-spec rumerge([X], [Y]) -> [(X | Y)].
rumerge(T1, []) ->
T1;
@@ -952,13 +954,13 @@ flatmap(F, [Hd|Tail]) ->
F(Hd) ++ flatmap(F, Tail);
flatmap(F, []) when is_function(F, 1) -> [].
--spec foldl(fun((T, _) -> _), _, [T]) -> _.
+-spec foldl(fun((T, term()) -> term()), term(), [T]) -> term().
foldl(F, Accu, [Hd|Tail]) ->
foldl(F, F(Hd, Accu), Tail);
foldl(F, Accu, []) when is_function(F, 2) -> Accu.
--spec foldr(fun((T, _) -> _), _, [T]) -> _.
+-spec foldr(fun((T, term()) -> term()), term(), [T]) -> term().
foldr(F, Accu, [Hd|Tail]) ->
F(Hd, foldr(F, Accu, Tail));
@@ -998,14 +1000,14 @@ zf(F, [Hd|Tail]) ->
end;
zf(F, []) when is_function(F, 1) -> [].
--spec foreach(F :: fun((T) -> _), List :: [T]) -> 'ok'.
+-spec foreach(F :: fun((T) -> term()), List :: [T]) -> 'ok'.
foreach(F, [Hd|Tail]) ->
F(Hd),
foreach(F, Tail);
foreach(F, []) when is_function(F, 1) -> ok.
--spec mapfoldl(fun((T, _) -> {_, _}), _, [T]) -> {[_], _}.
+-spec mapfoldl(fun((A, term()) -> {B, term()}), term(), [A]) -> {[B], term()}.
mapfoldl(F, Accu0, [Hd|Tail]) ->
{R,Accu1} = F(Hd, Accu0),
@@ -1013,7 +1015,7 @@ mapfoldl(F, Accu0, [Hd|Tail]) ->
{[R|Rs],Accu2};
mapfoldl(F, Accu, []) when is_function(F, 2) -> {[],Accu}.
--spec mapfoldr(fun((T, _) -> {_, _}), _, [T]) -> {[_], _}.
+-spec mapfoldr(fun((A, term()) -> {B, term()}), term(), [A]) -> {[B], term()}.
mapfoldr(F, Accu0, [Hd|Tail]) ->
{Rs,Accu1} = mapfoldr(F, Accu0, Tail),
diff --git a/lib/stdlib/src/ordsets.erl b/lib/stdlib/src/ordsets.erl
index e992b66714..4c72e351d0 100644
--- a/lib/stdlib/src/ordsets.erl
+++ b/lib/stdlib/src/ordsets.erl
@@ -26,12 +26,14 @@
-export([subtract/2,is_subset/2]).
-export([fold/3,filter/2]).
+-export_type([ordset/1]).
+
-type ordset(T) :: [T].
%% new() -> Set.
%% Return a new empty ordered set.
--spec new() -> ordset(term()).
+-spec new() -> [].
new() -> [].
@@ -84,7 +86,7 @@ is_element(_, []) -> false.
%% add_element(Element, OrdSet) -> OrdSet.
%% Return OrdSet with Element inserted in it.
--spec add_element(term(), ordset(_)) -> ordset(_).
+-spec add_element(E, ordset(T)) -> [T | E,...].
add_element(E, [H|Es]) when E > H -> [H|add_element(E, Es)];
add_element(E, [H|_]=Set) when E < H -> [E|Set];
@@ -94,7 +96,7 @@ add_element(E, []) -> [E].
%% del_element(Element, OrdSet) -> OrdSet.
%% Return OrdSet but with Element removed.
--spec del_element(term(), ordset(_)) -> ordset(_).
+-spec del_element(term(), ordset(T)) -> ordset(T).
del_element(E, [H|Es]) when E > H -> [H|del_element(E, Es)];
del_element(E, [H|_]=Set) when E < H -> Set;
@@ -104,7 +106,7 @@ del_element(_, []) -> [].
%% union(OrdSet1, OrdSet2) -> OrdSet
%% Return the union of OrdSet1 and OrdSet2.
--spec union(ordset(_), ordset(_)) -> ordset(_).
+-spec union(ordset(T1), ordset(T2)) -> ordset(T1 | T2).
union([E1|Es1], [E2|_]=Set2) when E1 < E2 ->
[E1|union(Es1, Set2)];
@@ -118,7 +120,7 @@ union(Es1, []) -> Es1.
%% union([OrdSet]) -> OrdSet
%% Return the union of the list of ordered sets.
--spec union([ordset(_)]) -> ordset(_).
+-spec union([ordset(T)]) -> ordset(T).
union([S1,S2|Ss]) ->
union1(union(S1, S2), Ss);
@@ -206,7 +208,7 @@ is_subset(_, []) -> false.
%% fold(Fun, Accumulator, OrdSet) -> Accumulator.
%% Fold function Fun over all elements in OrdSet and return Accumulator.
--spec fold(fun((_, _) -> _), _, ordset(_)) -> _.
+-spec fold(fun((T, term()) -> term()), term(), ordset(T)) -> term().
fold(F, Acc, Set) ->
lists:foldl(F, Acc, Set).
@@ -214,7 +216,7 @@ fold(F, Acc, Set) ->
%% filter(Fun, OrdSet) -> OrdSet.
%% Filter OrdSet with Fun.
--spec filter(fun((_) -> boolean()), ordset(_)) -> ordset(_).
+-spec filter(fun((T) -> boolean()), ordset(T)) -> ordset(T).
filter(F, Set) ->
lists:filter(F, Set).
diff --git a/lib/stdlib/src/string.erl b/lib/stdlib/src/string.erl
index 6636a03f06..c987c224db 100644
--- a/lib/stdlib/src/string.erl
+++ b/lib/stdlib/src/string.erl
@@ -201,7 +201,7 @@ chars(C, 0, Tail) when is_integer(C) ->
-spec copies(string(), non_neg_integer()) -> string().
-copies(CharList, Num) when is_list(CharList), Num >= 0 ->
+copies(CharList, Num) when is_list(CharList), is_integer(Num), Num >= 0 ->
copies(CharList, Num, []).
copies(_CharList, 0, R) ->
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index f5d5441184..5bdd1a8672 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -33,7 +33,9 @@
-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]).
-export([handle_cast/2]).
--export_type([child_spec/0, strategy/0]).
+%%--------------------------------------------------------------------------
+
+-export_type([child_spec/0, del_err/0, startchild_ret/0, strategy/0]).
%%--------------------------------------------------------------------------
@@ -77,6 +79,10 @@
-define(is_simple(State), State#state.strategy =:= simple_one_for_one).
+%%--------------------------------------------------------------------------
+
+-spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}].
+
behaviour_info(callbacks) ->
[{init,1}];
behaviour_info(_Other) ->
@@ -160,11 +166,13 @@ check_childspecs(X) -> {error, {badarg, X}}.
%%%
%%% ---------------------------------------------------
+-type init_sup_name() :: sup_name() | 'self'.
+
-type stop_rsn() :: 'shutdown' | {'bad_return', {module(),'init', term()}}
| {'bad_start_spec', term()} | {'start_spec', term()}
| {'supervisor_data', term()}.
--spec init({sup_name(), module(), [term()]}) ->
+-spec init({init_sup_name(), module(), [term()]}) ->
{'ok', state()} | 'ignore' | {'stop', stop_rsn()}.
init({SupName, Mod, Args}) ->
@@ -184,7 +192,7 @@ init({SupName, Mod, Args}) ->
Error ->
{stop, {bad_return, {Mod, init, Error}}}
end.
-
+
init_children(State, StartSpec) ->
SupName = State#state.name,
case check_startspec(StartSpec) of
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index 760e610e00..8b18ef5664 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2010. 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
@@ -50,7 +50,8 @@
otp_4208/1, otp_4989/1, many_clients/1, otp_4906/1, otp_5402/1,
simultaneous_open/1, insert_new/1, repair_continuation/1,
otp_5487/1, otp_6206/1, otp_6359/1, otp_4738/1, otp_7146/1,
- otp_8070/1]).
+ otp_8070/1, otp_8856/1, otp_8898/1, otp_8899/1, otp_8903/1,
+ otp_8923/1]).
-export([dets_dirty_loop/0]).
@@ -108,7 +109,8 @@ all(suite) ->
cache_duplicate_bags_v9, otp_4208, otp_4989, many_clients,
otp_4906, otp_5402, simultaneous_open, insert_new,
repair_continuation, otp_5487, otp_6206, otp_6359, otp_4738,
- otp_7146, otp_8070]}
+ otp_7146, otp_8070, otp_8856, otp_8898, otp_8899, otp_8903,
+ otp_8923]}
end.
not_run(suite) -> [];
@@ -2935,6 +2937,57 @@ ets_init(Tab, N) ->
ets:insert(Tab, {N,N}),
ets_init(Tab, N - 1).
+otp_8898(doc) ->
+ ["OTP-8898. Truncated Dets file."];
+otp_8898(suite) ->
+ [];
+otp_8898(Config) when is_list(Config) ->
+ Tab = otp_8898,
+ ?line FName = filename(Tab, Config),
+
+ Server = self(),
+
+ ?line file:delete(FName),
+ ?line {ok, _} = dets:open_file(Tab,[{file, FName}]),
+ ?line [P1,P2,P3] = new_clients(3, Tab),
+
+ Seq = [{P1,[sync]},{P2,[{lookup,1,[]}]},{P3,[{insert,{1,b}}]}],
+ ?line atomic_requests(Server, Tab, [[]], Seq),
+ ?line true = get_replies([{P1,ok},{P2,ok},{P3,ok}]),
+ ?line ok = dets:close(Tab),
+ ?line {ok, _} = dets:open_file(Tab,[{file, FName}]),
+ ?line file:delete(FName),
+
+ ok.
+
+otp_8899(doc) ->
+ ["OTP-8899. Several clients. Updated Head was ignored."];
+otp_8899(suite) ->
+ [];
+otp_8899(Config) when is_list(Config) ->
+ Tab = many_clients,
+ ?line FName = filename(Tab, Config),
+
+ Server = self(),
+
+ ?line file:delete(FName),
+ ?line {ok, _} = dets:open_file(Tab,[{file, FName},{version,9}]),
+ ?line [P1,P2,P3,P4] = new_clients(4, Tab),
+
+ MC = [Tab],
+ Seq6a = [{P1,[{insert,[{used_to_be_skipped_by,match}]},
+ {lookup,1,[{1,a}]}]},
+ {P2,[{verbose,true,MC}]},
+ {P3,[{lookup,1,[{1,a}]}]}, {P4,[{verbose,true,MC}]}],
+ ?line atomic_requests(Server, Tab, [[{1,a},{2,b},{3,c}]], Seq6a),
+ ?line true = get_replies([{P1,ok}, {P2,ok}, {P3,ok}, {P4,ok}]),
+ ?line [{1,a},{2,b},{3,c},{used_to_be_skipped_by,match}] =
+ lists:sort(dets:match_object(Tab, '_')),
+ ?line _ = dets:close(Tab),
+ ?line file:delete(FName),
+
+ ok.
+
many_clients(doc) ->
["Several clients accessing a table simultaneously."];
many_clients(suite) ->
@@ -3071,6 +3124,11 @@ client(S, Tab) ->
eval([], _Tab) ->
ok;
+eval([{verbose,Bool,Expected} | L], Tab) ->
+ ?line case dets:verbose(Bool) of
+ Expected -> eval(L, Tab);
+ Error -> {error, {verbose,Error}}
+ end;
eval([sync | L], Tab) ->
?line case dets:sync(Tab) of
ok -> eval(L, Tab);
@@ -3701,6 +3759,87 @@ otp_8070(Config) when is_list(Config) ->
file:delete(File),
ok.
+otp_8856(doc) ->
+ ["OTP-8856. insert_new() bug."];
+otp_8856(suite) ->
+ [];
+otp_8856(Config) when is_list(Config) ->
+ Tab = otp_8856,
+ File = filename(Tab, Config),
+ file:delete(File),
+ Me = self(),
+ ?line {ok, _} = dets:open_file(Tab, [{type, bag}, {file, File}]),
+ spawn(fun()-> Me ! {1, dets:insert(Tab, [])} end),
+ spawn(fun()-> Me ! {2, dets:insert_new(Tab, [])} end),
+ ?line ok = dets:close(Tab),
+ ?line receive {1, ok} -> ok end,
+ ?line receive {2, true} -> ok end,
+ file:delete(File),
+
+ ?line {ok, _} = dets:open_file(Tab, [{type, set}, {file, File}]),
+ spawn(fun() -> dets:delete(Tab, 0) end),
+ spawn(fun() -> Me ! {3, dets:insert_new(Tab, {0,0})} end),
+ ?line ok = dets:close(Tab),
+ ?line receive {3, true} -> ok end,
+ file:delete(File),
+ ok.
+
+otp_8903(doc) ->
+ ["OTP-8903. bchunk/match/select bug."];
+otp_8903(suite) ->
+ [];
+otp_8903(Config) when is_list(Config) ->
+ Tab = otp_8903,
+ File = filename(Tab, Config),
+ ?line {ok,T} = dets:open_file(bug, [{file,File}]),
+ ?line ok = dets:insert(T, [{1,a},{2,b},{3,c}]),
+ ?line dets:safe_fixtable(T, true),
+ ?line {[_],C1} = dets:match_object(T, '_', 1),
+ ?line {BC1,_D} = dets:bchunk(T, start),
+ ?line ok = dets:close(T),
+ ?line {'EXIT', {badarg, _}} = (catch {foo,dets:match_object(C1)}),
+ ?line {'EXIT', {badarg, _}} = (catch {foo,dets:bchunk(T, BC1)}),
+ ?line {ok,T} = dets:open_file(bug, [{file,File}]),
+ ?line false = dets:info(T, safe_fixed),
+ ?line {'EXIT', {badarg, _}} = (catch {foo,dets:match_object(C1)}),
+ ?line {'EXIT', {badarg, _}} = (catch {foo,dets:bchunk(T, BC1)}),
+ ?line ok = dets:close(T),
+ file:delete(File),
+ ok.
+
+otp_8923(doc) ->
+ ["OTP-8923. rehash due to lookup after initialization."];
+otp_8923(suite) ->
+ [];
+otp_8923(Config) when is_list(Config) ->
+ Tab = otp_8923,
+ File = filename(Tab, Config),
+ %% Create a file with more than 256 keys:
+ file:delete(File),
+ Bin = list_to_binary([ 0 || _ <- lists:seq(1, 400) ]),
+ BigBin = list_to_binary([ 0 ||_ <- lists:seq(1, 4000)]),
+ Ets = ets:new(temp, [{keypos,1}]),
+ ?line [ true = ets:insert(Ets, {C,Bin}) || C <- lists:seq(1, 700) ],
+ ?line true = ets:insert(Ets, {helper_data,BigBin}),
+ ?line true = ets:insert(Ets, {prim_btree,BigBin}),
+ ?line true = ets:insert(Ets, {sec_btree,BigBin}),
+ %% Note: too few slots; re-hash will take place
+ ?line {ok, Tab} = dets:open_file(Tab, [{file,File}]),
+ ?line Tab = ets:to_dets(Ets, Tab),
+ ?line ok = dets:close(Tab),
+ ?line true = ets:delete(Ets),
+
+ ?line {ok,Ref} = dets:open_file(File),
+ ?line [{1,_}] = dets:lookup(Ref, 1),
+ ?line ok = dets:close(Ref),
+
+ ?line {ok,Ref2} = dets:open_file(File),
+ ?line [{helper_data,_}] = dets:lookup(Ref2, helper_data),
+ ?line ok = dets:close(Ref2),
+
+ file:delete(File),
+ ok.
+
%%
%% Parts common to several test cases
%%
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index e31dfdd764..e9fb932632 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -24,7 +24,7 @@
variable/1, variable_1/1, otp_4870/1, otp_4871/1, otp_5362/1,
pmod/1, not_circular/1, skip_header/1, otp_6277/1, otp_7702/1,
otp_8130/1, overload_mac/1, otp_8388/1, otp_8470/1, otp_8503/1,
- otp_8562/1, otp_8665/1]).
+ otp_8562/1, otp_8665/1, otp_8911/1]).
-export([epp_parse_erl_form/2]).
@@ -64,7 +64,7 @@ all(doc) ->
all(suite) ->
[rec_1, upcase_mac, predef_mac, variable, otp_4870, otp_4871, otp_5362,
pmod, not_circular, skip_header, otp_6277, otp_7702, otp_8130,
- overload_mac, otp_8388, otp_8470, otp_8503, otp_8562, otp_8665].
+ overload_mac, otp_8388, otp_8470, otp_8503, otp_8562, otp_8665, otp_8911].
rec_1(doc) ->
["Recursive macros hang or crash epp (OTP-1398)."];
@@ -1197,6 +1197,40 @@ otp_8562(Config) when is_list(Config) ->
?line [] = compile(Config, Cs),
ok.
+otp_8911(doc) ->
+ ["OTP-8911. -file and file inclusion bug"];
+otp_8911(suite) ->
+ [];
+otp_8911(Config) when is_list(Config) ->
+ ?line {ok, CWD} = file:get_cwd(),
+ ?line ok = file:set_cwd(?config(priv_dir, Config)),
+
+ File = "i.erl",
+ Cont = <<"-module(i).
+ -compile(export_all).
+ -file(\"fil1\", 100).
+ -include(\"i1.erl\").
+ t() ->
+ a.
+ ">>,
+ ?line ok = file:write_file(File, Cont),
+ Incl = <<"-file(\"fil2\", 35).
+ t1() ->
+ b.
+ ">>,
+ File1 = "i1.erl",
+ ?line ok = file:write_file(File1, Incl),
+
+ ?line {ok, i} = cover:compile(File),
+ ?line a = i:t(),
+ ?line {ok,[{{i,6},1}]} = cover:analyse(i, calls, line),
+ ?line cover:stop(),
+
+ file:delete(File),
+ file:delete(File1),
+ ?line file:set_cwd(CWD),
+ ok.
+
otp_8665(doc) ->
["OTP-8665. Bugfix premature end."];
otp_8665(suite) ->
diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl
index 77fd190e45..162ca6006f 100644
--- a/lib/stdlib/test/escript_SUITE.erl
+++ b/lib/stdlib/test/escript_SUITE.erl
@@ -31,6 +31,7 @@
epp/1,
create_and_extract/1,
foldl/1,
+ overflow/1,
verify_sections/3
]).
@@ -48,7 +49,8 @@ all(suite) ->
archive_script,
epp,
create_and_extract,
- foldl
+ foldl,
+ overflow
].
init_per_testcase(_Case, Config) ->
@@ -736,6 +738,17 @@ emulate_escript_foldl(Fun, Acc, File) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+overflow(Config) when is_list(Config) ->
+ Data = ?config(data_dir, Config),
+ Dir = filename:absname(Data), %Get rid of trailing slash.
+ ?line run(Dir, "arg_overflow",
+ [<<"ExitCode:0">>]),
+ ?line run(Dir, "linebuf_overflow",
+ [<<"ExitCode:0">>]),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
run(Dir, Cmd0, Expected0) ->
Expected = iolist_to_binary(expected_output(Expected0, Dir)),
Cmd = case os:type() of
diff --git a/lib/stdlib/test/escript_SUITE_data/arg_overflow b/lib/stdlib/test/escript_SUITE_data/arg_overflow
new file mode 100755
index 0000000000..dd5accc051
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/arg_overflow
@@ -0,0 +1,5 @@
+#! /usr/bin/env escript
+%% -*- erlang -*-
+%%!x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
+main(_) ->
+ halt(0).
diff --git a/lib/stdlib/test/escript_SUITE_data/linebuf_overflow b/lib/stdlib/test/escript_SUITE_data/linebuf_overflow
new file mode 100755
index 0000000000..33133c1ce9
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/linebuf_overflow
@@ -0,0 +1,5 @@
+#! /usr/bin/env escript
+%% -*- erlang -*-
+%%!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+main(_) ->
+ halt(0).
diff --git a/lib/stdlib/test/string_SUITE.erl b/lib/stdlib/test/string_SUITE.erl
index 3171b87c44..452e048dd7 100644
--- a/lib/stdlib/test/string_SUITE.erl
+++ b/lib/stdlib/test/string_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2010. 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
@@ -240,7 +240,8 @@ copies(Config) when is_list(Config) ->
?line "." = string:copies(".", 1),
?line 30 = length(string:copies("123", 10)),
%% invalid arg type
- ?line {'EXIT',_} = (catch string:chars("hej", -1)),
+ ?line {'EXIT',_} = (catch string:copies("hej", -1)),
+ ?line {'EXIT',_} = (catch string:copies("hej", 2.0)),
ok.
words(suite) ->
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index a40bf83c5a..9df5f26454 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -1818,7 +1818,7 @@ char_value(Node) ->
%%
%% @see char/1
--spec char_literal(syntaxTree()) -> string().
+-spec char_literal(syntaxTree()) -> nonempty_string().
char_literal(Node) ->
io_lib:write_char(char_value(Node)).
@@ -1908,7 +1908,7 @@ string_value(Node) ->
%%
%% @see string/1
--spec string_literal(syntaxTree()) -> string().
+-spec string_literal(syntaxTree()) -> nonempty_string().
string_literal(Node) ->
io_lib:write_string(string_value(Node)).
diff --git a/lib/syntax_tools/src/erl_syntax_lib.erl b/lib/syntax_tools/src/erl_syntax_lib.erl
index daef74e874..97dfbfd7cd 100644
--- a/lib/syntax_tools/src/erl_syntax_lib.erl
+++ b/lib/syntax_tools/src/erl_syntax_lib.erl
@@ -49,10 +49,6 @@
-export_type([info_pair/0]).
%% =====================================================================
-
--type ordset(X) :: [X]. % XXX: TAKE ME OUT
-
-%% =====================================================================
%% @spec map(Function, Tree::syntaxTree()) -> syntaxTree()
%%
%% Function = (syntaxTree()) -> syntaxTree()
@@ -480,7 +476,7 @@ new_variable_names(0, Names, _, _, _) ->
%% @see annotate_bindings/1
%% @see //stdlib/ordsets
--spec annotate_bindings(erl_syntax:syntaxTree(), ordset(atom())) ->
+-spec annotate_bindings(erl_syntax:syntaxTree(), ordsets:ordset(atom())) ->
erl_syntax:syntaxTree().
annotate_bindings(Tree, Env) ->
diff --git a/lib/syntax_tools/src/igor.erl b/lib/syntax_tools/src/igor.erl
index 7ec62f1dba..aa933eb54b 100644
--- a/lib/syntax_tools/src/igor.erl
+++ b/lib/syntax_tools/src/igor.erl
@@ -119,20 +119,16 @@
%% =====================================================================
--type ordset(X) :: [X]. % XXX: TAKE ME OUT
-
-%% =====================================================================
-
%% Data structure for module information
-record(module, {name :: atom(),
vars = none :: [atom()] | 'none',
- functions :: ordset({atom(), arity()}),
- exports :: ordset({atom(), arity()})
- | ordset({{atom(), arity()}, term()}),
- aliases :: ordset({{atom(), arity()},
- {atom(), {atom(), arity()}}}),
- attributes :: ordset({atom(), term()}),
+ functions :: ordsets:ordset({atom(), arity()}),
+ exports :: ordsets:ordset({atom(), arity()})
+ | ordsets:ordset({{atom(), arity()}, term()}),
+ aliases :: ordsets:ordset({{atom(), arity()},
+ {atom(), {atom(), arity()}}}),
+ attributes :: ordsets:ordset({atom(), term()}),
records :: [{atom(), [{atom(), term()}]}]
}).
@@ -149,7 +145,7 @@ default_printer(Tree, Options) ->
-type moduleName() :: atom().
-type functionName() :: {atom(), arity()}.
-type functionPair() :: {functionName(), {moduleName(), functionName()}}.
--type stubDescriptor() :: [{moduleName(), [functionPair()], [attribute()]}].
+-type stubDescriptor() :: {moduleName(), [functionPair()], [attribute()]}.
-type notes() :: 'always' | 'yes' | 'no'.
@@ -209,7 +205,7 @@ parse_transform(Forms, Options) ->
%% @spec merge(Name::atom(), Files::[filename()]) -> [filename()]
%% @equiv merge(Name, Files, [])
--spec merge(atom(), [file:filename()]) -> [file:filename()].
+-spec merge(atom(), [file:filename()]) -> [file:filename(),...].
merge(Name, Files) ->
merge(Name, Files, []).
@@ -343,7 +339,7 @@ merge(Name, Files) ->
{suffix, ?DEFAULT_SUFFIX},
{verbose, false}]).
--spec merge(atom(), [file:filename()], [option()]) -> [file:filename()].
+-spec merge(atom(), [file:filename()], [option()]) -> [file:filename(),...].
merge(Name, Files, Opts) ->
Opts1 = Opts ++ ?DEFAULT_MERGE_OPTS,
@@ -484,7 +480,7 @@ merge_files(Name, Trees, Files, Opts) ->
%%
%% Forms = syntaxTree() | [syntaxTree()]
%%
-%% @type stubDescriptor() = [{ModuleName, Functions, [Attribute]}]
+%% @type stubDescriptor() = {ModuleName, Functions, [Attribute]}
%% ModuleName = atom()
%% Functions = [{FunctionName, {ModuleName, FunctionName}}]
%% FunctionName = {atom(), integer()}
@@ -687,15 +683,15 @@ merge_files(Name, Trees, Files, Opts) ->
%% Data structure for merging environment.
-record(merge, {target :: atom(),
- sources :: ordset(atom()),
- export :: ordset(atom()),
- static :: ordset(atom()),
- safe :: ordset(atom()),
+ sources :: ordsets:ordset(atom()),
+ export :: ordsets:ordset(atom()),
+ static :: ordsets:ordset(atom()),
+ safe :: ordsets:ordset(atom()),
preserved :: boolean(),
no_headers :: boolean(),
notes :: notes(),
redirect :: dict(), % = dict(atom(), atom())
- no_imports :: ordset(atom()),
+ no_imports :: ordsets:ordset(atom()),
options :: [option()]
}).
diff --git a/lib/wx/configure.in b/lib/wx/configure.in
index 855c0c975e..8f8c5ee123 100755
--- a/lib/wx/configure.in
+++ b/lib/wx/configure.in
@@ -194,6 +194,36 @@ case $host_os in
;;
esac
+dnl
+dnl Opengl tests
+dnl
+
+if test X"$host_os" != X"win32" ; then
+ AC_CHECK_HEADERS([GL/gl.h], [],
+ [AC_CHECK_HEADERS([OpenGL/gl.h])])
+ if test X"$ac_cv_header_GL_gl_h" != Xyes &&
+ test X"$ac_cv_header_OpenGL_gl_h" != Xyes
+ then
+ saved_CPPFLAGS="$CPPFLAGS"
+ AC_MSG_NOTICE(Checking for OpenGL headers in /usr/X11R6)
+ CPPFLAGS="-isystem /usr/X11R6/include $CPPFLAGS"
+ $as_unset ac_cv_header_GL_gl_h
+ AC_CHECK_HEADERS([GL/gl.h])
+ if test X"$ac_cv_header_GL_gl_h" != Xyes ; then
+ AC_MSG_NOTICE(Checking for OpenGL headers in /usr/local)
+ CPPFLAGS="-isystem /usr/local/include $saved_CPPFLAGS"
+ $as_unset ac_cv_header_GL_gl_h
+ AC_CHECK_HEADERS([GL/gl.h])
+ if test X"$ac_cv_header_GL_gl_h" != Xyes ; then
+ AC_MSG_WARN([No OpenGL headers found, wx will NOT be usable])
+ CPPFLAGS="$saved_CPPFLAGS"
+ fi
+ fi
+ fi
+else
+ AC_CHECK_HEADERS([gl/gl.h],[],[],[#include <windows.h>])
+fi
+
CXXFLAGS="$CFLAGS $CPPFLAGS"
CFLAGS="$CFLAGS $CPPFLAGS $C_ONLY_FLAGS"
@@ -386,17 +416,6 @@ if test "$WXERL_CAN_BUILD_DRIVER" != "false"; then
AC_SUBST(WX_HAVE_STATIC_LIBS)
AC_SUBST(RC_FILE_TYPE)
-dnl
-dnl Opengl tests
-dnl
-
-if test X"$host_os" != X"win32" ; then
- AC_CHECK_HEADERS([GL/gl.h])
- AC_CHECK_HEADERS([OpenGL/gl.h])
-else
- AC_CHECK_HEADERS([gl/gl.h],[],[],[#include <windows.h>])
-fi
-
AC_MSG_CHECKING(if wxwidgets have opengl support)
AC_LANG_PUSH(C++)
saved_CXXFLAGS=$CXXFLAGS