summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Gustavsson <bjorn@erlang.org>2023-04-28 06:31:36 +0200
committerBjörn Gustavsson <bjorn@erlang.org>2023-04-28 07:26:00 +0200
commit9a37583f4b319ecca3424f353aa6d4cd4e6b3fe2 (patch)
tree7b64dc3f2dd3406fd317e47db6ec684930ed4d98
parent432aae16404da21d75ae85889e413d9843333d5e (diff)
downloaderlang-9a37583f4b319ecca3424f353aa6d4cd4e6b3fe2.tar.gz
Eliminate internal error in beam_types:float_from_range/1
Closes #7178
-rw-r--r--lib/compiler/src/beam_types.erl19
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl37
2 files changed, 52 insertions, 4 deletions
diff --git a/lib/compiler/src/beam_types.erl b/lib/compiler/src/beam_types.erl
index 9c3da159c4..b668251f79 100644
--- a/lib/compiler/src/beam_types.erl
+++ b/lib/compiler/src/beam_types.erl
@@ -1182,11 +1182,24 @@ float_from_range(any) ->
float_from_range({'-inf','+inf'}) ->
#t_float{};
float_from_range({'-inf',Max}) ->
- #t_float{elements={'-inf',float(Max)}};
+ make_float_range('-inf', safe_float(Max));
float_from_range({Min,'+inf'}) ->
- #t_float{elements={float(Min),'+inf'}};
+ make_float_range(safe_float(Min), '+inf');
float_from_range({Min,Max}) ->
- #t_float{elements={float(Min),float(Max)}}.
+ make_float_range(safe_float(Min), safe_float(Max)).
+
+safe_float(N) when is_number(N) ->
+ try
+ float(N)
+ catch
+ error:_ when N < 0 -> '-inf';
+ error:_ when N > 0 -> '+inf'
+ end.
+
+make_float_range('-inf', '+inf') ->
+ #t_float{};
+make_float_range(Min, Max) ->
+ #t_float{elements={Min, Max}}.
integer_from_range(none) ->
none;
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index 6562b3228f..94aca11b01 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -22,7 +22,8 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
integers/1,numbers/1,coverage/1,booleans/1,setelement/1,
- cons/1,tuple/1,record_float/1,binary_float/1,float_compare/1,
+ cons/1,tuple/1,
+ record_float/1,binary_float/1,float_compare/1,float_overflow/1,
arity_checks/1,elixir_binaries/1,find_best/1,
test_size/1,cover_lists_functions/1,list_append/1,bad_binary_unit/1,
none_argument/1,success_type_oscillation/1,type_subtraction/1,
@@ -51,6 +52,7 @@ groups() ->
record_float,
binary_float,
float_compare,
+ float_overflow,
arity_checks,
elixir_binaries,
find_best,
@@ -771,6 +773,39 @@ do_float_compare(X) ->
_T -> Y > 0
end.
+float_overflow(_Config) ->
+ Res1 = id((1 bsl 1023) * two()),
+ Res1 = float_overflow_1(),
+
+ Res2 = id((-1 bsl 1023) * two()),
+ Res2 = float_overflow_2(),
+
+ ok.
+
+%% GH-7178: There would be an overflow when converting a number range
+%% to a float range.
+float_overflow_1() ->
+ round(
+ try
+ round(float(1 bsl 1023)) * two()
+ catch
+ _:_ ->
+ 0.0
+ end
+ ).
+
+float_overflow_2() ->
+ round(
+ try
+ round(float(-1 bsl 1023)) * two()
+ catch
+ _:_ ->
+ 0.0
+ end
+ ).
+
+two() -> 2.
+
arity_checks(_Config) ->
%% ERL-549: an unsafe optimization removed a test_arity instruction,
%% causing the following to return 'broken' instead of 'ok'.