erlang zlib引起的系统崩溃记录
原创文章,转载请注明: 转载自庆亮的博客-webgame架构
本文链接地址: erlang zlib引起的系统崩溃记录
author: 庆亮 (qing.liang.cn@gmail.com / http://twitter.com/qingliangcn )
date: 2010-07-12
之前同事遇到一个问题,系统运行一段时间后有大量的port没有正常关闭而导致beam崩溃,经过定位发现是由于zlib引起的。过程很简单,没什么技术含量,记录一下。
错误信息大致是这样的(原因是传入的数据不是zlib压缩格式):
** exception error: data_error
in function zlib:call/3
in call from zlib:inflate/2
in call from zlib:uncompress/1
看call的实现,应该是这里,erlang:error(list_to_atom(Res)),
看了下zlib的解压源码:
-spec uncompress(binary()) -> binary().
uncompress(Binary) when byte_size(Binary) >= 8 ->
Z = open(),
inflateInit(Z),
Bs = inflate(Z, Binary),
inflateEnd(Z),
close(Z),
list_to_binary(Bs);
uncompress(Binary) when is_binary(Binary) -> erlang:error(data_error);
uncompress(_) -> erlang:error(badarg).
open是返回一个port
open() ->
open_port({spawn, "zlib_drv"}, [binary]).
close则关闭一个port
close(Z) ->
try
true = port_close(Z),
receive %In case the caller is the owner and traps exits
{'EXIT',Z,_} -> ok
after 0 -> ok
end
catch _:_ -> erlang:error(badarg)
end.inflate(Z, Data) ->
try port_command(Z, Data) of
true ->
call(Z, ?INFLATE, <<?Z_NO_FLUSH:32>>),
collect(Z)
catch
error:_Err ->
flush(Z),
erlang:error(badarg)
end.
call(Z, Cmd, Arg) ->
try port_control(Z, Cmd, Arg) of
[0|Res] -> list_to_atom(Res);
[1|Res] ->
flush(Z),
erlang:error(list_to_atom(Res));
[2,A,B,C,D] ->
(A bsl 24)+(B bsl 16)+(C bsl 8)+D;
[3,A,B,C,D] ->
erlang:error({need_dictionary,(A bsl 24)+(B bsl 16)+(C bsl 8)+D})
catch
error:badarg -> %% Rethrow loses port_control from stacktrace.
erlang:error(badarg)
end.
erlang在遇到port返回错误时直接error了,典型的非防御性编程。 但是个人认为这个接口应该在抛出错误之前关闭掉打开的port。

