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 %% v3_core 168 BadAbstr = [{attribute,0,module,bad_module}, 169 {function,0,foo,2,[bad_clauses]}], 170 expect_error(fun() -> v3_core:module(BadAbstr, []) end), 171 172 %% sys_core_fold, sys_core_alias, sys_core_bsm, v3_kernel 173 BadCoreErlang = {c_module,[], 174 name,[],[], 175 [{{c_var,[],{foo,2}},seriously_bad_body}]}, 176 expect_error(fun() -> sys_core_fold:module(BadCoreErlang, []) end), 177 expect_error(fun() -> sys_core_alias:module(BadCoreErlang, []) end), 178 expect_error(fun() -> sys_core_bsm:module(BadCoreErlang, []) end), 179 expect_error(fun() -> v3_kernel:module(BadCoreErlang, []) end), 180 181 %% beam_kernel_to_ssa 182 BadKernel = {k_mdef,[],?MODULE, 183 [{foo,0}], 184 [], 185 [{k_fdef, 186 {k,[],[],[]}, 187 f,0,[], 188 seriously_bad_body}]}, 189 expect_error(fun() -> beam_kernel_to_ssa:module(BadKernel, []) end), 190 191 %% beam_ssa_lint 192 %% beam_ssa_bool 193 %% beam_ssa_recv 194 %% beam_ssa_share 195 %% beam_ssa_pre_codegen 196 %% beam_ssa_codegen 197 BadSSA = {b_module,#{},a,b,c, 198 [{b_function,#{func_info=>{mod,foo,0}},args,bad_blocks,0}]}, 199 expect_error(fun() -> beam_ssa_lint:module(BadSSA, []) end), 200 expect_error(fun() -> beam_ssa_bool:module(BadSSA, []) end), 201 expect_error(fun() -> beam_ssa_recv:module(BadSSA, []) end), 202 expect_error(fun() -> beam_ssa_share:module(BadSSA, []) end), 203 expect_error(fun() -> beam_ssa_pre_codegen:module(BadSSA, []) end), 204 expect_error(fun() -> beam_ssa_codegen:module(BadSSA, []) end), 205 206 %% beam_ssa_opt 207 BadSSABlocks = #{0 => {b_blk,#{},[bad_code],{b_ret,#{},arg}}}, 208 BadSSAOpt = {b_module,#{},a,[],[], 209 [{b_function,#{func_info=>{mod,foo,0}},[], 210 BadSSABlocks,0}]}, 211 expect_error(fun() -> beam_ssa_opt:module(BadSSAOpt, []) end), 212 213 %% beam_ssa_bc_size 214 cover_beam_ssa_bc_size(1), 215 216 %% beam_ssa_lint, beam_ssa_pp 217 {error,[{_,Errors}]} = beam_ssa_lint:module(bad_ssa_lint_input(), []), 218 _ = [io:put_chars(Mod:format_error(Reason)) || 219 {Mod,Reason} <- Errors], 220 221 %% Cover printing of annotations in beam_ssa_pp 222 PPAnno = #{func_info=>{mod,foo,0},other_anno=>value,map_anno=>#{k=>v}}, 223 PPBlocks = #{0=>{b_blk,#{},[],{b_ret,#{},{b_literal,42}}}}, 224 PP = {b_function,PPAnno,[],PPBlocks,0}, 225 io:put_chars(beam_ssa_pp:format_function(PP)), 226 227 %% beam_a 228 BeamAInput = {?MODULE,[{foo,0}],[], 229 [{function,foo,0,2, 230 [{label,1}, 231 {func_info,{atom,?MODULE},{atom,foo},0}, 232 {label,2}|non_proper_list]}],99}, 233 expect_error(fun() -> beam_a:module(BeamAInput, []) end), 234 235 %% beam_block 236 BlockInput = {?MODULE,[{foo,0}],[], 237 [{function,foo,0,2, 238 [{label,1}, 239 {func_info,{atom,?MODULE},{atom,foo},0}, 240 {label,2}|non_proper_list]}],99}, 241 expect_error(fun() -> beam_block:module(BlockInput, []) end), 242 243 %% beam_jump 244 JumpInput = BlockInput, 245 expect_error(fun() -> beam_jump:module(JumpInput, []) end), 246 247 %% beam_clean 248 CleanInput = {?MODULE,[{foo,0}],[], 249 [{function,foo,0,2, 250 [{label,1}, 251 {func_info,{atom,?MODULE},{atom,foo},0}, 252 {label,2}, 253 {jump,{f,42}}]}],99}, 254 expect_error(fun() -> beam_clean:module(CleanInput, []) end), 255 256 %% beam_jump 257 TrimInput = BlockInput, 258 expect_error(fun() -> beam_trim:module(TrimInput, []) end), 259 260 %% beam_peep. This is tricky. Use a select instruction with 261 %% an odd number of elements in the list to crash 262 %% prune_redundant_values/2 but not beam_clean:clean_labels/1. 263 PeepInput = {?MODULE,[{foo,0}],[], 264 [{function,foo,0,2, 265 [{label,1}, 266 {func_info,{atom,?MODULE},{atom,foo},0}, 267 {label,2},{select,select_val,r,{f,2},[{f,2}]}]}], 268 2}, 269 expect_error(fun() -> beam_peep:module(PeepInput, []) end), 270 271 BeamZInput = {?MODULE,[{foo,0}],[], 272 [{function,foo,0,2, 273 [{label,1}, 274 {func_info,{atom,?MODULE},{atom,foo},0}, 275 {label,2}|non_proper_list]}],99}, 276 expect_error(fun() -> beam_z:module(BeamZInput, []) end), 277 278 %% beam_validator. 279 BeamValInput = {?MODULE,[{foo,0}],[], 280 [{function,foo,0,2, 281 [{label,1}, 282 {func_info,{atom,?MODULE},{atom,foo},0}, 283 {label,2}|non_proper_list]}],99}, 284 expect_error(fun() -> beam_validator:validate(BeamValInput, strong) end), 285 286 ok. 287 288cover_beam_ssa_bc_size(20) -> 289 ok; 290cover_beam_ssa_bc_size(N) -> 291 BcSizeKey = {b_local,{b_literal,name},1}, 292 %% Try different sizes for the opt_st record. 293 OptSt = erlang:make_tuple(N, #{}, [{1,opt_st}]), 294 expect_error(fun() -> beam_ssa_bc_size:opt(#{BcSizeKey => OptSt}) end), 295 cover_beam_ssa_bc_size(N + 1). 296 297bad_ssa_lint_input() -> 298 {b_module,#{},t, 299 [{a,1},{b,1},{c,1},{module_info,0},{module_info,1}], 300 [], 301 [{b_function, 302 #{func_info => {t,a,1},location => {"t.erl",4}}, 303 [{b_var,0}], 304 #{0 => {b_blk,#{},[],{b_ret,#{},{b_var,'@undefined_var'}}}}, 305 3}, 306 {b_function, 307 #{func_info => {t,b,1},location => {"t.erl",5}}, 308 [{b_var,0}], 309 #{0 => 310 {b_blk,#{}, 311 [{b_set,#{},{b_var,'@first_var'},first_op,[]}, 312 {b_set,#{},{b_var,'@second_var'},second_op,[]}, 313 {b_set,#{},{b_var,'@ret'},succeeded,[{b_var,'@first_var'}]}], 314 {b_ret,#{},{b_var,'@ret'}}}}, 315 3}, 316 {b_function, 317 #{func_info => {t,c,1},location => {"t.erl",6}}, 318 [{b_var,0}], 319 #{0 => 320 {b_blk,#{}, 321 [{b_set,#{},{b_var,'@first_var'},first_op,[]}, 322 {b_set,#{},{b_var,'@ret'},succeeded,[{b_var,'@first_var'}]}, 323 {b_set,#{},{b_var,'@second_var'},second_op,[]}], 324 {b_ret,#{},{b_var,'@ret'}}}}, 325 3}, 326 {b_function, 327 #{func_info => {t,module_info,0}}, 328 [], 329 #{0 => 330 {b_blk,#{}, 331 [{b_set,#{}, 332 {b_var,{'@ssa_ret',3}}, 333 call, 334 [{b_remote, 335 {b_literal,erlang}, 336 {b_literal,get_module_info}, 337 1}, 338 {b_var,'@unknown_variable'}]}], 339 {b_ret,#{},{b_var,{'@ssa_ret',3}}}}}, 340 4}]}. 341 342expect_error(Fun) -> 343 try Fun() of 344 Any -> 345 io:format("~p", [Any]), 346 ct:fail(call_was_supposed_to_fail) 347 catch 348 Class:Reason:Stk -> 349 io:format("~p:~p\n~p\n", [Class,Reason,Stk]), 350 case {Class,Reason} of 351 {error,undef} -> 352 ct:fail(not_supposed_to_fail_with_undef); 353 {_,_} -> 354 ok 355 end 356 end. 357 358confused_literals(Config) when is_list(Config) -> 359 {0,infinity} = confused_literals_1(int), 360 {0.0,infinity} = confused_literals_1(float), 361 ok. 362 363confused_literals_1(int) -> {0,infinity}; 364confused_literals_1(float) -> {0.0,infinity}. 365 366integer_encoding() -> 367 [{timetrap,{minutes,4}}]. 368 369integer_encoding(Config) when is_list(Config) -> 370 PrivDir = proplists:get_value(priv_dir, Config), 371 SrcFile = filename:join(PrivDir, "misc_SUITE_integer_encoding.erl"), 372 DataFile = filename:join(PrivDir, "integer_encoding.data"), 373 Mod = misc_SUITE_integer_encoding, 374 375 %% Create files. 376 {ok,Src} = file:open(SrcFile, [write]), 377 {ok,Data} = file:open(DataFile, [write]), 378 io:format(Src, "-module(~s).\n", [Mod]), 379 io:put_chars(Src, "-export([t/1]).\n"), 380 io:put_chars(Src, "t(Last) ->[\n"), 381 io:put_chars(Data, "[\n"), 382 383 do_integer_encoding(137, 0, Src, Data), 384 _ = [begin 385 B = 1 bsl I, 386 do_integer_encoding(-B-1, Src, Data), 387 do_integer_encoding(-B, Src, Data), 388 do_integer_encoding(-B+1, Src, Data), 389 do_integer_encoding(B-1, Src, Data), 390 do_integer_encoding(B, Src, Data), 391 do_integer_encoding(B+1, Src, Data) 392 end || I <- lists:seq(1, 130)], 393 io:put_chars(Src, "Last].\n\n"), 394 ok = file:close(Src), 395 io:put_chars(Data, "0].\n\n"), 396 ok = file:close(Data), 397 398 %% Compile and load Erlang module. 399 SrcRoot = filename:rootname(SrcFile), 400 {ok,Mod,Binary} = compile:file(SrcRoot, [binary,report]), 401 {module,Mod} = code:load_binary(Mod, SrcRoot, Binary), 402 403 %% Compare lists. 404 List = Mod:t(0), 405 {ok,[List]} = file:consult(DataFile), 406 407 %% Cleanup. 408 file:delete(SrcFile), 409 file:delete(DataFile), 410 ok. 411 412do_integer_encoding(0, _, _, _) -> ok; 413do_integer_encoding(N, I0, Src, Data) -> 414 I1 = (I0 bsl 5) bor (rand:uniform(32) - 1), 415 do_integer_encoding(I1, Src, Data), 416 I2 = -(I1 bxor (rand:uniform(32) - 1)), 417 do_integer_encoding(I2, Src, Data), 418 do_integer_encoding(N-1, I1, Src, Data). 419 420do_integer_encoding(I, Src, Data) -> 421 Str = integer_to_list(I), 422 io:put_chars(Src, [Str,",\n"]), 423 io:put_chars(Data, [Str,",\n"]). 424