1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1999-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(bs_match_int_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 integer/1,signed_integer/1,dynamic/1,more_dynamic/1,mml/1, 25 match_huge_int/1,bignum/1,unaligned_32_bit/1]). 26 27-include_lib("common_test/include/ct.hrl"). 28 29-import(lists, [seq/2]). 30 31suite() -> [{ct_hooks,[ts_install_cth]}]. 32 33all() -> 34 [integer, signed_integer, dynamic, more_dynamic, mml, 35 match_huge_int, bignum, unaligned_32_bit]. 36 37groups() -> 38 []. 39 40init_per_suite(Config) -> 41 Config. 42 43end_per_suite(_Config) -> 44 ok. 45 46init_per_group(_GroupName, Config) -> 47 Config. 48 49end_per_group(_GroupName, Config) -> 50 Config. 51 52 53integer(Config) when is_list(Config) -> 54 0 = get_int(mkbin([])), 55 0 = get_int(mkbin([0])), 56 42 = get_int(mkbin([42])), 57 255 = get_int(mkbin([255])), 58 256 = get_int(mkbin([1,0])), 59 257 = get_int(mkbin([1,1])), 60 258 = get_int(mkbin([1,2])), 61 258 = get_int(mkbin([1,2])), 62 65534 = get_int(mkbin([255,254])), 63 16776455 = get_int(mkbin([255,253,7])), 64 4245492555 = get_int(mkbin([253,13,19,75])), 65 4294967294 = get_int(mkbin([255,255,255,254])), 66 4294967295 = get_int(mkbin([255,255,255,255])), 67 Eight = [200,1,19,128,222,42,97,111], 68 cmp128(Eight, uint(Eight)), 69 fun_clause(catch get_int(mkbin(seq(1,5)))), 70 ok. 71 72get_int(Bin) -> 73 I = get_int1(Bin), 74 get_int(Bin, I). 75 76get_int(Bin0, I) when size(Bin0) < 4 -> 77 Bin = <<0,Bin0/binary>>, 78 I = get_int1(Bin), 79 get_int(Bin, I); 80get_int(_, I) -> I. 81 82get_int1(<<I:0>>) -> I; 83get_int1(<<I:8>>) -> I; 84get_int1(<<I:16>>) -> I; 85get_int1(<<I:24>>) -> I; 86get_int1(<<I:32>>) -> I. 87 88cmp128(<<I:128>>, I) -> equal; 89cmp128(_, _) -> not_equal. 90 91signed_integer(Config) when is_list(Config) -> 92 {no_match,_} = sint(mkbin([])), 93 {no_match,_} = sint(mkbin([1,2,3])), 94 127 = sint(mkbin([127])), 95 -1 = sint(mkbin([255])), 96 -128 = sint(mkbin([128])), 97 42 = sint(mkbin([42,255])), 98 127 = sint(mkbin([127,255])). 99 100sint(Bin) -> 101 case Bin of 102 <<I:8/signed>> -> I; 103 <<I:8/signed,_:3,_:5>> -> I; 104 Other -> {no_match,Other} 105 end. 106 107uint(L) -> uint(L, 0). 108uint([H|T], Acc) -> uint(T, Acc bsl 8 bor H); 109uint([], Acc) -> Acc. 110 111dynamic(Config) when is_list(Config) -> 112 dynamic(mkbin([255]), 8), 113 dynamic(mkbin([255,255]), 16), 114 dynamic(mkbin([255,255,255]), 24), 115 dynamic(mkbin([255,255,255,255]), 32), 116 ok. 117 118dynamic(Bin, S1) when S1 >= 0 -> 119 S2 = size(Bin) * 8 - S1, 120 dynamic(Bin, S1, S2, (1 bsl S1) - 1, (1 bsl S2) - 1), 121 dynamic(Bin, S1-1); 122dynamic(_, _) -> ok. 123 124dynamic(Bin, S1, S2, A, B) -> 125% io:format("~p ~p ~p ~p\n", [S1,S2,A,B]), 126 case Bin of 127 <<A:S1,B:S2>> -> 128 io:format("~p ~p ~p ~p\n", [S1,S2,A,B]), 129 ok; 130 _Other -> erlang:error(badmatch, [Bin,S1,S2,A,B]) 131 end. 132 133%% Extract integers at different alignments and of different sizes. 134more_dynamic(Config) when is_list(Config) -> 135 136 % Unsigned big-endian numbers. 137 Unsigned = fun(Bin, List, SkipBef, N) -> 138 SkipAft = 8*size(Bin) - N - SkipBef, 139 <<_:SkipBef,Int:N,_:SkipAft>> = Bin, 140 Int = make_int(List, N, 0) 141 end, 142 more_dynamic1(Unsigned, erlang:md5(mkbin([42]))), 143 144 %% Signed big-endian numbers. 145 Signed = fun(Bin, List, SkipBef, N) -> 146 SkipAft = 8*size(Bin) - N - SkipBef, 147 <<_:SkipBef,Int:N/signed,_:SkipAft>> = Bin, 148 case make_signed_int(List, N) of 149 Int -> ok; 150 Other -> 151 io:format("Bin = ~p,", [Bin]), 152 io:format("SkipBef = ~p, N = ~p", [SkipBef,N]), 153 io:format("Expected ~p, got ~p", [Int,Other]), 154 ct:fail(signed_big_endian_fail) 155 end 156 end, 157 more_dynamic1(Signed, erlang:md5(mkbin([43]))), 158 159 %% Unsigned little-endian numbers. 160 UnsLittle = fun(Bin, List, SkipBef, N) -> 161 SkipAft = 8*size(Bin) - N - SkipBef, 162 <<_:SkipBef,Int:N/little,_:SkipAft>> = Bin, 163 Int = make_int(big_to_little(List, N), N, 0) 164 end, 165 more_dynamic1(UnsLittle, erlang:md5(mkbin([44]))), 166 167 %% Signed little-endian numbers. 168 SignLittle = fun(Bin, List, SkipBef, N) -> 169 SkipAft = 8*size(Bin) - N - SkipBef, 170 <<_:SkipBef,Int:N/signed-little,_:SkipAft>> = Bin, 171 Little = big_to_little(List, N), 172 Int = make_signed_int(Little, N) 173 end, 174 more_dynamic1(SignLittle, erlang:md5(mkbin([45]))), 175 176 ok. 177 178more_dynamic1(Action, Bin) -> 179 BitList = bits_to_list(binary_to_list(Bin), 16#80), 180 more_dynamic2(Action, Bin, BitList, 0). 181 182more_dynamic2(Action, Bin, [_|T]=List, Bef) -> 183 more_dynamic3(Action, Bin, List, Bef, size(Bin)*8), 184 more_dynamic2(Action, Bin, T, Bef+1); 185more_dynamic2(_, _, [], _) -> ok. 186 187more_dynamic3(Action, Bin, List, Bef, Aft) when Bef =< Aft -> 188%% io:format("~p, ~p", [Bef,Aft-Bef]), 189 Action(Bin, List, Bef, Aft-Bef), 190 more_dynamic3(Action, Bin, List, Bef, Aft-1); 191more_dynamic3(_, _, _, _, _) -> ok. 192 193big_to_little(List, N) -> big_to_little(List, N, []). 194 195big_to_little([B0,B1,B2,B3,B4,B5,B6,B7|T], N, Acc) when N >= 8 -> 196 big_to_little(T, N-8, [B0,B1,B2,B3,B4,B5,B6,B7|Acc]); 197big_to_little(List, N, Acc) -> lists:sublist(List, 1, N) ++ Acc. 198 199make_signed_int(_List, 0) -> 0; 200make_signed_int([0|_]=List, N) -> make_int(List, N, 0); 201make_signed_int([1|_]=List0, N) -> 202 List1 = reversed_sublist(List0, N, []), 203 List2 = two_complement_and_reverse(List1, 1, []), 204 -make_int(List2, length(List2), 0). 205 206reversed_sublist(_List, 0, Acc) -> Acc; 207reversed_sublist([H|T], N, Acc) -> reversed_sublist(T, N-1, [H|Acc]). 208 209two_complement_and_reverse([H|T], Carry, Acc) -> 210 Sum = 1-H+Carry, 211 two_complement_and_reverse(T, Sum div 2, [Sum rem 2|Acc]); 212two_complement_and_reverse([], Carry, Acc) -> [Carry|Acc]. 213 214make_int(_List, 0, Acc) -> Acc; 215make_int([H|T], N, Acc) -> make_int(T, N-1, Acc bsl 1 bor H). 216 217bits_to_list([_|T], 0) -> bits_to_list(T, 16#80); 218bits_to_list([H|_]=List, Mask) -> 219 [case H band Mask of 220 0 -> 0; 221 _ -> 1 222 end|bits_to_list(List, Mask bsr 1)]; 223bits_to_list([], _) -> []. 224 225fun_clause({'EXIT',{function_clause,_}}) -> ok. 226mkbin(L) when is_list(L) -> list_to_binary(L). 227 228 229mml(Config) when is_list(Config) -> 230 single_byte_binary = mml_choose(<<42>>), 231 multi_byte_binary = mml_choose(<<42,43>>). 232 233mml_choose(<<_A:8>>) -> single_byte_binary; 234mml_choose(<<_A:8,_T/binary>>) -> multi_byte_binary. 235 236match_huge_int(Config) when is_list(Config) -> 237 case ?MODULE of 238 bs_match_int_no_opt_SUITE -> 239 %% This test case is written with the assumption that 240 %% bs_skip2 instructions are used when the value of the 241 %% extracted segment will not be used. In OTP 21 and earlier, that 242 %% assumption was always true, because the bs_skip optimization 243 %% was included in v3_codegen and could not be disabled. 244 %% In OTP 22, the bs_skip optimization is done by beam_ssa_opt 245 %% and is disabled. 246 %% 247 %% On memory-constrained computers, using bs_get_integer2 248 %% instructions may cause the runtime system to terminate 249 %% because of insufficient memory. 250 {skip, "unoptimized code would use too much memory"}; 251 bs_match_int_SUITE -> 252 Sz = 1 bsl 27, 253 Bin = <<0:Sz,13:8>>, 254 skip_huge_int_1(Sz, Bin), 255 0 = match_huge_int_1(Sz, Bin), 256 257 %% Test overflowing the size of an integer field. 258 nomatch = overflow_huge_int_skip_32(Bin), 259 case erlang:system_info(wordsize) of 260 4 -> 261 nomatch = overflow_huge_int_32(Bin); 262 8 -> 263 %% An attempt will be made to allocate heap space for 264 %% the bignum (which will probably fail); only if the 265 %% allocation succeeds will the matching fail because 266 %% the binary is too small. 267 ok 268 end, 269 nomatch = overflow_huge_int_skip_64(Bin), 270 nomatch = overflow_huge_int_64(Bin), 271 272 %% Test overflowing the size of an integer field using 273 %% variables as sizes. 274 Sizes = case erlang:system_info(wordsize) of 275 4 -> lists:seq(25, 32); 276 8 -> [] 277 end ++ lists:seq(50, 64), 278 ok = overflow_huge_int_unit128(Bin, Sizes) 279 end. 280 281overflow_huge_int_unit128(Bin, [Sz0|Sizes]) -> 282 Sz = id(1 bsl Sz0), 283 case Bin of 284 <<_:Sz/unit:128,0,_/binary>> -> 285 {error,Sz}; 286 _ -> 287 case Bin of 288 <<Var:Sz/unit:128,0,_/binary>> -> 289 {error,Sz,Var}; 290 _ -> 291 overflow_huge_int_unit128(Bin, Sizes) 292 end 293 end; 294overflow_huge_int_unit128(_, []) -> ok. 295 296match_huge_int_1(I, Bin) -> 297 <<Int:I,13>> = Bin, 298 Int. 299 300skip_huge_int_1(I, Bin) -> 301 <<_:I,13>> = Bin. 302 303overflow_huge_int_skip_32(<<_:4294967296,0,_/binary>>) -> 1; % 1 bsl 32 304overflow_huge_int_skip_32(<<_:33554432/unit:128,0,_/binary>>) -> 2; % 1 bsl 25 305overflow_huge_int_skip_32(<<_:67108864/unit:64,0,_/binary>>) -> 3; % 1 bsl 26 306overflow_huge_int_skip_32(<<_:134217728/unit:32,0,_/binary>>) -> 4; % 1 bsl 27 307overflow_huge_int_skip_32(<<_:268435456/unit:16,0,_/binary>>) -> 5; % 1 bsl 28 308overflow_huge_int_skip_32(<<_:536870912/unit:8,0,_/binary>>) -> 6; % 1 bsl 29 309overflow_huge_int_skip_32(<<_:1073741824/unit:8,0,_/binary>>) -> 7; % 1 bsl 30 310overflow_huge_int_skip_32(<<_:2147483648/unit:8,0,_/binary>>) -> 8; % 1 bsl 31 311overflow_huge_int_skip_32(_) -> nomatch. 312 313overflow_huge_int_32(<<Int:4294967296,_/binary>>) -> {1,Int}; % 1 bsl 32 314overflow_huge_int_32(<<Int:33554432/unit:128,0,_/binary>>) -> {2,Int}; % 1 bsl 25 315overflow_huge_int_32(<<Int:67108864/unit:128,0,_/binary>>) -> {3,Int}; % 1 bsl 26 316overflow_huge_int_32(<<Int:134217728/unit:128,0,_/binary>>) -> {4,Int}; % 1 bsl 27 317overflow_huge_int_32(<<Int:268435456/unit:128,0,_/binary>>) -> {5,Int}; % 1 bsl 28 318overflow_huge_int_32(<<Int:536870912/unit:128,0,_/binary>>) -> {6,Int}; % 1 bsl 29 319overflow_huge_int_32(<<Int:1073741824/unit:128,0,_/binary>>) -> {7,Int}; % 1 bsl 30 320overflow_huge_int_32(<<Int:2147483648/unit:128,0,_/binary>>) -> {8,Int}; % 1 bsl 31 321overflow_huge_int_32(_) -> nomatch. 322 323overflow_huge_int_skip_64(<<_:18446744073709551616,_/binary>>) -> 1; % 1 bsl 64 324overflow_huge_int_skip_64(<<_:144115188075855872/unit:128,0,_/binary>>) -> 2; % 1 bsl 57 325overflow_huge_int_skip_64(<<_:288230376151711744/unit:64,0,_/binary>>) -> 3; % 1 bsl 58 326overflow_huge_int_skip_64(<<_:576460752303423488/unit:32,0,_/binary>>) -> 4; % 1 bsl 59 327overflow_huge_int_skip_64(<<_:1152921504606846976/unit:16,0,_/binary>>) -> 5; % 1 bsl 60 328overflow_huge_int_skip_64(<<_:2305843009213693952/unit:8,0,_/binary>>) -> 6; % 1 bsl 61 329overflow_huge_int_skip_64(<<_:4611686018427387904/unit:8,0,_/binary>>) -> 7; % 1 bsl 62 330overflow_huge_int_skip_64(<<_:9223372036854775808/unit:8,0,_/binary>>) -> 8; % 1 bsl 63 331overflow_huge_int_skip_64(_) -> nomatch. 332 333overflow_huge_int_64(<<Int:18446744073709551616,_/binary>>) -> {1,Int}; % 1 bsl 64 334overflow_huge_int_64(<<Int:144115188075855872/unit:128,0,_/binary>>) -> {2,Int}; % 1 bsl 57 335overflow_huge_int_64(<<Int:288230376151711744/unit:128,0,_/binary>>) -> {3,Int}; % 1 bsl 58 336overflow_huge_int_64(<<Int:576460752303423488/unit:128,0,_/binary>>) -> {4,Int}; % 1 bsl 59 337overflow_huge_int_64(<<Int:1152921504606846976/unit:128,0,_/binary>>) -> {5,Int}; % 1 bsl 60 338overflow_huge_int_64(<<Int:2305843009213693952/unit:128,0,_/binary>>) -> {6,Int}; % 1 bsl 61 339overflow_huge_int_64(<<Int:4611686018427387904/unit:128,0,_/binary>>) -> {7,Int}; % 1 bsl 62 340overflow_huge_int_64(<<Int:9223372036854775808/unit:128,0,_/binary>>) -> {8,Int}; % 1 bsl 63 341overflow_huge_int_64(_) -> nomatch. 342 343bignum(Config) when is_list(Config) -> 344 Bin = id(<<42,0:1024/unit:8,43>>), 345 <<42:1025/little-integer-unit:8,_:8>> = Bin, 346 <<_:8,43:1025/integer-unit:8>> = Bin, 347 348 BignumBin = id(<<0:512/unit:8,258254417031933722623:9/unit:8>>), 349 <<258254417031933722623:(512+9)/unit:8>> = BignumBin, 350 erlang:garbage_collect(), %Search for holes in debug-build 351 352 %% ERL-1391 353 _ = [begin 354 N = (LHS bsl RHS), 355 <<N:64/integer-little-signed>> = id(<<N:64/integer-little-signed>>) 356 end || LHS <- [-1, 1], RHS <- lists:seq(1, 62)], 357 358 MPos = (1 bsl 63) - 1, 359 <<MPos:64/integer-little-signed>> = id(<<MPos:64/integer-little-signed>>), 360 MNeg = -1 bsl 63, 361 <<MNeg:64/integer-little-signed>> = id(<<MNeg:64/integer-little-signed>>), 362 363 ok. 364 365unaligned_32_bit(Config) when is_list(Config) -> 366 %% There used to be a risk for heap overflow (fixed in R11B-5). 367 L = unaligned_32_bit_1(<<-1:(64*1024)>>), 368 unaligned_32_bit_verify(L, 1638). 369 370unaligned_32_bit_1(<<1:1,U:32,_:7,T/binary>>) -> 371 [U|unaligned_32_bit_1(T)]; 372unaligned_32_bit_1(_) -> 373 []. 374 375unaligned_32_bit_verify([], 0) -> ok; 376unaligned_32_bit_verify([4294967295|T], N) when N > 0 -> 377 unaligned_32_bit_verify(T, N-1). 378 379id(I) -> I. 380