summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSverker Eriksson <sverker@erlang.org>2021-05-05 21:40:18 +0200
committerSverker Eriksson <sverker@erlang.org>2021-05-06 12:09:11 +0200
commite036714975e7b2d199b17b48007aa3a5f0e9dc0a (patch)
treee507bdd996ccd1688ebb42426b8b06222922fd87
parent7fe7fa3dde556b5b92522f8279d465bb52baf1f6 (diff)
downloaderlang-e036714975e7b2d199b17b48007aa3a5f0e9dc0a.tar.gz
erts: Fix matchspec stack depth estimation bug
-rw-r--r--erts/emulator/beam/erl_db_util.c27
-rw-r--r--lib/stdlib/test/ets_SUITE.erl14
2 files changed, 38 insertions, 3 deletions
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index e2c029c244..49518012e4 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -3765,6 +3765,7 @@ dmc_array(DMCContext *context, DMCHeap *heap, DMC_STACK_TYPE(UWord) *text,
{
int all_constant = 1;
int textpos = DMC_STACK_NUM(*text);
+ int preventive_bumps = 0;
Uint i;
/*
@@ -3784,13 +3785,35 @@ dmc_array(DMCContext *context, DMCHeap *heap, DMC_STACK_TYPE(UWord) *text,
if (!c && all_constant) {
all_constant = 0;
if (i < nelems - 1) {
+ /* Revert preventive stack bumps as they will now be done again
+ * for real by do_emit_constant() */
+ context->stack_used -= preventive_bumps;
+
dmc_rearrange_constants(context, text, textpos,
p + i + 1, nelems - i - 1);
}
- } else if (c && !all_constant) {
- do_emit_constant(context, text, p[i]);
+ } else if (c) {
+ if (all_constant) {
+ /*
+ * OTP-17379:
+ * All constants so far, but do preventive stack bumps
+ * as the constants may later be converted to matchPushC
+ * by dmc_rearrange_constants above.
+ * Otherwise dmc_expr() may do incorrect stack depth estimation
+ * when it emits instructions for the first non-constant.
+ */
+ ++context->stack_used;
+ ++preventive_bumps;
+ }
+ else {
+ do_emit_constant(context, text, p[i]);
+ }
}
}
+ if (all_constant) {
+ /* Preventive stack bumps not needed */
+ context->stack_used -= preventive_bumps;
+ }
*constant = all_constant;
return retOk;
}
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 433b812fd5..2b8d6806ba 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -41,7 +41,9 @@
-export([t_delete_object/1, t_init_table/1, t_whitebox/1,
select_bound_chunk/1,
t_delete_all_objects/1, t_insert_list/1, t_test_ms/1,
- t_select_delete/1,t_select_replace/1,t_select_replace_next_bug/1,t_ets_dets/1]).
+ t_select_delete/1,t_select_replace/1,t_select_replace_next_bug/1,
+ t_select_pam_stack_overflow_bug/1,
+ t_ets_dets/1]).
-export([ordered/1, ordered_match/1, interface_equality/1,
fixtable_next/1, fixtable_insert/1, rename/1, rename_unnamed/1, evil_rename/1,
@@ -127,6 +129,7 @@ all() ->
t_init_table, t_whitebox, t_delete_all_objects,
t_insert_list, t_test_ms, t_select_delete, t_select_replace,
t_select_replace_next_bug,
+ t_select_pam_stack_overflow_bug,
t_ets_dets, memory, t_select_reverse, t_bucket_disappears,
t_named_select,
select_fail, t_insert_new, t_repair_continuation,
@@ -1488,6 +1491,15 @@ t_select_replace_next_bug(Config) when is_list(Config) ->
ets:delete(T).
+%% OTP-17379
+t_select_pam_stack_overflow_bug(Config) ->
+ T = ets:new(k, []),
+ ets:insert(T,[{x,17}]),
+ [{x,18}] = ets:select(T,[{{x,17}, [], [{{{element,1,'$_'},{const,18}}}]}]),
+ ets:delete(T),
+ ok.
+
+
%% Test that partly bound keys gives faster matches.
partly_bound(Config) when is_list(Config) ->
case os:type() of