diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 32affb6b6c69..2b5350abcb53 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -2026,11 +2026,25 @@ static BIF_RETTYPE binary_to_term_int(Process* p, Eterm bin, B2TContext *ctx) break; case B2TDecodeInit: - if (is_non_value(ctx->trap_bin) && ctx->b2ts.extsize > ctx->reds) { - /* dec_term will maybe trap, allocate space for magic bin - before result term to make it easy to trim with HRelease. - */ - ctx = b2t_export_context(p, ctx); + if (is_non_value(ctx->trap_bin)) { + if (ctx->b2ts.extsize > ctx->reds) { + /* dec_term will maybe trap, allocate space for magic bin + * before result term to make it easy to trim with HRelease. + */ + ctx = b2t_export_context(p, ctx); + } + else { + /* + * We will probably not trap. To ensure we don't, + * artificially increase our available reductions. + * This is a workaround for GH-11404. Calling HAlloc() + * in b2t_export_context() after factory has been created + * causes problems. + */ + const SWord consumed = initial_reds - ctx->reds; + ctx->reds = (INT_MAX / B2T_MEMCPY_FACTOR); + initial_reds = ctx->reds + consumed; + } } ctx->u.dc.ep = ctx->b2ts.extp; ctx->u.dc.res = (Eterm) (UWord) NULL; @@ -2114,6 +2128,7 @@ static BIF_RETTYPE binary_to_term_int(Process* p, Eterm bin, B2TContext *ctx) }while (ctx->reds > 0 || ctx->state >= B2TDone); if (is_non_value(ctx->trap_bin)) { + ASSERT(ctx->state < B2TDecode); ctx = b2t_export_context(p, ctx); ASSERT(is_value(ctx->trap_bin)); } diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl index 9d69741b8ba8..fda670870f39 100644 --- a/erts/emulator/test/binary_SUITE.erl +++ b/erts/emulator/test/binary_SUITE.erl @@ -68,6 +68,7 @@ bad_binary_to_term_2/1,safe_binary_to_term2/1, bad_binary_to_term/1, bad_terms/1, more_bad_terms/1, big_binary_to_term/1, + binary_to_term_trap_crash/1, otp_5484/1,otp_5933/1, ordering/1,unaligned_order/1,gc_test/1, bit_sized_binary_sizes/1, @@ -99,6 +100,7 @@ all() -> bad_binary_to_term_2, safe_binary_to_term2, bad_binary_to_term, bad_terms, t_hash, bad_size, big_binary_to_term, + binary_to_term_trap_crash, sub_bin_copy, bad_term_to_binary, t2b_system_limit, term_to_iovec, more_bad_terms, unsorted_map_in_map, @@ -1951,6 +1953,23 @@ trapping_loop2(Bif,Args,N) -> apply(erlang,Bif,Args), trapping_loop2(Bif, Args, N-1). +%% GH-11404: Bug caused SEGV or failed ASSERT. +binary_to_term_trap_crash(Config) -> + Term = {0,"1234567890123456",0,0,0,0,0,0, + [1 bsl 47], [], {127,0,0,1}, + 0,[],[],[],[],[],[],[],[],[],[],0,[],"123456789",[],[],0,0, + 0,[],0,[],[],[],[],[],1,[],[],[],[],[],[],0,0,"123",[],0,[], + 1,[],[],[],0,0,{0,0},0,[],0,0,0,[],[],0,[],0,0,[]}, + Bin = term_to_binary(Term), + CONTEXT_REDS = erlang:system_info(context_reductions), + [begin + erlang:yield(), + erlang:bump_reductions(I), + binary_to_term(Bin) + end + || I <- lists:seq(1,CONTEXT_REDS)], + ok. + large(Config) when is_list(Config) -> List = lists:flatten(lists:map(fun (_) -> [0,1,2,3,4,5,6,7,8]