Skip to content

Commit e271199

Browse files
committed
erts: Fix binary_to_term for compressed and zlib >= v1.2.9
Problem: z_stream was incorrectly copied with memcpy which just happened to work with zlib < v1.2.9. Solution: Avoid copying z_stream.
1 parent 07b8f44 commit e271199

File tree

1 file changed

+18
-7
lines changed

1 file changed

+18
-7
lines changed

erts/emulator/beam/external.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,7 @@ typedef struct B2TContext_t {
11931193
} u;
11941194
} B2TContext;
11951195

1196+
static B2TContext* b2t_export_context(Process*, B2TContext* src);
11961197

11971198
static uLongf binary2term_uncomp_size(byte* data, Sint size)
11981199
{
@@ -1225,7 +1226,7 @@ static uLongf binary2term_uncomp_size(byte* data, Sint size)
12251226

12261227
static ERTS_INLINE int
12271228
binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size,
1228-
B2TContext* ctx)
1229+
B2TContext** ctxp, Process* p)
12291230
{
12301231
byte *bytes = data;
12311232
Sint size = data_size;
@@ -1239,8 +1240,8 @@ binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size,
12391240
size--;
12401241
if (size < 5 || *bytes != COMPRESSED) {
12411242
state->extp = bytes;
1242-
if (ctx)
1243-
ctx->state = B2TSizeInit;
1243+
if (ctxp)
1244+
(*ctxp)->state = B2TSizeInit;
12441245
}
12451246
else {
12461247
uLongf dest_len = (Uint32) get_int32(bytes+1);
@@ -1257,16 +1258,26 @@ binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size,
12571258
return -1;
12581259
}
12591260
state->extp = erts_alloc(ERTS_ALC_T_EXT_TERM_DATA, dest_len);
1260-
ctx->reds -= dest_len;
1261+
if (ctxp)
1262+
(*ctxp)->reds -= dest_len;
12611263
}
12621264
state->exttmp = 1;
1263-
if (ctx) {
1265+
if (ctxp) {
1266+
/*
1267+
* Start decompression by exporting trap context
1268+
* so we don't have to deal with deep-copying z_stream.
1269+
*/
1270+
B2TContext* ctx = b2t_export_context(p, *ctxp);
1271+
ASSERT(state = &(*ctxp)->b2ts);
1272+
state = &ctx->b2ts;
1273+
12641274
if (erl_zlib_inflate_start(&ctx->u.uc.stream, bytes, size) != Z_OK)
12651275
return -1;
12661276

12671277
ctx->u.uc.dbytes = state->extp;
12681278
ctx->u.uc.dleft = dest_len;
12691279
ctx->state = B2TUncompressChunk;
1280+
*ctxp = ctx;
12701281
}
12711282
else {
12721283
uLongf dlen = dest_len;
@@ -1308,7 +1319,7 @@ erts_binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size
13081319
{
13091320
Sint res;
13101321

1311-
if (binary2term_prepare(state, data, data_size, NULL) < 0 ||
1322+
if (binary2term_prepare(state, data, data_size, NULL, NULL) < 0 ||
13121323
(res=decoded_size(state->extp, state->extp + state->extsize, 0, NULL)) < 0) {
13131324

13141325
if (state->exttmp)
@@ -1435,7 +1446,7 @@ static Eterm binary_to_term_int(Process* p, Uint32 flags, Eterm bin, Binary* con
14351446
if (ctx->aligned_alloc) {
14361447
ctx->reds -= bin_size / 8;
14371448
}
1438-
if (binary2term_prepare(&ctx->b2ts, bytes, bin_size, ctx) < 0) {
1449+
if (binary2term_prepare(&ctx->b2ts, bytes, bin_size, &ctx, p) < 0) {
14391450
ctx->state = B2TBadArg;
14401451
}
14411452
break;

0 commit comments

Comments
 (0)