From 32dd52d5b35793470930a2c7a7394316bca5abd4 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Wed, 20 Oct 2010 15:39:20 +0200 Subject: Fix a bug concerning bchunk(), match() and select() If a Dets table was closed after calling bchunk/2, match/1,3, match_object/1,3, or select/1,3 and then opened again, a subsequent call using the returned continuation would normally return a reply. This bug has fixed; now the call fails with reason 'badarg'. --- lib/stdlib/src/dets.erl | 71 ++++++++++++++++++++++-------------------- lib/stdlib/test/dets_SUITE.erl | 29 +++++++++++++++-- 2 files changed, 63 insertions(+), 37 deletions(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl index 4584b8184f..cf68958a9f 100644 --- a/lib/stdlib/src/dets.erl +++ b/lib/stdlib/src/dets.erl @@ -147,6 +147,7 @@ bin, % small chunk not consumed, or 'eof' at end-of-file alloc, % the part of the file not yet scanned, mostly a binary tab, + proc, % the pid of the Dets process match_program % true | compiled_match_spec() | undefined }). @@ -208,8 +209,6 @@ all() -> bchunk(Tab, start) -> badarg(treq(Tab, {bchunk_init, Tab}), [Tab, start]); -bchunk(Tab, #dets_cont{bin = eof, tab = Tab}) -> - '$end_of_table'; bchunk(Tab, #dets_cont{what = bchunk, tab = Tab} = State) -> badarg(treq(Tab, {bchunk, State}), [Tab, State]); bchunk(Tab, Term) -> @@ -722,11 +721,14 @@ init_chunk_match(Tab, Pat, What, N) when is_integer(N), N >= 0; N =:= default -> case compile_match_spec(What, Pat) of {Spec, MP} -> - case req(dets_server:get_pid(Tab), {match, MP, Spec, N}) of + Proc = dets_server:get_pid(Tab), + case req(Proc, {match, MP, Spec, N}) of {done, L} -> - {L, #dets_cont{tab = Tab, what = What, bin = eof}}; + {L, #dets_cont{tab = Tab, proc = Proc, what = What, + bin = eof}}; {cont, State} -> - chunk_match(State#dets_cont{what = What, tab = Tab}); + chunk_match(State#dets_cont{what = What, tab = Tab, + proc = Proc}); Error -> Error end; @@ -736,34 +738,28 @@ init_chunk_match(Tab, Pat, What, N) when is_integer(N), N >= 0; init_chunk_match(_Tab, _Pat, _What, _) -> badarg. -chunk_match(State) -> - case catch dets_server:get_pid(State#dets_cont.tab) of - {'EXIT', _Reason} -> - badarg; - _Proc when State#dets_cont.bin =:= eof -> - '$end_of_table'; - Proc -> - case req(Proc, {match_init, State}) of - {cont, {Bins, NewState}} -> - MP = NewState#dets_cont.match_program, - case catch do_foldl_bins(Bins, MP) of - {'EXIT', _} -> - case ets:is_compiled_ms(MP) of - true -> - Bad = dets_utils:bad_object(chunk_match, - Bins), - req(Proc, {corrupt, Bad}); - false -> - badarg - end; - [] -> - chunk_match(NewState); - Terms -> - {Terms, NewState} - end; - Error -> - Error - end +chunk_match(#dets_cont{proc = Proc}=State) -> + case req(Proc, {match_init, State}) of + '$end_of_table'=Reply -> + Reply; + {cont, {Bins, NewState}} -> + MP = NewState#dets_cont.match_program, + case catch do_foldl_bins(Bins, MP) of + {'EXIT', _} -> + case ets:is_compiled_ms(MP) of + true -> + Bad = dets_utils:bad_object(chunk_match, Bins), + req(Proc, {corrupt, Bad}); + false -> + badarg + end; + [] -> + chunk_match(NewState); + Terms -> + {Terms, NewState} + end; + Error -> + Error end. do_foldl_bins(Bins, true) -> @@ -1578,13 +1574,18 @@ do_bchunk_init(Head, Tab) -> L = dets_utils:all_allocated(H2), C0 = #dets_cont{no_objs = default, bin = <<>>, alloc = L}, BinParms = term_to_binary(Parms), - {H2, {C0#dets_cont{tab = Tab, what = bchunk}, [BinParms]}} + {H2, {C0#dets_cont{tab = Tab, proc = self(),what = bchunk}, + [BinParms]}} end; {NewHead, _} = HeadError when is_record(NewHead, head) -> HeadError end. %% -> {NewHead, {cont(), [binary()]}} | {NewHead, Error} +do_bchunk(Head, #dets_cont{proc = Proc}) when Proc =/= self() -> + {Head, badarg}; +do_bchunk(Head, #dets_cont{bin = eof}) -> + {Head, '$end_of_table'}; do_bchunk(Head, State) -> case dets_v9:read_bchunks(Head, State#dets_cont.alloc) of {error, Reason} -> @@ -1954,6 +1955,8 @@ flookup_keys(Head, Keys) -> end. %% -> {NewHead, Result} +fmatch_init(Head, #dets_cont{bin = eof}) -> + {Head, '$end_of_table'}; fmatch_init(Head, C) -> case scan(Head, C) of {scan_error, Reason} -> diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl index 760e610e00..3c938313b4 100644 --- a/lib/stdlib/test/dets_SUITE.erl +++ b/lib/stdlib/test/dets_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2010. 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 @@ -50,7 +50,7 @@ otp_4208/1, otp_4989/1, many_clients/1, otp_4906/1, otp_5402/1, 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_8070/1, otp_8903/1]). -export([dets_dirty_loop/0]). @@ -108,7 +108,7 @@ all(suite) -> cache_duplicate_bags_v9, otp_4208, otp_4989, 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_7146, otp_8070, otp_8903]} end. not_run(suite) -> []; @@ -3701,6 +3701,29 @@ otp_8070(Config) when is_list(Config) -> file:delete(File), ok. +otp_8903(doc) -> + ["OTP-8903. bchunk/match/select bug."]; +otp_8903(suite) -> + []; +otp_8903(Config) when is_list(Config) -> + Tab = otp_8903, + File = filename(Tab, Config), + ?line {ok,T} = dets:open_file(bug, [{file,File}]), + ?line ok = dets:insert(T, [{1,a},{2,b},{3,c}]), + ?line dets:safe_fixtable(T, true), + ?line {[_],C1} = dets:match_object(T, '_', 1), + ?line {BC1,_D} = dets:bchunk(T, start), + ?line ok = dets:close(T), + ?line {'EXIT', {badarg, _}} = (catch {foo,dets:match_object(C1)}), + ?line {'EXIT', {badarg, _}} = (catch {foo,dets:bchunk(T, BC1)}), + ?line {ok,T} = dets:open_file(bug, [{file,File}]), + ?line false = dets:info(T, safe_fixed), + ?line {'EXIT', {badarg, _}} = (catch {foo,dets:match_object(C1)}), + ?line {'EXIT', {badarg, _}} = (catch {foo,dets:bchunk(T, BC1)}), + ?line ok = dets:close(T), + file:delete(File), + ok. + %% %% Parts common to several test cases %% -- cgit v1.2.3