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/compiler/src/beam_block.erl35
-rw-r--r--lib/compiler/src/cerl.erl6
-rw-r--r--lib/compiler/src/core_lint.erl3
-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/dialyzer/doc/src/dialyzer.xml10
-rw-r--r--lib/dialyzer/src/dialyzer_races.erl38
-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/hipe/cerl/erl_types.erl63
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl4
-rw-r--r--lib/kernel/doc/src/notes.xml23
-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/public_key/src/pubkey_cert.erl2
-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.erl54
-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.hrl2
-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/src/dets.erl111
-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.erl110
-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
53 files changed, 2146 insertions, 781 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/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 097577b371..b513a8965c 100644
--- a/lib/compiler/src/core_lint.erl
+++ b/lib/compiler/src/core_lint.erl
@@ -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()}.
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/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml
index 1ec2ce830a..b977a44913 100644
--- a/lib/dialyzer/doc/src/dialyzer.xml
+++ b/lib/dialyzer/doc/src/dialyzer.xml
@@ -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/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/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 9bc56c99ff..4dd124a457 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,
@@ -2388,9 +2391,9 @@ inf_tuple_sets([{Arity, Tuples1}|Left1], [{Arity, Tuples2}|Left2], Acc, Mode) ->
[] -> inf_tuple_sets(Left1, Left2, Acc, Mode);
NewTuples -> inf_tuple_sets(Left1, Left2, [{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 +2409,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).
@@ -2791,13 +2794,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(_, _)) ->
@@ -3634,7 +3637,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 +3658,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 +3701,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 +3719,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 +3727,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 +3948,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/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/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/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/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..9824e17fcd 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).
@@ -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..d2dee4d861 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -104,7 +104,7 @@
-type tls_atom_version() :: sslv3 | tlsv1.
-type cache_ref() :: term().
-type certdb_ref() :: term().
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss.
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon.
-type enum_algo() :: integer().
-type public_key() :: #'RSAPublicKey'{} | integer().
-type public_key_params() :: #'Dss-Parms'{} | term().
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/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/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..a1f70dc27d 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,7 @@
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]).
-export([dets_dirty_loop/0]).
@@ -108,7 +108,7 @@ 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]}
end.
not_run(suite) -> [];
@@ -2935,6 +2935,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 +3122,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 +3757,54 @@ 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.
+
%%
%% 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()]
}).