diff options
Diffstat (limited to 'lib/stdlib')
-rw-r--r-- | lib/stdlib/doc/src/unicode_usage.xml | 8 | ||||
-rw-r--r-- | lib/stdlib/src/Makefile | 1 | ||||
-rw-r--r-- | lib/stdlib/src/erl_lint.erl | 5 | ||||
-rw-r--r-- | lib/stdlib/src/escript.erl | 18 | ||||
-rw-r--r-- | lib/stdlib/src/filename.erl | 2 | ||||
-rw-r--r-- | lib/stdlib/src/gen_server.erl | 2 | ||||
-rw-r--r-- | lib/stdlib/test/erl_lint_SUITE.erl | 25 | ||||
-rw-r--r-- | lib/stdlib/test/escript_SUITE.erl | 149 | ||||
-rw-r--r-- | lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl | 17 | ||||
-rw-r--r-- | lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl | 105 | ||||
-rw-r--r-- | lib/stdlib/test/ets_SUITE.erl | 18 | ||||
-rw-r--r-- | lib/stdlib/test/filename_SUITE.erl | 15 | ||||
-rw-r--r-- | lib/stdlib/test/gen_server_SUITE.erl | 22 | ||||
-rw-r--r-- | lib/stdlib/test/qlc_SUITE.erl | 8 |
14 files changed, 370 insertions, 25 deletions
diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml index a7e010a05f..b7b5d497d0 100644 --- a/lib/stdlib/doc/src/unicode_usage.xml +++ b/lib/stdlib/doc/src/unicode_usage.xml @@ -53,7 +53,7 @@ <item>Basically the same as UTF-32, but without some Unicode semantics, defined by IEEE and has little use as a separate encoding standard. For all normal (and possibly abnormal) usages, UTF-32 and UCS-4 are interchangeable.</item> </taglist> <p>Certain ranges of characters are left unused and certain ranges are even deemed invalid. The most notable invalid range is 16#D800 - 16#DFFF, as the UTF-16 encoding does not allow for encoding of these numbers. It can be speculated that the UTF-16 encoding standard was, from the beginning, expected to be able to hold all Unicode characters in one 16-bit entity, but then had to be extended, leaving a hole in the Unicode range to cope with backward compatibility.</p> -<p>Additionally, the codepoint 16#FEFF is used for byte order marks (BOM's) and use of that character is not encouraged in other contexts than that. It actually is valid though, as the character "ZWNBS" (Zero Width Non Breaking Space). BOM's are used to identify encodings and byte order for programs where such parameters are not known in advance. Byte order marks are more seldom used than one could expect, put their use is becoming more widely spread as they provide the means for programs to make educated guesses about the Unicode format of a certain file.</p> +<p>Additionally, the codepoint 16#FEFF is used for byte order marks (BOM's) and use of that character is not encouraged in other contexts than that. It actually is valid though, as the character "ZWNBS" (Zero Width Non Breaking Space). BOM's are used to identify encodings and byte order for programs where such parameters are not known in advance. Byte order marks are more seldom used than one could expect, but their use is becoming more widely spread as they provide the means for programs to make educated guesses about the Unicode format of a certain file.</p> </section> <section> <title>Standard Unicode representation in Erlang</title> @@ -210,6 +210,12 @@ Eshell V5.7 (abort with ^G) </section> </section> <section> +<title>Unicode in environment variables and parameters</title> +<p>Environment variables and their interpretation is handled much in the same way as file names. If Unicode file names are enabled, environment variables as well as parameters to the Erlang VM are expected to be in Unicode.</p> +<p>If Unicode file names are enabled, the calls to <seealso marker="kernel:os#os_getenv/0"><c>os:getenv/0</c></seealso>, <seealso marker="kernel:os#os_getenv/1"><c>os:getenv/1</c></seealso> and <seealso marker="kernel:os#os_putenv/2"><c>os:putenv/2</c></seealso> will handle Unicode strings. On Unix-like platforms, the built-in functions will translate environment variables in UTF-8 to/from Unicode strings, possibly with codepoints > 255. On Windows the Unicode versions of the environment system API will be used, also allowing for codepoints > 255.</p> +<p>On Unix-like operating systems, parameters are expected to be UTF-8 without translation if Unicode file names are enabled.</p> +</section> +<section> <title>Unicode-aware modules</title> <p>Most of the modules in Erlang/OTP are of course Unicode-unaware in the sense that they have no notion of Unicode and really shouldn't have. Typically they handle non-textual or byte-oriented data (like <c>gen_tcp</c> etc).</p> <p>Modules that actually handle textual data (like <c>io_lib</c>, <c>string</c> etc) are sometimes subject to conversion or extension to be able to handle Unicode characters.</p> diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile index 8bdaae57fd..54186a3ba7 100644 --- a/lib/stdlib/src/Makefile +++ b/lib/stdlib/src/Makefile @@ -167,6 +167,7 @@ docs: # This is a trick so that the preloaded files will get the correct type # specifications. primary_bootstrap_compiler: \ + $(BOOTSTRAP_COMPILER)/ebin/epp.beam \ $(BOOTSTRAP_COMPILER)/ebin/erl_scan.beam \ $(BOOTSTRAP_COMPILER)/ebin/erl_parse.beam \ $(BOOTSTRAP_COMPILER)/ebin/erl_lint.beam \ diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index abab81d31f..648ff349a4 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -248,6 +248,8 @@ format_error({illegal_guard_local_call, {F,A}}) -> io_lib:format("call to local/imported function ~w/~w is illegal in guard", [F,A]); format_error(illegal_guard_expr) -> "illegal guard expression"; +format_error(deprecated_tuple_fun) -> + "tuple funs are deprecated and will be removed in R16"; %% --- exports --- format_error({explicit_export,F,A}) -> io_lib:format("in this release, the call to ~w/~w must be written " @@ -1914,7 +1916,8 @@ gexpr({call,Line,{remote,_Lr,{atom,_Lm,erlang},{atom,_Lf,F}},As}, Vt, St0) -> true -> {Asvt,St1}; false -> {Asvt,add_error(Line, illegal_guard_expr, St1)} end; -gexpr({call,L,{tuple,Lt,[{atom,Lm,erlang},{atom,Lf,F}]},As}, Vt, St) -> +gexpr({call,L,{tuple,Lt,[{atom,Lm,erlang},{atom,Lf,F}]},As}, Vt, St0) -> + St = add_warning(L, deprecated_tuple_fun, St0), gexpr({call,L,{remote,Lt,{atom,Lm,erlang},{atom,Lf,F}},As}, Vt, St); gexpr({op,Line,Op,A}, Vt, St0) -> {Avt,St1} = gexpr(A, Vt, St0), diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl index 27e70ac4d4..498d850df3 100644 --- a/lib/stdlib/src/escript.erl +++ b/lib/stdlib/src/escript.erl @@ -22,7 +22,7 @@ -export([script_name/0, create/2, extract/2]). %% Internal API. --export([start/0, start/1]). +-export([start/0, start/1, parse_file/1]). %%----------------------------------------------------------------------- @@ -346,7 +346,8 @@ parse_and_run(File, Args, Options) -> case Source of archive -> {ok, FileInfo} = file:read_file_info(File), - case code:set_primary_archive(File, FormsOrBin, FileInfo) of + case code:set_primary_archive(File, FormsOrBin, FileInfo, + fun escript:parse_file/1) of ok when CheckOnly -> case code:load_file(Module) of {module, _} -> @@ -396,6 +397,19 @@ parse_and_run(File, Args, Options) -> %% Parse script %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Only used as callback by erl_prim_loader +parse_file(File) -> + try parse_file(File, false) of + {_Source, _Module, FormsOrBin, _HasRecs, _Mode} + when is_binary(FormsOrBin) -> + {ok, FormsOrBin}; + _ -> + {error, no_archive_bin} + catch + throw:Reason -> + {error, Reason} + end. + parse_file(File, CheckOnly) -> {HeaderSz, NextLineNo, Fd, Sections} = parse_header(File, false), diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl index dbfcbea4f7..870af4e95f 100644 --- a/lib/stdlib/src/filename.erl +++ b/lib/stdlib/src/filename.erl @@ -726,6 +726,8 @@ nativename(Name0) -> _ -> Name end. +win32_nativename(Name) when is_binary(Name) -> + binary:replace(Name, <<"/">>, <<"\\">>, [global]); win32_nativename([$/|Rest]) -> [$\\|win32_nativename(Rest)]; win32_nativename([C|Rest]) -> diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl index 59c6d240ba..04308a51b7 100644 --- a/lib/stdlib/src/gen_server.erl +++ b/lib/stdlib/src/gen_server.erl @@ -270,7 +270,7 @@ enter_loop(Mod, Options, State) -> enter_loop(Mod, Options, State, self(), infinity). enter_loop(Mod, Options, State, ServerName = {Scope, _}) - when Scope == local; Scope == local -> + when Scope == local; Scope == global -> enter_loop(Mod, Options, State, ServerName, infinity); enter_loop(Mod, Options, State, ServerName = {via, _, _}) -> diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index dcd622b984..9f9d97b619 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -1331,17 +1331,20 @@ guard(Config) when is_list(Config) -> foo. ">>, [warn_unused_vars, nowarn_obsolete_guard], - {errors,[{2,erl_lint,illegal_guard_expr}, - {4,erl_lint,illegal_guard_expr}, - {6,erl_lint,illegal_guard_expr}, - {8,erl_lint,illegal_guard_expr}, - {10,erl_lint,illegal_guard_expr}, - {12,erl_lint,illegal_guard_expr}, - {14,erl_lint,illegal_guard_expr}, - {16,erl_lint,illegal_guard_expr}, - {18,erl_lint,illegal_guard_expr}, - {20,erl_lint,illegal_guard_expr}], - []}}, + {error,[{2,erl_lint,illegal_guard_expr}, + {4,erl_lint,illegal_guard_expr}, + {6,erl_lint,illegal_guard_expr}, + {8,erl_lint,illegal_guard_expr}, + {10,erl_lint,illegal_guard_expr}, + {12,erl_lint,illegal_guard_expr}, + {14,erl_lint,illegal_guard_expr}, + {16,erl_lint,illegal_guard_expr}, + {18,erl_lint,illegal_guard_expr}, + {20,erl_lint,illegal_guard_expr}], + [{8,erl_lint,deprecated_tuple_fun}, + {14,erl_lint,deprecated_tuple_fun}, + {20,erl_lint,deprecated_tuple_fun}, + {28,erl_lint,deprecated_tuple_fun}]}}, {guard6, <<"-record(apa,{a=a,b=foo:bar()}). apa() -> diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl index 7ed1ee742a..38c085616d 100644 --- a/lib/stdlib/test/escript_SUITE.erl +++ b/lib/stdlib/test/escript_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. 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 @@ -29,6 +29,7 @@ module_script/1, beam_script/1, archive_script/1, + archive_script_file_access/1, epp/1, create_and_extract/1, foldl/1, @@ -44,7 +45,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [basic, errors, strange_name, emulator_flags, module_script, beam_script, archive_script, epp, - create_and_extract, foldl, overflow]. + create_and_extract, foldl, overflow, + archive_script_file_access]. groups() -> []. @@ -356,7 +358,7 @@ beam_script(Config) when is_list(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Create an archive file containing two entire applications plus two %% alternate main modules. Generate a new escript containing the archive -%% (with .app and .beam files and ) and the escript header. +%% (with .app and .beam files and) and the escript header. archive_script(Config) when is_list(Config) -> %% Copy the orig files to priv_dir @@ -464,6 +466,147 @@ archive_script(Config) when is_list(Config) -> ok. +%% Test the correction of OTP-10071 +%% The errors identified are +%% +%% a) If primary archive was named "xxx", then a file in the same +%% directory named "xxxyyy" would be interpreted as a file named yyy +%% inside the archive. +%% +%% b) erl_prim_loader did not correctly create and normalize absolute +%% paths for primary archive and files inside it, so unless given +%% with exact same path files inside the archive would not be +%% found. E.g. if escript was started as ./xxx then "xxx/file" +%% would not be found since erl_prim_loader would try to match +%% /full/path/to/xxx with /full/path/to/./xxx. Same problem with +%% ../. Also, the use of symlinks in the path to the archive would +%% cause problems. +%% +%% c) Depending on how the primary archive was built, +%% erl_prim_loader:list_dir/1 would sometimes return an empty string +%% inside the file list. This was a virtual element representing the +%% top directory of the archive. This shall not occur. +%% +archive_script_file_access(Config) when is_list(Config) -> + %% Copy the orig files to priv_dir + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + + MainMod = "archive_script_file_access", + MainSrc = MainMod ++ ".erl", + MainBeam = MainMod ++ ".beam", + + Archive = filename:join([PrivDir, "archive_script_file_access.zip"]), + ?line {ok, _} = zip:create(Archive, ["archive_script_file_access"], + [{compress, []}, {cwd, DataDir}]), + ?line {ok, _} = zip:extract(Archive, [{cwd, PrivDir}]), + TopDir = filename:join([PrivDir, "archive_script_file_access"]), + + %% Compile the code + ?line ok = compile_files([MainSrc], TopDir, TopDir), + + %% First, create a file structure which will be included in the archive: + %% + %% dir1/ + %% dir1/subdir1/ + %% dir1/subdir1/file1 + %% + {ok, OldDir} = file:get_cwd(), + ok = file:set_cwd(TopDir), + DummyDir = "dir1", + DummySubDir = filename:join(DummyDir, "subdir1"), + RelDummyFile = filename:join(DummySubDir, "file1"), + DummyFile = filename:join(TopDir,RelDummyFile), + ok = filelib:ensure_dir(DummyFile), + ok = file:write_file(DummyFile, ["foo\nbar\nbaz"]), + + %% 1. Create zip archive by adding the dummy file and the beam + %% file as binaries to zip. + %% + %% This used to provoke the following issues when the script was run as + %% "./<script_name>": + %% a. erl_prim_loader:read_file_info/1 returning 'error' + %% b. erl_prim_loader:list_dir/1 returning {ok, ["dir1", [], "file1"]} + %% leading to an infinite loop in reltool_target:spec_dir/1 + Files1 = + lists:map(fun(Filename) -> + {ok, Bin} = file:read_file(Filename), + {Filename,Bin} + end, + [RelDummyFile,MainBeam]), + {ok, {"mem", Bin1}} = zip:create("mem", Files1, [memory]), + + %% Create the escript + ScriptName1 = "archive_script_file_access1", + Script1 = filename:join([PrivDir, ScriptName1]), + Flags = "-escript main " ++ MainMod, + ok = escript:create(Script1,[shebang,{emu_args,Flags},{archive,Bin1}]), + ok = file:change_mode(Script1,8#00744), + + %% If supported, create a symlink to the script. This is used to + %% test error b) described above this test case. + SymlinkName1 = "symlink_to_"++ScriptName1, + Symlink1 = filename:join([PrivDir, SymlinkName1]), + file:make_symlink(ScriptName1,Symlink1), % will fail if not supported + + %% Also add a dummy file in the same directory with the same name + %% as the script except is also has an extension. This used to + %% test error a) described above this test case. + ok = file:write_file(Script1 ++ ".extension", + <<"same name as script, but with extension">>), + + %% Change to script's directory and run it as "./<script_name>" + ok = file:set_cwd(PrivDir), + run(PrivDir, "./" ++ ScriptName1 ++ " " ++ ScriptName1, + [<<"ExitCode:0">>]), + ok = file:set_cwd(TopDir), + + + %% 2. Create zip archive by letting zip read the files from the file system + %% + %% The difference compared to the archive_script_file_access1 is + %% that this will have a file element for each directory in the + %% archive - while archive_script_file_access1 will only have a + %% file element per regular file. + Files2 = [DummyDir,MainBeam], + {ok, {"mem", Bin2}} = zip:create("mem", Files2, [memory]), + + %% Create the escript + ScriptName2 = "archive_script_file_access2", + Script2 = filename:join([PrivDir, ScriptName2]), + ok = escript:create(Script2,[shebang,{emu_args,Flags},{archive,Bin2}]), + ok = file:change_mode(Script2,8#00744), + + %% Also add a dummy file in the same directory with the same name + %% as the script except is also has an extension. This used to + %% test error a) described above this test case. + ok = file:write_file(Script2 ++ ".extension", + <<"same name as script, but with extension">>), + + %% If supported, create a symlink to the script. This is used to + %% test error b) described above this test case. + SymlinkName2 = "symlink_to_"++ScriptName2, + Symlink2 = filename:join([PrivDir, SymlinkName2]), + file:make_symlink(ScriptName2,Symlink2), % will fail if not supported + + %% Change to script's directory and run it as "./<script_name>" + ok = file:set_cwd(PrivDir), + run(PrivDir, "./" ++ ScriptName2 ++ " " ++ ScriptName2, + [<<"ExitCode:0">>]), + + %% 3. If symlinks are supported, run one of the scripts via a symlink. + %% + %% This is in order to test error b) described above this test case. + case file:read_link(Symlink2) of + {ok,_} -> + run(PrivDir, "./" ++ SymlinkName2 ++ " " ++ ScriptName2, + [<<"ExitCode:0">>]); + _ -> % not supported + ok + end, + ok = file:set_cwd(OldDir). + + compile_app(TopDir, AppName) -> AppDir = filename:join([TopDir, AppName]), SrcDir = filename:join([AppDir, "src"]), diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl index de56579998..431a51b0e5 100644 --- a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl +++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl @@ -21,6 +21,8 @@ -export([main/1]). +-include_lib("kernel/include/file.hrl"). + -define(DUMMY, archive_script_dummy). -define(DICT, archive_script_dict). @@ -32,7 +34,7 @@ main(MainArgs) -> io:format("dummy:~p\n",[[E || E <- ErlArgs, element(1, E) =:= ?DUMMY]]), %% Start the applications - {error, {not_started, ?DICT}} = application:start(archive_script_dummy), + {error, {not_started, ?DICT}} = application:start(?DUMMY), ok = application:start(?DICT), ok = application:start(?DUMMY), @@ -57,4 +59,17 @@ main(MainArgs) -> ok = ?DICT:erase(Tab, Key), error = ?DICT:find(Tab, Key), ok = ?DICT:erase(Tab), + + %% Check mtime related caching bug with escript/primary archive files + Escript = escript:script_name(), + {ok, FileInfo} = file:read_file_info(Escript), + %% Modify mtime of archive file and try to reload module + FileInfo2 = FileInfo#file_info{mtime=calendar:now_to_local_time(now())}, + ok = file:write_file_info(Escript, FileInfo2), + Module = ?DICT, + {file, _} = code:is_loaded(Module), + true = code:delete(Module), + false = code:is_loaded(Module), + {module, Module} = code:ensure_loaded(Module), + ok. diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl b/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl new file mode 100644 index 0000000000..b03c8ba70d --- /dev/null +++ b/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl @@ -0,0 +1,105 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. 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% +%% +-module(archive_script_file_access). +-behaviour(escript). + +-export([main/1]). + +-include_lib("kernel/include/file.hrl"). + +main([RelArchiveFile]) -> + + AbsArchiveFile = filename:absname(RelArchiveFile), + DotSlashArchiveFile = "./" ++ RelArchiveFile, + + Beam = atom_to_list(?MODULE) ++ ".beam", + AbsBeam = filename:join(AbsArchiveFile,Beam), + RelBeam = filename:join(RelArchiveFile,Beam), + DotSlashBeam = filename:join(DotSlashArchiveFile,Beam), + Dir = "dir1", + AbsDir = filename:join(AbsArchiveFile,Dir), + RelDir = filename:join(RelArchiveFile,Dir), + DotSlashDir = filename:join(DotSlashArchiveFile,Dir), + SubDir = "subdir1", + AbsSubDir = filename:join(AbsDir,SubDir), + RelSubDir = filename:join(RelDir,SubDir), + DotSlashSubDir = filename:join(DotSlashDir,SubDir), + + {ok,List1} = erl_prim_loader:list_dir(AbsArchiveFile), + {ok,List1} = erl_prim_loader:list_dir(RelArchiveFile), + {ok,List1} = erl_prim_loader:list_dir(DotSlashArchiveFile), + {ok,List1} = erl_prim_loader:list_dir(AbsArchiveFile ++ "/"), + {ok,List1} = erl_prim_loader:list_dir(AbsArchiveFile ++ "/."), + {ok,List1} = erl_prim_loader:list_dir(filename:join([AbsDir,".."])), + {ok,List1} = erl_prim_loader:list_dir(filename:join([RelDir,".."])), + {ok,List1} = erl_prim_loader:list_dir(filename:join([DotSlashDir,".."])), + {ok,List1} = erl_prim_loader:list_dir(filename:join([AbsSubDir,"..",".."])), + {ok,List1} = erl_prim_loader:list_dir(filename:join([RelSubDir,"..",".."])), + {ok,List1} = erl_prim_loader:list_dir(filename:join([DotSlashSubDir,"..",".."])), + false = lists:member([],List1), + + %% If symlinks are supported on this platform... + RelSymlinkArchiveFile = "symlink_to_" ++ RelArchiveFile, + case file:read_link(RelSymlinkArchiveFile) of + {ok,_} -> + DotSlashSymlinkArchiveFile = "./" ++ RelSymlinkArchiveFile, + AbsSymlinkArchiveFile=filename:join(filename:dirname(AbsArchiveFile), + RelSymlinkArchiveFile), + {ok,List1} = erl_prim_loader:list_dir(AbsSymlinkArchiveFile), + {ok,List1} = erl_prim_loader:list_dir(RelSymlinkArchiveFile), + {ok,List1} = erl_prim_loader:list_dir(DotSlashSymlinkArchiveFile); + _ -> % not supported + ok + end, + + + {ok,List2} = erl_prim_loader:list_dir(AbsDir), + {ok,List2} = erl_prim_loader:list_dir(RelDir), + {ok,List2} = erl_prim_loader:list_dir(DotSlashDir), + false = lists:member([],List2), + + error = erl_prim_loader:list_dir(AbsBeam), + error = erl_prim_loader:list_dir(RelBeam), + error = erl_prim_loader:list_dir(DotSlashBeam), + + error = erl_prim_loader:get_file(AbsArchiveFile), + error = erl_prim_loader:get_file(RelArchiveFile), + error = erl_prim_loader:get_file(DotSlashArchiveFile), + error = erl_prim_loader:get_file(AbsArchiveFile ++ "/"), + error = erl_prim_loader:get_file(AbsArchiveFile ++ "/."), + {ok,Bin,AbsBeam} = erl_prim_loader:get_file(AbsBeam), + {ok,Bin,RelBeam} = erl_prim_loader:get_file(RelBeam), + {ok,Bin,DotSlashBeam} = erl_prim_loader:get_file(DotSlashBeam), + + {ok,#file_info{type=directory}=DFI} = + erl_prim_loader:read_file_info(AbsArchiveFile), + {ok,DFI} = erl_prim_loader:read_file_info(RelArchiveFile), + {ok,DFI} = erl_prim_loader:read_file_info(DotSlashArchiveFile), + {ok,DFI} = erl_prim_loader:read_file_info(AbsArchiveFile ++ "/"), + {ok,DFI} = erl_prim_loader:read_file_info(AbsArchiveFile ++ "/."), + {ok,#file_info{type=regular}=RFI} = erl_prim_loader:read_file_info(AbsBeam), + {ok,RFI} = erl_prim_loader:read_file_info(RelBeam), + {ok,RFI} = erl_prim_loader:read_file_info(DotSlashBeam), + + F = AbsArchiveFile ++ ".extension", + error = erl_prim_loader:list_dir(F), + {ok,_,_} = erl_prim_loader:get_file(F), + {ok,#file_info{type=regular}} = erl_prim_loader:read_file_info(F), + + ok. diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 297c4ec1c9..95f10b1df3 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -74,6 +74,7 @@ -export([bad_table/1, types/1]). -export([otp_9932/1]). -export([otp_9423/1]). +-export([otp_10182/1]). -export([init_per_testcase/2, end_per_testcase/2]). %% Convenience for manual testing @@ -146,6 +147,7 @@ all() -> exit_many_large_table_owner, exit_many_tables_owner, exit_many_many_tables_owner, write_concurrency, heir, give_away, setopts, bad_table, types, + otp_10182, otp_9932, otp_9423]. @@ -1024,6 +1026,8 @@ t_test_ms(Config) when is_list(Config) -> [{{'$1','$2'},[{'<','$1','$2'}],['$$']}]), ?line {ok,false} = ets:test_ms({a,b}, [{{'$1','$2'},[{'>','$1','$2'}],['$$']}]), + Tpl = {a,gb_sets:new()}, + ?line {ok,Tpl} = ets:test_ms(Tpl, [{{'_','_'}, [], ['$_']}]), % OTP-10190 ?line {error,[{error,String}]} = ets:test_ms({a,b}, [{{'$1','$2'}, [{'flurp','$1','$2'}], @@ -5470,6 +5474,20 @@ otp_9423(Config) when is_list(Config) -> Skipped -> Skipped end. + +%% Corrupted binary in compressed table +otp_10182(Config) when is_list(Config) -> + Bin = <<"aHR0cDovL2hvb3RzdWl0ZS5jb20vYy9wcm8tYWRyb2xsLWFi">>, + Key = {test, Bin}, + Value = base64:decode(Bin), + In = {Key,Value}, + Db = ets:new(undefined, [set, protected, {read_concurrency, true}, compressed]), + ets:insert(Db, In), + [Out] = ets:lookup(Db, Key), + io:format("In : ~p\nOut: ~p\n", [In,Out]), + ets:delete(Db), + In = Out. + diff --git a/lib/stdlib/test/filename_SUITE.erl b/lib/stdlib/test/filename_SUITE.erl index 4cfa589660..99516c0c04 100644 --- a/lib/stdlib/test/filename_SUITE.erl +++ b/lib/stdlib/test/filename_SUITE.erl @@ -25,7 +25,7 @@ -export([pathtype/1,rootname/1,split/1,find_src/1]). -export([absname_bin/1, absname_bin_2/1, basename_bin_1/1, basename_bin_2/1, - dirname_bin/1, extension_bin/1, join_bin/1]). + dirname_bin/1, extension_bin/1, join_bin/1, t_nativename_bin/1]). -export([pathtype_bin/1,rootname_bin/1,split_bin/1]). -include_lib("test_server/include/test_server.hrl"). @@ -38,7 +38,7 @@ all() -> join, pathtype, rootname, split, t_nativename, find_src, absname_bin, absname_bin_2, basename_bin_1, basename_bin_2, dirname_bin, extension_bin, - join_bin, pathtype_bin, rootname_bin, split_bin]. + join_bin, pathtype_bin, rootname_bin, split_bin, t_nativename_bin]. groups() -> []. @@ -804,3 +804,14 @@ split_bin(Config) when is_list(Config) -> ok end. +t_nativename_bin(Config) when is_list(Config) -> + ?line <<"abcedf">> = filename:nativename(<<"abcedf">>), + case os:type() of + {win32, _} -> + ?line <<"a:\\temp\\arne.exe">> = + filename:nativename(<<"A:/temp//arne.exe/">>); + _ -> + ?line <<"/usr/tmp/arne">> = + filename:nativename(<<"/usr/tmp//arne/">>) + end. + diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl index cdf15ba017..48ef7e55ed 100644 --- a/lib/stdlib/test/gen_server_SUITE.erl +++ b/lib/stdlib/test/gen_server_SUITE.erl @@ -37,7 +37,8 @@ % spawn export -export([spec_init_local/2, spec_init_global/2, spec_init_via/2, - spec_init_default_timeout/2, spec_init_anonymous/1, + spec_init_default_timeout/2, spec_init_global_default_timeout/2, + spec_init_anonymous/1, spec_init_anonymous_default_timeout/1, spec_init_not_proc_lib/1, cast_fast_messup/0]). @@ -749,7 +750,7 @@ spec_init(suite) -> spec_init(Config) when is_list(Config) -> OldFlag = process_flag(trap_exit, true), - + ?line {ok, Pid0} = start_link(spec_init_local, [{ok, my_server}, []]), ?line ok = gen_server:call(Pid0, started_p), ?line ok = gen_server:call(Pid0, stop), @@ -819,6 +820,14 @@ spec_init(Config) when is_list(Config) -> test_server:fail(gen_server_did_not_die) end, + %% Before the OTP-10130 fix this failed because a timeout message + %% was generated as the spawned process crashed because a {global, Name} + %% was matched as a timeout value instead of matching on scope. + {ok, _PidHurra} = + start_link(spec_init_global_default_timeout, [{ok, hurra}, []]), + timer:sleep(1000), + ok = gen_server:call(_PidHurra, started_p), + ?line Pid5 = erlang:spawn_link(?MODULE, spec_init_not_proc_lib, [[]]), receive @@ -1125,6 +1134,15 @@ spec_init_default_timeout({ok, Name}, Options) -> %% Supervised init can occur here ... gen_server:enter_loop(?MODULE, Options, {}, {local, Name}). +%% OTP-10130, A bug was introduced where global scope was not matched when +%% enter_loop/4 was called (no timeout). +spec_init_global_default_timeout({ok, Name}, Options) -> + process_flag(trap_exit, true), + global:register_name(Name, self()), + proc_lib:init_ack({ok, self()}), + %% Supervised init can occur here ... + gen_server:enter_loop(?MODULE, Options, {}, {global, Name}). + spec_init_anonymous(Options) -> process_flag(trap_exit, true), proc_lib:init_ack({ok, self()}), diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl index 1e74ad7727..192268f90e 100644 --- a/lib/stdlib/test/qlc_SUITE.erl +++ b/lib/stdlib/test/qlc_SUITE.erl @@ -2969,12 +2969,14 @@ lookup1(Config) when is_list(Config) -> [3] = lookup_keys(Q) end, [{1,a},{3,3}])">>, + {cres, <<"A = 3, etsc(fun(E) -> Q = qlc:q([X || X <- ets:table(E), A =:= {erlang,element}(1, X)]), [{3,3}] = qlc:e(Q), [3] = lookup_keys(Q) end, [{1,a},{3,3}])">>, + {warnings,[{3,erl_lint,deprecated_tuple_fun}]}}, <<"etsc(fun(E) -> A = 3, @@ -3439,12 +3441,14 @@ lookup2(Config) when is_list(Config) -> [r] = qlc:e(Q), [r] = lookup_keys(Q) end, [{keypos,1}], [#r{}])">>, + {cres, <<"etsc(fun(E) -> Q = qlc:q([element(1, X) || X <- ets:table(E), {erlang,is_record}(X, r, 2)]), [r] = qlc:e(Q), [r] = lookup_keys(Q) end, [{keypos,1}], [#r{}])">>, + {warnings,[{4,erl_lint,deprecated_tuple_fun}]}}, {cres, <<"etsc(fun(E) -> Q = qlc:q([element(1, X) || X <- ets:table(E), @@ -3465,12 +3469,14 @@ lookup2(Config) when is_list(Config) -> [r] = qlc:e(Q), [r] = lookup_keys(Q) end, [{keypos,1}], [#r{}])">>, + {cres, <<"etsc(fun(E) -> Q = qlc:q([element(1, X) || X <- ets:table(E), {erlang,is_record}(X, r)]), [r] = qlc:e(Q), [r] = lookup_keys(Q) - end, [{keypos,1}], [#r{}])">> + end, [{keypos,1}], [#r{}])">>, + {warnings,[{4,erl_lint,deprecated_tuple_fun}]}} ], ?line run(Config, <<"-record(r, {a}).\n">>, TsR), |