1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2006-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(misc_SUITE). 21 22-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 23 init_per_group/2,end_per_group/2, 24 init_per_testcase/2,end_per_testcase/2, 25 tobias/1,empty_string/1,md5/1,silly_coverage/1, 26 confused_literals/1,integer_encoding/0,integer_encoding/1, 27 override_bif/1]). 28 29-include_lib("common_test/include/ct.hrl"). 30 31%% For the override_bif testcase. 32%% NB, no other testcases in this testsuite can use these without erlang:prefix! 33-compile({no_auto_import,[abs/1]}). 34-compile({no_auto_import,[binary_part/3]}). 35-compile({no_auto_import,[binary_part/2]}). 36-import(test_lib,[binary_part/2]). 37 38%% This should do no harm (except for fun byte_size/1 which does not, by design, work with import 39-compile({no_auto_import,[byte_size/1]}). 40-import(erlang,[byte_size/1]). 41 42%% Cover the code for callback handling. 43-callback must_define_this_one() -> 'ok'. 44-callback do_something_strange(atom()) -> 'ok'. 45-optional_callbacks([do_something_strange/1]). 46-optional_callbacks([ignore_me]). %Invalid; ignored. 47 48%% Include an opaque declaration to cover the stripping of 49%% opaque types from attributes in v3_kernel. 50-opaque misc_SUITE_test_cases() :: [atom()]. 51 52init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> 53 Config. 54 55end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> 56 ok. 57 58suite() -> 59 [{ct_hooks,[ts_install_cth]}, 60 {timetrap,{minutes,10}}]. 61 62-spec all() -> misc_SUITE_test_cases(). 63all() -> 64 slow_group() ++ [{group,p}]. 65 66groups() -> 67 [{p,[parallel], 68 [tobias,empty_string,silly_coverage, 69 confused_literals,override_bif]}, 70 {slow,[parallel],[integer_encoding,md5]}]. 71 72init_per_suite(Config) -> 73 test_lib:recompile(?MODULE), 74 Config. 75 76end_per_suite(_Config) -> 77 ok. 78 79init_per_group(_GroupName, Config) -> 80 Config. 81 82end_per_group(_GroupName, Config) -> 83 Config. 84 85slow_group() -> 86 case ?MODULE of 87 misc_SUITE -> 88 %% Canononical module name. Run slow cases. 89 [{group,slow}]; 90 _ -> 91 %% Cloned module. Don't run. 92 [] 93 end. 94 95%% 96%% Functions that override new and old bif's 97%% 98abs(_N) -> 99 dummy_abs. 100 101binary_part(_,_,_) -> 102 dummy_bp. 103 104%% Test that local functions and imports override auto-imported BIFs. 105override_bif(Config) when is_list(Config) -> 106 dummy_abs = abs(1), 107 dummy_bp = binary_part(<<"hello">>,1,1), 108 dummy = binary_part(<<"hello">>,{1,1}), 109 1 = erlang:abs(1), 110 <<"e">> = erlang:binary_part(<<"hello">>,1,1), 111 <<"e">> = erlang:binary_part(<<"hello">>,{1,1}), 112 F = fun(X) when byte_size(X) =:= 4 -> 113 four; 114 (X) -> 115 byte_size(X) 116 end, 117 four = F(<<1,2,3,4>>), 118 5 = F(<<1,2,3,4,5>>), 119 ok. 120 121%% A bug reported by Tobias Lindahl for a development version of R11B. 122 123tobias(Config) when is_list(Config) -> 124 1 = tobias_1([1,2,3]), 125 ok. 126 127tobias_1([H|_T]) -> 128 %% In an R11B compiler, the move optimizer in beam_block would 129 %% confuse H and _T. 130 tobias_2(0, 0), 131 H. 132 133tobias_2(_, _) -> 134 2. 135 136 137%% A bug reported by Richard Carlsson. Used to crash beam_asm 138%% because of a put_string instruction with an empty string. 139%% The real problem was in sys_core_fold (empty strings should 140%% be replaced by []). 141 142-record(r, {s = ""}). 143 144empty_string(Config) when is_list(Config) -> 145 #r{s="x"} = empty_string_1(#r{}), 146 ok. 147 148empty_string_1(T) -> 149 case T of 150 #r{s = ""} -> T #r{s = "x"} 151 end. 152 153md5(Config) when is_list(Config) -> 154 Dir = filename:dirname(code:which(?MODULE)), 155 Beams = filelib:wildcard(filename:join(Dir, "*.beam")), 156 io:format("Found ~w beam files", [length(Beams)]), 157 lists:foreach(fun md5_1/1, Beams). 158 159md5_1(Beam) -> 160 {ok,{Mod,[Vsn]}} = beam_lib:version(Beam), 161 {ok,Code} = file:read_file(Beam), 162 {Mod,<<Vsn:128>>} = {Mod,code:module_md5(Code)}. 163 164%% Cover some code that handles internal errors. 165 166silly_coverage(Config) when is_list(Config) -> 167 %% sys_core_fold, sys_core_alias, sys_core_bsm, v3_kernel 168 BadCoreErlang = {c_module,[], 169 name,[],[], 170 [{{c_var,[],{foo,2}},seriously_bad_body}]}, 171 expect_error(fun() -> sys_core_fold:module(BadCoreErlang, []) end), 172 expect_error(fun() -> sys_core_alias:module(BadCoreErlang, []) end), 173 expect_error(fun() -> sys_core_bsm:module(BadCoreErlang, []) end), 174 expect_error(fun() -> v3_kernel:module(BadCoreErlang, []) end), 175 176 %% beam_kernel_to_ssa 177 BadKernel = {k_mdef,[],?MODULE, 178 [{foo,0}], 179 [], 180 [{k_fdef, 181 {k,[],[],[]}, 182 f,0,[], 183 seriously_bad_body}]}, 184 expect_error(fun() -> beam_kernel_to_ssa:module(BadKernel, []) end), 185 186 %% beam_ssa_lint 187 %% beam_ssa_recv 188 %% beam_ssa_share 189 %% beam_ssa_pre_codegen 190 %% beam_ssa_codegen 191 BadSSA = {b_module,#{},a,b,c, 192 [{b_function,#{func_info=>{mod,foo,0}},args,bad_blocks,0}]}, 193 expect_error(fun() -> beam_ssa_lint:module(BadSSA, []) end), 194 expect_error(fun() -> beam_ssa_recv:module(BadSSA, []) end), 195 expect_error(fun() -> beam_ssa_share:module(BadSSA, []) end), 196 expect_error(fun() -> beam_ssa_pre_codegen:module(BadSSA, []) end), 197 expect_error(fun() -> beam_ssa_codegen:module(BadSSA, []) end), 198 199 %% beam_ssa_opt 200 BadSSABlocks = #{0 => {b_blk,#{},[bad_code],{b_ret,#{},arg}}}, 201 BadSSAOpt = {b_module,#{},a,[],c, 202 [{b_function,#{func_info=>{mod,foo,0}},[], 203 BadSSABlocks,0}]}, 204 expect_error(fun() -> beam_ssa_opt:module(BadSSAOpt, []) end), 205 206 %% beam_ssa_lint, beam_ssa_pp 207 {error,[{_,Errors}]} = beam_ssa_lint:module(bad_ssa_lint_input(), []), 208 _ = [io:put_chars(Mod:format_error(Reason)) || 209 {Mod,Reason} <- Errors], 210 211 %% Cover printing of annotations in beam_ssa_pp 212 PPAnno = #{func_info=>{mod,foo,0},other_anno=>value,map_anno=>#{k=>v}}, 213 PPBlocks = #{0=>{b_blk,#{},[],{b_ret,#{},{b_literal,42}}}}, 214 PP = {b_function,PPAnno,[],PPBlocks,0}, 215 io:put_chars(beam_ssa_pp:format_function(PP)), 216 217 %% beam_a 218 BeamAInput = {?MODULE,[{foo,0}],[], 219 [{function,foo,0,2, 220 [{label,1}, 221 {func_info,{atom,?MODULE},{atom,foo},0}, 222 {label,2}|non_proper_list]}],99}, 223 expect_error(fun() -> beam_a:module(BeamAInput, []) end), 224 225 %% beam_block 226 BlockInput = {?MODULE,[{foo,0}],[], 227 [{function,foo,0,2, 228 [{label,1}, 229 {func_info,{atom,?MODULE},{atom,foo},0}, 230 {label,2}|non_proper_list]}],99}, 231 expect_error(fun() -> beam_block:module(BlockInput, []) end), 232 233 %% beam_except 234 ExceptInput = {?MODULE,[{foo,0}],[], 235 [{function,foo,0,2, 236 [{label,1}, 237 {line,loc}, 238 {func_info,{atom,?MODULE},{atom,foo},0}, 239 {label,2}|non_proper_list]}],99}, 240 expect_error(fun() -> beam_except:module(ExceptInput, []) end), 241 242 %% beam_jump 243 JumpInput = BlockInput, 244 expect_error(fun() -> beam_jump:module(JumpInput, []) end), 245 246 %% beam_clean 247 CleanInput = {?MODULE,[{foo,0}],[], 248 [{function,foo,0,2, 249 [{label,1}, 250 {func_info,{atom,?MODULE},{atom,foo},0}, 251 {label,2}, 252 {jump,{f,42}}]}],99}, 253 expect_error(fun() -> beam_clean:module(CleanInput, []) end), 254 255 %% beam_jump 256 TrimInput = BlockInput, 257 expect_error(fun() -> beam_trim:module(TrimInput, []) end), 258 259 %% beam_peep. This is tricky. Use a select instruction with 260 %% an odd number of elements in the list to crash 261 %% prune_redundant_values/2 but not beam_clean:clean_labels/1. 262 PeepInput = {?MODULE,[{foo,0}],[], 263 [{function,foo,0,2, 264 [{label,1}, 265 {func_info,{atom,?MODULE},{atom,foo},0}, 266 {label,2},{select,select_val,r,{f,2},[{f,2}]}]}], 267 2}, 268 expect_error(fun() -> beam_peep:module(PeepInput, []) end), 269 270 BeamZInput = {?MODULE,[{foo,0}],[], 271 [{function,foo,0,2, 272 [{label,1}, 273 {func_info,{atom,?MODULE},{atom,foo},0}, 274 {label,2}|non_proper_list]}],99}, 275 expect_error(fun() -> beam_z:module(BeamZInput, []) end), 276 277 %% beam_validator. 278 BeamValInput = {?MODULE,[{foo,0}],[], 279 [{function,foo,0,2, 280 [{label,1}, 281 {func_info,{atom,?MODULE},{atom,foo},0}, 282 {label,2}|non_proper_list]}],99}, 283 expect_error(fun() -> beam_validator:module(BeamValInput, []) end), 284 285 ok. 286 287bad_ssa_lint_input() -> 288 {b_module,#{},t, 289 [{foobar,1},{module_info,0},{module_info,1}], 290 [], 291 [{b_function, 292 #{func_info => {t,foobar,1},location => {"t.erl",4}}, 293 [{b_var,0}], 294 #{0 => {b_blk,#{},[],{b_ret,#{},{b_var,'@undefined_var'}}}}, 295 3}, 296 {b_function, 297 #{func_info => {t,module_info,0}}, 298 [], 299 #{0 => 300 {b_blk,#{}, 301 [{b_set,#{}, 302 {b_var,{'@ssa_ret',3}}, 303 call, 304 [{b_remote, 305 {b_literal,erlang}, 306 {b_literal,get_module_info}, 307 1}, 308 {b_var,'@unknown_variable'}]}], 309 {b_ret,#{},{b_var,{'@ssa_ret',3}}}}}, 310 4}]}. 311 312expect_error(Fun) -> 313 try Fun() of 314 Any -> 315 io:format("~p", [Any]), 316 ct:fail(call_was_supposed_to_fail) 317 catch 318 Class:Reason:Stk -> 319 io:format("~p:~p\n~p\n", [Class,Reason,Stk]), 320 case {Class,Reason} of 321 {error,undef} -> 322 ct:fail(not_supposed_to_fail_with_undef); 323 {_,_} -> 324 ok 325 end 326 end. 327 328confused_literals(Config) when is_list(Config) -> 329 {0,infinity} = confused_literals_1(int), 330 {0.0,infinity} = confused_literals_1(float), 331 ok. 332 333confused_literals_1(int) -> {0,infinity}; 334confused_literals_1(float) -> {0.0,infinity}. 335 336integer_encoding() -> 337 [{timetrap,{minutes,4}}]. 338 339integer_encoding(Config) when is_list(Config) -> 340 PrivDir = proplists:get_value(priv_dir, Config), 341 SrcFile = filename:join(PrivDir, "misc_SUITE_integer_encoding.erl"), 342 DataFile = filename:join(PrivDir, "integer_encoding.data"), 343 Mod = misc_SUITE_integer_encoding, 344 345 %% Create files. 346 {ok,Src} = file:open(SrcFile, [write]), 347 {ok,Data} = file:open(DataFile, [write]), 348 io:format(Src, "-module(~s).\n", [Mod]), 349 io:put_chars(Src, "-export([t/1]).\n"), 350 io:put_chars(Src, "t(Last) ->[\n"), 351 io:put_chars(Data, "[\n"), 352 353 do_integer_encoding(137, 0, Src, Data), 354 _ = [begin 355 B = 1 bsl I, 356 do_integer_encoding(-B-1, Src, Data), 357 do_integer_encoding(-B, Src, Data), 358 do_integer_encoding(-B+1, Src, Data), 359 do_integer_encoding(B-1, Src, Data), 360 do_integer_encoding(B, Src, Data), 361 do_integer_encoding(B+1, Src, Data) 362 end || I <- lists:seq(1, 130)], 363 io:put_chars(Src, "Last].\n\n"), 364 ok = file:close(Src), 365 io:put_chars(Data, "0].\n\n"), 366 ok = file:close(Data), 367 368 %% Compile and load Erlang module. 369 SrcRoot = filename:rootname(SrcFile), 370 {ok,Mod,Binary} = compile:file(SrcRoot, [binary,report]), 371 {module,Mod} = code:load_binary(Mod, SrcRoot, Binary), 372 373 %% Compare lists. 374 List = Mod:t(0), 375 {ok,[List]} = file:consult(DataFile), 376 377 %% Cleanup. 378 file:delete(SrcFile), 379 file:delete(DataFile), 380 ok. 381 382do_integer_encoding(0, _, _, _) -> ok; 383do_integer_encoding(N, I0, Src, Data) -> 384 I1 = (I0 bsl 5) bor (rand:uniform(32) - 1), 385 do_integer_encoding(I1, Src, Data), 386 I2 = -(I1 bxor (rand:uniform(32) - 1)), 387 do_integer_encoding(I2, Src, Data), 388 do_integer_encoding(N-1, I1, Src, Data). 389 390do_integer_encoding(I, Src, Data) -> 391 Str = integer_to_list(I), 392 io:put_chars(Src, [Str,",\n"]), 393 io:put_chars(Data, [Str,",\n"]). 394