From 6db87840174c80225bac5328ffe5e74dad5242f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 6 May 2011 12:28:13 +0200 Subject: Replace io_list_len() with erts_iolist_size() The io_list_len() function returns an int, where a negative return value indicates a type error. One problem is that an int only consists of 32 bits in a 64-bit emulator. Changing the return type to Sint will solve that problem, but in the 32-bit emulator, a large iolist and a iolist with a type error will both return a negative number. (Noticed by Jon Meredith.) Another problem is that for iolists whose total size exceed the word size, the result would be truncated, leading to a subsequent buffer overflow and emulator crash. Therefore, introduce the new erts_iolist_size() function which returns a status indication and writes the result size through a passed pointer. If the result size does not fit in a word, return an overflow indication. --- erts/emulator/test/driver_SUITE.erl | 58 ++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'erts/emulator/test/driver_SUITE.erl') diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl index ffd08f2214..520e3e8c76 100644 --- a/erts/emulator/test/driver_SUITE.erl +++ b/erts/emulator/test/driver_SUITE.erl @@ -179,7 +179,13 @@ outputv_errors(Config) when is_list(Config) -> ?line outputv_errors_1([L|T]) end), outputv_errors_1(42), - ok. + + %% Test iolists that do not fit in the address space. + %% Unfortunately, it would be too slow to test in a 64-bit emulator. + case erlang:system_info(wordsize) of + 4 -> outputv_huge_iolists(); + _ -> ok + end. outputv_bad_types(Test) -> Types = [-1,256,atom,42.0,{a,b,c},make_ref(),fun() -> 42 end, @@ -187,11 +193,61 @@ outputv_bad_types(Test) -> _ = [Test(Type) || Type <- Types], ok. +outputv_huge_iolists() -> + FourGigs = 1 bsl 32, + ?line Sizes = [FourGigs+N || N <- lists:seq(0, 64)] ++ + [1 bsl N || N <- lists:seq(33, 37)], + ?line Base = <<0:(1 bsl 20)/unit:8>>, + [begin + ?line L = build_iolist(Sz, Base), + ?line outputv_errors_1(L) + end || Sz <- Sizes], + ok. + outputv_errors_1(Term) -> Port = open_port({spawn_driver,outputv_drv}, []), {'EXIT',{badarg,_}} = (catch port_command(Port, Term)), port_close(Port). +build_iolist(N, Base) when N < 16 -> + case random:uniform(3) of + 1 -> + <> = Base, + Bin; + _ -> + lists:seq(1, N) + end; +build_iolist(N, Base) when N =< byte_size(Base) -> + case random:uniform(3) of + 1 -> + <> = Base, + Bin; + 2 -> + <> = Base, + [Bin]; + 3 -> + case N rem 2 of + 0 -> + L = build_iolist(N div 2, Base), + [L,L]; + 1 -> + L = build_iolist(N div 2, Base), + [L,L,45] + end + end; +build_iolist(N0, Base) -> + Small = random:uniform(15), + Seq = lists:seq(1, Small), + N = N0 - Small, + case N rem 2 of + 0 -> + L = build_iolist(N div 2, Base), + [L,L|Seq]; + 1 -> + L = build_iolist(N div 2, Base), + [47,L,L|Seq] + end. + outputv_echo(doc) -> ["Test echoing data with a driver that supports outputv."]; outputv_echo(Config) when is_list(Config) -> ?line Dog = test_server:timetrap(test_server:minutes(10)), -- cgit v1.2.3