diff options
author | Daniel White <[email protected]> | 2015-01-17 19:20:41 +1100 |
---|---|---|
committer | Daniel White <[email protected]> | 2015-01-17 19:37:16 +1100 |
commit | aaa7c91756da6eb4435c9a23f4725dcc1dc147aa (patch) | |
tree | a1da4bfee9a41fbb95faf01bd8064ea96c8a492b /lib/stdlib/src/zip.erl | |
parent | 905824012cef106e7bd3796bff36a2aa04b58850 (diff) | |
download | otp-aaa7c91756da6eb4435c9a23f4725dcc1dc147aa.tar.gz otp-aaa7c91756da6eb4435c9a23f4725dcc1dc147aa.tar.bz2 otp-aaa7c91756da6eb4435c9a23f4725dcc1dc147aa.zip |
Prevent zip:zip_open/1,2 from leaking ports
The case was discovered where a parent process would exit before closing
the zip file. The result was that a port would be left open
indefinitely, as the small zip server would not detect this condition.
By comparison, the file module will close the associated port when the
parent exits for any reason. This change would make the zip module more
consistent with the semantics of similar modules.
This change is breaking for any callers expecting to pass the handle to
another process for processing (assuming it exits).
Diffstat (limited to 'lib/stdlib/src/zip.erl')
-rw-r--r-- | lib/stdlib/src/zip.erl | 26 |
1 files changed, 17 insertions, 9 deletions
diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl index b768c6d0b9..cbd326ae92 100644 --- a/lib/stdlib/src/zip.erl +++ b/lib/stdlib/src/zip.erl @@ -1114,15 +1114,19 @@ local_file_header_from_info_method_name(#file_info{mtime = MTime}, file_name_length = length(Name), extra_field_length = 0}. +server_init(Parent) -> + %% we want to know if our parent dies + process_flag(trap_exit, true), + server_loop(Parent, not_open). %% small, simple, stupid zip-archive server -server_loop(OpenZip) -> +server_loop(Parent, OpenZip) -> receive {From, {open, Archive, Options}} -> case openzip_open(Archive, Options) of {ok, NewOpenZip} -> From ! {self(), {ok, self()}}, - server_loop(NewOpenZip); + server_loop(Parent, NewOpenZip); Error -> From ! {self(), Error} end; @@ -1130,19 +1134,22 @@ server_loop(OpenZip) -> From ! {self(), openzip_close(OpenZip)}; {From, get} -> From ! {self(), openzip_get(OpenZip)}, - server_loop(OpenZip); + server_loop(Parent, OpenZip); {From, {get, FileName}} -> From ! {self(), openzip_get(FileName, OpenZip)}, - server_loop(OpenZip); + server_loop(Parent, OpenZip); {From, list_dir} -> From ! {self(), openzip_list_dir(OpenZip)}, - server_loop(OpenZip); + server_loop(Parent, OpenZip); {From, {list_dir, Opts}} -> From ! {self(), openzip_list_dir(OpenZip, Opts)}, - server_loop(OpenZip); + server_loop(Parent, OpenZip); {From, get_state} -> From ! {self(), OpenZip}, - server_loop(OpenZip); + server_loop(Parent, OpenZip); + {'EXIT', Parent, Reason} -> + openzip_close(OpenZip), + exit({parent_died, Reason}); _ -> {error, bad_msg} end. @@ -1162,8 +1169,9 @@ zip_open(Archive) -> zip_open(Archive, []). Reason :: term()). zip_open(Archive, Options) -> - Pid = spawn(fun() -> server_loop(not_open) end), - request(self(), Pid, {open, Archive, Options}). + Self = self(), + Pid = spawn_link(fun() -> server_init(Self) end), + request(Self, Pid, {open, Archive, Options}). -spec(zip_get(ZipHandle) -> {ok, [Result]} | {error, Reason} when ZipHandle :: pid(), |