From f02afa352f14e2dc0f3be4f6854a68b14129c2ba Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Wed, 5 Mar 2014 10:19:01 +0100 Subject: stdlib: Fix a Dets bug with leaking file descriptors Thanks to Hakan Mattson for reporting this bug. --- lib/stdlib/src/dets.erl | 3 ++- lib/stdlib/test/dets_SUITE.erl | 23 ++++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl index 44dad04f43..8c5c86f3b9 100644 --- a/lib/stdlib/src/dets.erl +++ b/lib/stdlib/src/dets.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -1785,6 +1785,7 @@ read_file_header(FileName, Access, RamFile) -> Version =:= 9 -> dets_v9:read_file_header(Fd, FileName); true -> + _ = file:close(Fd), throw({error, {not_a_dets_file, FileName}}) end. diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl index 059d553b00..0f6b76a629 100644 --- a/lib/stdlib/test/dets_SUITE.erl +++ b/lib/stdlib/test/dets_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -52,7 +52,7 @@ simultaneous_open/1, insert_new/1, repair_continuation/1, otp_5487/1, otp_6206/1, otp_6359/1, otp_4738/1, otp_7146/1, otp_8070/1, otp_8856/1, otp_8898/1, otp_8899/1, otp_8903/1, - otp_8923/1, otp_9282/1, otp_11245/1]). + otp_8923/1, otp_9282/1, otp_11245/1, otp_11709/1]). -export([dets_dirty_loop/0]). @@ -109,7 +109,7 @@ all() -> many_clients, otp_4906, otp_5402, simultaneous_open, insert_new, repair_continuation, otp_5487, otp_6206, otp_6359, otp_4738, otp_7146, otp_8070, otp_8856, otp_8898, - otp_8899, otp_8903, otp_8923, otp_9282, otp_11245 + otp_8899, otp_8903, otp_8923, otp_9282, otp_11245, otp_11709 ]. groups() -> @@ -3920,6 +3920,23 @@ otp_11245(Config) when is_list(Config) -> file:delete(File), ok. +otp_11709(doc) -> + ["OTP-11709. Bugfixes."]; +otp_11709(suite) -> + []; +otp_11709(Config) when is_list(Config) -> + Long = <<"a sufficiently long text">>, + + %% Bug: leaking file descriptor + P0 = pps(), + File = filename(otp_11709, Config), + ok = file:write_file(File, Long), + false = dets:is_dets_file(File), + check_pps(P0), + + file:delete(File), + ok. + %% %% Parts common to several test cases %% -- cgit v1.2.3 From e936ccec462760c4bb98679f1b88a7a5a3ead65f Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Wed, 5 Mar 2014 14:14:00 +0100 Subject: stdlib: Fix a Dets bug where files were deleted Instead of deleting the small file when opening it with dets:open_file/2 an error message is returned, mimicking the behaviour when the file is bigger. open_file/1 has been modified to return the same error message when the file is small as when the file is bigger. Thanks to Hakan Mattson for reporting this bug. --- lib/stdlib/src/dets.erl | 9 ++++--- lib/stdlib/test/dets_SUITE.erl | 54 ++++++++++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 26 deletions(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl index 8c5c86f3b9..c32da1624f 100644 --- a/lib/stdlib/src/dets.erl +++ b/lib/stdlib/src/dets.erl @@ -2114,6 +2114,8 @@ test_bchunk_format(Head, Term) -> do_open_file([Fname, Verbose], Parent, Server, Ref) -> case catch fopen2(Fname, Ref) of + {error, {tooshort, _}} -> + err({error, {not_a_dets_file, Fname}}); {error, _Reason} = Error -> err(Error); {ok, Head} -> @@ -2127,11 +2129,10 @@ do_open_file([Fname, Verbose], Parent, Server, Ref) -> [Bad]), {error, {dets_bug, Fname, Bad}} end; -do_open_file([Tab, OpenArgs, Verb], Parent, Server, Ref) -> +do_open_file([Tab, OpenArgs, Verb], Parent, Server, _Ref) -> case catch fopen3(Tab, OpenArgs) of {error, {tooshort, _}} -> - _ = file:delete(OpenArgs#open_args.file), - do_open_file([Tab, OpenArgs, Verb], Parent, Server, Ref); + err({error, {not_a_dets_file, OpenArgs#open_args.file}}); {error, _Reason} = Error -> err(Error); {ok, Head} -> @@ -2487,7 +2488,6 @@ fopen2(Fname, Tab) -> {ok, _} -> Acc = read_write, Ram = false, - %% Fd is not always closed upon error, but exit is soon called. {ok, Fd, FH} = read_file_header(Fname, Acc, Ram), Mod = FH#fileheader.mod, Do = case Mod:check_file_header(FH, Fd) of @@ -2543,7 +2543,6 @@ fopen_existing_file(Tab, OpenArgs) -> ram_file = Ram, delayed_write = CacheSz, auto_save = Auto, access = Acc, version = Version, debug = Debug} = OpenArgs, - %% Fd is not always closed upon error, but exit is soon called. {ok, Fd, FH} = read_file_header(Fname, Acc, Ram), V9 = (Version =:= 9) or (Version =:= default), MinF = (MinSlots =:= default) or (MinSlots =:= FH#fileheader.min_no_slots), diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl index 0f6b76a629..00a5da42ad 100644 --- a/lib/stdlib/test/dets_SUITE.erl +++ b/lib/stdlib/test/dets_SUITE.erl @@ -772,9 +772,9 @@ open_1(Config, V) -> crash(Fname, TypePos), {error, {invalid_type_code,Fname}} = dets:open_file(Fname), truncate(Fname, HeadSize - 10), - {error, {tooshort,Fname}} = dets:open_file(Fname), - {ok, TabRef} = dets:open_file(TabRef, [{file,Fname},{version,V}]), - ok = dets:close(TabRef), + {error,{not_a_dets_file,Fname}} = dets:open_file(Fname), + {error,{not_a_dets_file,Fname}} = + dets:open_file(TabRef, [{file,Fname},{version,V}]), file:delete(Fname), {error,{file_error,{foo,bar},_}} = dets:is_dets_file({foo,bar}), @@ -967,10 +967,12 @@ fast_init_table(Config) -> {'EXIT', _} = (catch dets:init_table(TabRef, fun(foo) -> bar end, {format,bchunk})), dets:close(TabRef), + file:delete(Fname), {ok, _} = dets:open_file(TabRef, Args), {'EXIT', _} = (catch dets:init_table(TabRef, fun() -> foo end, {format,bchunk})), dets:close(TabRef), + file:delete(Fname), {ok, _} = dets:open_file(TabRef, Args), {'EXIT', {badarg, _}} = (catch dets:init_table(TabRef, nofun, {format,bchunk})), @@ -979,10 +981,12 @@ fast_init_table(Config) -> away = (catch dets:init_table(TabRef, fun(_) -> throw(away) end, {format,bchunk})), dets:close(TabRef), + file:delete(Fname), {ok, _} = dets:open_file(TabRef, Args), {error, {init_fun, fopp}} = dets:init_table(TabRef, fun(read) -> fopp end, {format,bchunk}), dets:close(TabRef), + file:delete(Fname), {ok, _} = dets:open_file(TabRef, Args), dets:safe_fixtable(TabRef, true), {error, {fixed_table, TabRef}} = @@ -1389,23 +1393,6 @@ repair(Config, V) -> {ok, TabRef} = dets:open_file(TabRef, [{file,Fname},{version,V}]), ok = ins(TabRef, 100), ok = dets:close(TabRef), - truncate(Fname, HeadSize - 10), - %% a new file is created ('tooshort') - {ok, TabRef} = dets:open_file(TabRef, - [{file,Fname},{version,V}, - {min_no_slots,1000}, - {max_no_slots,1000000}]), - case dets:info(TabRef, no_slots) of - undefined -> ok; - {Min1,Slot1,Max1} -> - true = Min1 =< Slot1, true = Slot1 =< Max1, - true = 1000 < Min1, true = 1000+256 > Min1, - true = 1000000 < Max1, true = (1 bsl 20)+256 > Max1 - end, - 0 = dets:info(TabRef, size), - no_keys_test(TabRef), - _ = histogram(TabRef, silent), - ok = dets:close(TabRef), file:delete(Fname), %% version bump (v8) @@ -3925,6 +3912,7 @@ otp_11709(doc) -> otp_11709(suite) -> []; otp_11709(Config) when is_list(Config) -> + Short = <<"foo">>, Long = <<"a sufficiently long text">>, %% Bug: leaking file descriptor @@ -3934,7 +3922,31 @@ otp_11709(Config) when is_list(Config) -> false = dets:is_dets_file(File), check_pps(P0), - file:delete(File), + %% Bug: deleting file + Args = [[{access, A}, {repair, R}] || + A <- [read, read_write], + R <- [true, false, force]], + Fun1 = fun(S, As) -> + P1 = pps(), + ok = file:write_file(File, S), + {error,{not_a_dets_file,File}} = dets:open_file(File, As), + {ok, S} = file:read_file(File), + check_pps(P1) + end, + Fun2 = fun(S) -> + _ = [Fun1(S, As) || As <- Args], + ok + end, + ok = Fun2(Long), % no change here + ok = Fun2(Short), % mimic the behaviour for longer files + + %% open_file/1 + ok = file:write_file(File, Long), + {error,{not_a_dets_file,File}} = dets:open_file(File), % no change + ok = file:write_file(File, Short), + {error,{not_a_dets_file,File}} = dets:open_file(File), % mimic + + _ = file:delete(File), ok. %% -- cgit v1.2.3