Skip to content

Commit bd4dfcc

Browse files
committed
zstd: Fix copy of dict binary to environment
If we don't make a copy of the binary before referencing it in the dict and it is a heap binary, the binary will be released upon the next GC and the dict will segfault.
1 parent 35037ba commit bd4dfcc

File tree

3 files changed

+44
-25
lines changed

3 files changed

+44
-25
lines changed

erts/emulator/nifs/common/zstd_nif.c

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -820,29 +820,34 @@ static ERL_NIF_TERM create_cdict_nif(
820820
ErlNifBinary bin;
821821
int level;
822822

823-
if (!enif_inspect_iolist_as_binary(env, argv[0], &bin) ||
824-
!enif_get_int(env, argv[1], &level)) {
823+
if (!enif_is_binary(env, argv[0]) || !enif_get_int(env, argv[1], &level)) {
825824
return enif_make_badarg(env);
826825
} else {
827-
ERL_NIF_TERM result;
828-
ZstdDict *dict;
829-
ZSTD_CDict *cdict = ZSTD_createCDict_advanced(bin.data, bin.size,
826+
ERL_NIF_TERM result, binary_copy;
827+
ZstdDict *dictp, dict;
828+
829+
dict.env = enif_alloc_env();
830+
binary_copy = enif_make_copy(dict.env, argv[0]);
831+
832+
(void)enif_inspect_binary(dict.env, binary_copy, &bin);
833+
834+
dict.c = ZSTD_createCDict_advanced(bin.data, bin.size,
830835
ZSTD_dlm_byRef, ZSTD_dct_auto,
831836
ZSTD_getCParams(level, 0, bin.size),
832837
zstd_customMem);
833838

834-
if (!cdict)
839+
if (!dict.c) {
840+
enif_free_env(dict.env);
835841
return enif_make_tuple2(env, am_error,
836842
enif_make_atom(env, "invalid_compress_dict"));
843+
}
837844

838-
dict = enif_alloc_resource(compress_dict_type, sizeof(ZstdDict));
845+
dictp = enif_alloc_resource(compress_dict_type, sizeof(ZstdDict));
839846

840-
dict->c = cdict;
841-
dict->env = enif_alloc_env();
842-
enif_make_binary(dict->env, &bin);
847+
*dictp = dict;
843848

844-
result = enif_make_resource(env, (void *)dict);
845-
enif_release_resource((void *)dict);
849+
result = enif_make_resource(env, (void *)dictp);
850+
enif_release_resource((void *)dictp);
846851
return result;
847852
}
848853
}
@@ -857,26 +862,32 @@ static ERL_NIF_TERM create_ddict_nif(
857862
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
858863
ErlNifBinary bin;
859864

860-
if (!enif_inspect_iolist_as_binary(env, argv[0], &bin)) {
865+
if (!enif_is_binary(env, argv[0])) {
861866
return enif_make_badarg(env);
862867
} else {
863-
ERL_NIF_TERM result;
864-
ZstdDict *dict;
865-
ZSTD_DDict *ddict = ZSTD_createDDict_advanced(bin.data, bin.size,
868+
ERL_NIF_TERM result, binary_copy;
869+
ZstdDict *dictp, dict;
870+
871+
dict.env = enif_alloc_env();
872+
binary_copy = enif_make_copy(dict.env, argv[0]);
873+
874+
(void)enif_inspect_binary(dict.env, binary_copy, &bin);
875+
876+
dict.d = ZSTD_createDDict_advanced(bin.data, bin.size,
866877
ZSTD_dlm_byRef, ZSTD_dct_auto, zstd_customMem);
867878

868-
if (!ddict)
879+
if (!dict.d) {
880+
enif_free_env(dict.env);
869881
return enif_make_tuple2(env, am_error,
870882
enif_make_atom(env, "invalid_decompress_dict"));
883+
}
871884

872-
dict = enif_alloc_resource(decompress_dict_type, sizeof(ZstdDict));
885+
dictp = enif_alloc_resource(decompress_dict_type, sizeof(ZstdDict));
873886

874-
dict->d = ddict;
875-
dict->env = enif_alloc_env();
876-
enif_make_binary(dict->env, &bin);
887+
*dictp = dict;
877888

878-
result = enif_make_resource(env, (void *)dict);
879-
enif_release_resource((void *)dict);
889+
result = enif_make_resource(env, (void *)dictp);
890+
enif_release_resource((void *)dictp);
880891
return result;
881892
}
882893
}

erts/emulator/zstd/zstd.mk

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,17 @@ endif
4545

4646
ifeq ($(TYPE),gcov)
4747
ZSTD_CFLAGS = -O0 -fprofile-arcs -ftest-coverage $(DEBUG_CFLAGS) $(DEFS) $(THR_DEFS)
48-
else # gcov
48+
else # !gcov
4949
ifeq ($(TYPE),debug)
5050
## DEBUGLEVEL=1 enables asserts, see common/debug.h for details
5151
ZSTD_CFLAGS = -DDEBUGLEVEL=1 $(DEBUG_CFLAGS) $(DEFS) $(THR_DEFS)
52-
else # debug
52+
else # !debug && !gcov
53+
5354
ZSTD_CFLAGS = $(subst -O2, -O3, $(CONFIGURE_CFLAGS) $(DEFS) $(THR_DEFS))
55+
ifeq ($(TYPE), asan)
56+
ZSTD_CFLAGS += -DZSTD_ADDRESS_SANITIZER
57+
endif # asan
58+
5459
endif # debug
5560
endif # gcov
5661

lib/stdlib/test/zstd_SUITE.erl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,9 @@ dict_api(Config) ->
437437
{ok, DCtx} = zstd:context(decompress, #{ dictionary => DDict }),
438438
{'EXIT', _} = catch zstd:set_parameter(DCtx, dictionary, CDict),
439439

440+
{'EXIT', _} = catch zstd:dict(compress, [1,2,3]),
441+
{'EXIT', _} = catch zstd:dict(decompress, [1,2,3]),
442+
440443
ok.
441444

442445

0 commit comments

Comments
 (0)