diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index cfa51387b81c..3fee55cb1cee 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -3853,21 +3853,19 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, ASSERT(!use_iov); - /* Use [BIT_]BINARY_INTERNAL_REF, copying the actual BinRef - * and/or ErlSubBits whenever that is smaller than the data - * itself. */ - if (wire_size >= sizeof(BinRef)) { - if ((encoding == BINARY_EXT) && - (base == (byte*)refc_binary->orig_bytes) && - (size == refc_binary->orig_size * 8) && - (offset == 0)) { - encoding = BINARY_INTERNAL_REF; - copy_payload = 0; - } else if (wire_size >= (sizeof(ErlSubBits) + - sizeof(BinRef))) { - encoding = BITSTRING_INTERNAL_REF; - copy_payload = 0; - } + /* Always use [BIT_]BINARY_INTERNAL_REF: this may lead to a + * larger result than copying the payload, but ensures that + * the decoded object is exactly the same as the encoded + * one, simplifying the decompression logic in ETS. */ + if ((encoding == BINARY_EXT) && + (base == (byte*)refc_binary->orig_bytes) && + (size == refc_binary->orig_size * 8) && + (offset == 0)) { + encoding = BINARY_INTERNAL_REF; + copy_payload = 0; + } else { + encoding = BITSTRING_INTERNAL_REF; + copy_payload = 0; } } @@ -5606,19 +5604,15 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, ASSERT(vlen < 0); - /* Use [BIT_]BINARY_INTERNAL_REF, copying the actual BinRef - * and/or ErlSubBits whenever that is smaller than the data - * itself. */ - if (wire_size >= sizeof(BinRef)) { - if ((encoding == BINARY_EXT) && - (base == (byte*)refc_binary->orig_bytes) && - (size == refc_binary->orig_size * 8) && - (offset == 0)) { - encoding = BINARY_INTERNAL_REF; - } else if (wire_size >= (sizeof(ErlSubBits) + - sizeof(BinRef))) { - encoding = BITSTRING_INTERNAL_REF; - } + /* Always use [BIT_]BINARY_INTERNAL_REF: see matching comment + * in enc_term_int. */ + if ((encoding == BINARY_EXT) && + (base == (byte*)refc_binary->orig_bytes) && + (size == refc_binary->orig_size * 8) && + (offset == 0)) { + encoding = BINARY_INTERNAL_REF; + } else { + encoding = BITSTRING_INTERNAL_REF; } } diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 4613855e3ab6..db151e9d1499 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -7905,7 +7905,8 @@ maps_sum([L]) -> types(Config) when is_list(Config) -> init_externals(), repeat_for_opts(fun types_do/1, [repeat_for_opts_atom2list(set_types), - compressed]). + compressed, + [ordered_set, compressed]]). types_do(Opts) -> EtsMem = etsmem(), @@ -9312,9 +9313,12 @@ test_terms(Test_Func, Mode) -> Bin2 = list_to_binary(lists:seq(0, ?heap_binary_size+1)), Test_Func(Bin2), Bin3 = list_to_binary(lists:seq(0, 255)), + %% Test an undersized refc binary. GH-8682 + Bin4 = erts_debug:set_internal_state(binary, 61), garbage_collect(), Pib = process_info(self(),binary), Test_Func(Bin3), + Test_Func(Bin4), garbage_collect(), case Mode of strict -> Pib = process_info(self(),binary); @@ -9325,6 +9329,7 @@ test_terms(Test_Func, Mode) -> Test_Func(make_unaligned_sub_binary(Bin1)), Test_Func(make_unaligned_sub_binary(Bin2)), Test_Func(make_unaligned_sub_binary(Bin3)), + Test_Func(make_unaligned_sub_binary(Bin4)), Test_Func(make_sub_binary(lists:seq(42, 43))), Test_Func(make_sub_binary([42,43,44])),