From 2fbe8cc9b3f6f443ccccfaa485b05966aacc65d9 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 15 Mar 2012 12:13:28 +0100 Subject: Fix port leaks in zlib zip,unzip,gzip,gunzip,compress and uncompress did not close the port when given invalid data argument. Fixed by putting close in "try-after". A closed port could in same cases get stuck in limbo due to data in io-queue. Fixed by adding a flush callback. --- erts/emulator/drivers/common/zlib_drv.c | 10 ++++- erts/preloaded/ebin/zlib.beam | Bin 12432 -> 12804 bytes erts/preloaded/src/zlib.erl | 72 +++++++++++++++++++++----------- lib/kernel/test/zlib_SUITE.erl | 19 +++++++++ 4 files changed, 76 insertions(+), 25 deletions(-) diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c index da4a17db1a..a4b02b845e 100644 --- a/erts/emulator/drivers/common/zlib_drv.c +++ b/erts/emulator/drivers/common/zlib_drv.c @@ -64,6 +64,7 @@ static int zlib_init(void); static ErlDrvData zlib_start(ErlDrvPort port, char* buf); static void zlib_stop(ErlDrvData e); +static void zlib_flush(ErlDrvData e); static ErlDrvSSizeT zlib_ctl(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen); static void zlib_outputv(ErlDrvData drv_data, ErlIOVec *ev); @@ -82,7 +83,7 @@ ErlDrvEntry zlib_driver_entry = { NULL, /* timeout */ zlib_outputv, NULL, /* read_async */ - NULL, /* flush */ + zlib_flush, NULL, /* call */ NULL, /* event */ ERL_DRV_EXTENDED_MARKER, @@ -410,6 +411,13 @@ static void zlib_stop(ErlDrvData e) driver_free(d); } +static void zlib_flush(ErlDrvData drv_data) +{ + ZLibData* d = (ZLibData*) drv_data; + + driver_deq(d->port, driver_sizeq(d->port)); +} + static ErlDrvSSizeT zlib_ctl(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam index bf88a51502..7a1f896d36 100644 Binary files a/erts/preloaded/ebin/zlib.beam and b/erts/preloaded/ebin/zlib.beam differ diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index 210532edac..71b730016d 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -349,10 +349,14 @@ getQSize(Z) -> Compressed :: binary(). compress(Data) -> Z = open(), - deflateInit(Z, default), - Bs = deflate(Z, Data, finish), - deflateEnd(Z), - close(Z), + Bs = try + deflateInit(Z, default), + B = deflate(Z, Data, finish), + deflateEnd(Z), + B + after + close(Z) + end, iolist_to_binary(Bs). -spec uncompress(Data) -> Decompressed when @@ -364,10 +368,14 @@ uncompress(Data) -> if Size >= 8 -> Z = open(), - inflateInit(Z), - Bs = inflate(Z, Data), - inflateEnd(Z), - close(Z), + Bs = try + inflateInit(Z), + B = inflate(Z, Data), + inflateEnd(Z), + B + after + close(Z) + end, iolist_to_binary(Bs); true -> erlang:error(data_error) @@ -383,10 +391,14 @@ uncompress(Data) -> Compressed :: binary(). zip(Data) -> Z = open(), - deflateInit(Z, default, deflated, -?MAX_WBITS, 8, default), - Bs = deflate(Z, Data, finish), - deflateEnd(Z), - close(Z), + Bs = try + deflateInit(Z, default, deflated, -?MAX_WBITS, 8, default), + B = deflate(Z, Data, finish), + deflateEnd(Z), + B + after + close(Z) + end, iolist_to_binary(Bs). -spec unzip(Data) -> Decompressed when @@ -394,10 +406,14 @@ zip(Data) -> Decompressed :: binary(). unzip(Data) -> Z = open(), - inflateInit(Z, -?MAX_WBITS), - Bs = inflate(Z, Data), - inflateEnd(Z), - close(Z), + Bs = try + inflateInit(Z, -?MAX_WBITS), + B = inflate(Z, Data), + inflateEnd(Z), + B + after + close(Z) + end, iolist_to_binary(Bs). -spec gzip(Data) -> Compressed when @@ -405,10 +421,14 @@ unzip(Data) -> Compressed :: binary(). gzip(Data) -> Z = open(), - deflateInit(Z, default, deflated, 16+?MAX_WBITS, 8, default), - Bs = deflate(Z, Data, finish), - deflateEnd(Z), - close(Z), + Bs = try + deflateInit(Z, default, deflated, 16+?MAX_WBITS, 8, default), + B = deflate(Z, Data, finish), + deflateEnd(Z), + B + after + close(Z) + end, iolist_to_binary(Bs). -spec gunzip(Data) -> Decompressed when @@ -416,10 +436,14 @@ gzip(Data) -> Decompressed :: binary(). gunzip(Data) -> Z = open(), - inflateInit(Z, 16+?MAX_WBITS), - Bs = inflate(Z, Data), - inflateEnd(Z), - close(Z), + Bs = try + inflateInit(Z, 16+?MAX_WBITS), + B = inflate(Z, Data), + inflateEnd(Z), + B + after + close(Z) + end, iolist_to_binary(Bs). -spec collect(zstream()) -> iolist(). diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl index 74bafe8935..e0fd0f5d19 100644 --- a/lib/kernel/test/zlib_SUITE.erl +++ b/lib/kernel/test/zlib_SUITE.erl @@ -73,6 +73,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [{group, api}, {group, examples}, {group, func}, smp, + otp_9981, otp_7359]. groups() -> @@ -964,6 +965,24 @@ otp_7359_def_inf(Data,{DefSize,InfSize}) -> ?line ok = zlib:close(ZInf), ok. +otp_9981(Config) when is_list(Config) -> + Ports = lists:sort(erlang:ports()), + Invalid = <<"My invalid data">>, + catch zlib:compress(invalid), + Ports = lists:sort(erlang:ports()), + catch zlib:uncompress(Invalid), + Ports = lists:sort(erlang:ports()), + catch zlib:zip(invalid), + Ports = lists:sort(erlang:ports()), + catch zlib:unzip(Invalid), + Ports = lists:sort(erlang:ports()), + catch zlib:gzip(invalid), + Ports = lists:sort(erlang:ports()), + catch zlib:gunzip(Invalid), + Ports = lists:sort(erlang:ports()), + ok. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Helps with testing directly %%%%%%%%%%%%% -- cgit v1.2.3