diff options
-rw-r--r-- | erts/emulator/beam/erl_db_hash.c | 45 | ||||
-rw-r--r-- | erts/emulator/sys/common/erl_sys_common_misc.c | 3 | ||||
-rw-r--r-- | erts/emulator/test/num_bif_SUITE.erl | 1 | ||||
-rw-r--r-- | lib/erl_interface/src/legacy/erl_marshal.c | 2 | ||||
-rw-r--r-- | lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c | 12 | ||||
-rw-r--r-- | lib/stdlib/src/ms_transform.erl | 6 | ||||
-rw-r--r-- | lib/stdlib/test/ets_SUITE.erl | 45 |
7 files changed, 87 insertions, 27 deletions
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index b988a19cf4..752d3ae3a8 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -150,6 +150,22 @@ static ERTS_INLINE Uint hash_to_ix(DbTableHash* tb, HashValue hval) } +static ERTS_INLINE FixedDeletion* alloc_fixdel(DbTableHash* tb) +{ + FixedDeletion* fixd = (FixedDeletion*) erts_db_alloc(ERTS_ALC_T_DB_FIX_DEL, + (DbTable *) tb, + sizeof(FixedDeletion)); + ERTS_ETS_MISC_MEM_ADD(sizeof(FixedDeletion)); + return fixd; +} + +static ERTS_INLINE void free_fixdel(DbTableHash* tb, FixedDeletion* fixd) +{ + erts_db_free(ERTS_ALC_T_DB_FIX_DEL, (DbTable*)tb, + fixd, sizeof(FixedDeletion)); + ERTS_ETS_MISC_MEM_ADD(-sizeof(FixedDeletion)); +} + static ERTS_INLINE int link_fixdel(DbTableHash* tb, FixedDeletion* fixd, erts_aint_t fixated_by_me) @@ -160,8 +176,7 @@ static ERTS_INLINE int link_fixdel(DbTableHash* tb, was_next = erts_atomic_read_acqb(&tb->fixdel); do { /* Lockless atomic insertion in linked list: */ if (NFIXED(tb) <= fixated_by_me) { - erts_db_free(ERTS_ALC_T_DB_FIX_DEL, (DbTable*)tb, - fixd, sizeof(FixedDeletion)); + free_fixdel(tb, fixd); return 0; /* raced by unfixer */ } exp_next = was_next; @@ -180,10 +195,7 @@ static ERTS_INLINE int link_fixdel(DbTableHash* tb, static int add_fixed_deletion(DbTableHash* tb, int ix, erts_aint_t fixated_by_me) { - FixedDeletion* fixd = (FixedDeletion*) erts_db_alloc(ERTS_ALC_T_DB_FIX_DEL, - (DbTable *) tb, - sizeof(FixedDeletion)); - ERTS_ETS_MISC_MEM_ADD(sizeof(FixedDeletion)); + FixedDeletion* fixd = alloc_fixdel(tb); fixd->slot = ix; fixd->all = 0; return link_fixdel(tb, fixd, fixated_by_me); @@ -637,11 +649,7 @@ restart: free_me = fixdel; fixdel = fixdel->next; - erts_db_free(ERTS_ALC_T_DB_FIX_DEL, - (DbTable *) tb, - (void *) free_me, - sizeof(FixedDeletion)); - ERTS_ETS_MISC_MEM_ADD(-sizeof(FixedDeletion)); + free_fixdel(tb, free_me); work++; } @@ -2338,11 +2346,10 @@ static SWord db_mark_all_deleted_hash(DbTable *tbl, SWord reds) } else { /* First call */ - fixdel = erts_db_alloc(ERTS_ALC_T_DB_FIX_DEL, - (DbTable *) tb, - sizeof(FixedDeletion)); - ERTS_ETS_MISC_MEM_ADD(sizeof(FixedDeletion)); - link_fixdel(tb, fixdel, 0); + int ok; + fixdel = alloc_fixdel(tb); + ok = link_fixdel(tb, fixdel, 0); + ASSERT(ok); (void)ok; i = 0; } @@ -2444,11 +2451,7 @@ static SWord db_free_table_continue_hash(DbTable *tbl, SWord reds) FixedDeletion *fx = fixdel; fixdel = fx->next; - erts_db_free(ERTS_ALC_T_DB_FIX_DEL, - (DbTable *) tb, - (void *) fx, - sizeof(FixedDeletion)); - ERTS_ETS_MISC_MEM_ADD(-sizeof(FixedDeletion)); + free_fixdel(tb, fx); if (--reds < 0) { erts_atomic_set_relb(&tb->fixdel, (erts_aint_t)fixdel); return reds; /* Not done */ diff --git a/erts/emulator/sys/common/erl_sys_common_misc.c b/erts/emulator/sys/common/erl_sys_common_misc.c index 2541ab5d31..d34e1a9ec0 100644 --- a/erts/emulator/sys/common/erl_sys_common_misc.c +++ b/erts/emulator/sys/common/erl_sys_common_misc.c @@ -176,6 +176,7 @@ sys_double_to_chars_fast(double f, char *buffer, int buffer_size, int decimals, double af; Uint64 int_part, frac_part; int neg; + int has_decimals = decimals != 0; char *p = buffer; if (decimals < 0) @@ -257,7 +258,7 @@ sys_double_to_chars_fast(double f, char *buffer, int buffer_size, int decimals, } /* Delete trailing zeroes */ - if (compact) + if (compact && has_decimals) p = find_first_trailing_zero(p); *p = '\0'; return p - buffer; diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl index 700734cd0b..f15217814a 100644 --- a/erts/emulator/test/num_bif_SUITE.erl +++ b/erts/emulator/test/num_bif_SUITE.erl @@ -161,6 +161,7 @@ t_float_to_string(Config) when is_list(Config) -> test_fts("1.000",1.0, [{decimals, 3}]), test_fts("1.0",1.0, [{decimals, 1}]), test_fts("1.0",1.0, [{decimals, 3}, compact]), + test_fts("10",10.0, [{decimals, 0}, compact]), test_fts("1.12",1.123, [{decimals, 2}]), test_fts("1.123",1.123, [{decimals, 3}]), test_fts("1.123",1.123, [{decimals, 3}, compact]), diff --git a/lib/erl_interface/src/legacy/erl_marshal.c b/lib/erl_interface/src/legacy/erl_marshal.c index c18067b9bc..932bba43bf 100644 --- a/lib/erl_interface/src/legacy/erl_marshal.c +++ b/lib/erl_interface/src/legacy/erl_marshal.c @@ -1803,7 +1803,7 @@ static int cmp_exe2(unsigned char **e1, unsigned char **e2) k = 0; while (1) { if (k++ == min){ - if (i == j) return 0; + if (i == j) return compare_top_ext(e1 , e2); if (i < j) return -1; return 1; } diff --git a/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c b/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c index 1e986feacf..04e8ca322e 100644 --- a/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c +++ b/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c @@ -88,6 +88,11 @@ TESTCASE(compare_list) { // erlang:term_to_binary([0, 1000]) unsigned char term4[] = {131,108,0,0,0,2,97,0,98,0,0,3,232,106}; + // erlang:term_to_binary([a|b]) + unsigned char term5a[] = {131,108,0,0,0,1,100,0,1,97,100,0,1,98}; + // erlang:term_to_binary([a|c]) + unsigned char term5b[] = {131,108,0,0,0,1,100,0,1,97,100,0,1,99}; + erl_init(NULL, 0); start_a = term1; start_b = term2; @@ -103,6 +108,13 @@ TESTCASE(compare_list) { test_compare_ext("lists1", start_a, end_a, start_b, end_b, -1); + start_a = term5a; + start_b = term5b; + end_a = term5a + sizeof(term5a); + end_b = term5b + sizeof(term5b); + + test_compare_ext("lists5", start_a, end_a, start_b, end_b, -1); + report(1); } diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl index d117481d2e..3845e35e9b 100644 --- a/lib/stdlib/src/ms_transform.erl +++ b/lib/stdlib/src/ms_transform.erl @@ -224,10 +224,12 @@ transform_from_shell(Dialect, Clauses, BoundEnvironment) -> %% Called when translating during compiling %% --spec parse_transform(Forms, Options) -> Forms2 when +-spec parse_transform(Forms, Options) -> Forms2 | Errors | Warnings when Forms :: [erl_parse:abstract_form() | erl_parse:form_info()], Forms2 :: [erl_parse:abstract_form() | erl_parse:form_info()], - Options :: term(). + Options :: term(), + Errors :: {error, ErrInfo :: [tuple()], WarnInfo :: []}, + Warnings :: {warning, Forms2, WarnInfo :: [tuple()]}. parse_transform(Forms, _Options) -> SaveFilename = setup_filename(), diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 7a48d1d55e..d8912e548c 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -66,7 +66,7 @@ meta_lookup_named_read/1, meta_lookup_named_write/1, meta_newdel_unnamed/1, meta_newdel_named/1]). -export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1, - smp_select_replace/1, otp_8166/1, otp_8732/1]). + smp_select_replace/1, otp_8166/1, otp_8732/1, delete_unfix_race/1]). -export([exit_large_table_owner/1, exit_many_large_table_owner/1, exit_many_tables_owner/1, @@ -142,7 +142,8 @@ all() -> ets_all, massive_ets_all, take, - whereis_table]. + whereis_table, + delete_unfix_race]. groups() -> [{new, [], @@ -5489,6 +5490,46 @@ smp_fixed_delete_do() -> %%verify_table_load(T), ets:delete(T). +%% ERL-720 +%% Provoke race between ets:delete and table unfix (by select_count) +%% that caused ets_misc memory counter to indicate false leak. +delete_unfix_race(Config) when is_list(Config) -> + EtsMem = etsmem(), + Table = ets:new(t,[set,public,{write_concurrency,true}]), + InsertOp = + fun() -> + receive stop -> + false + after 0 -> + ets:insert(Table, {rand:uniform(10)}), + true + end + end, + DeleteOp = + fun() -> + receive stop -> + false + after 0 -> + ets:delete(Table, rand:uniform(10)), + true + end + end, + SelectOp = + fun() -> + ets:select_count(Table, ets:fun2ms(fun(X) -> true end)) + end, + Main = self(), + Ins = spawn(fun()-> repeat_while(InsertOp), Main ! self() end), + Del = spawn(fun()-> repeat_while(DeleteOp), Main ! self() end), + spawn(fun()-> + repeat(SelectOp, 10000), + Del ! stop, + Ins ! stop + end), + [receive Pid -> ok end || Pid <- [Ins,Del]], + ets:delete(Table), + verify_etsmem(EtsMem). + num_of_buckets(T) -> element(1,ets:info(T,stats)). |