aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/beam/erl_bits.c31
-rw-r--r--erts/emulator/test/bs_construct_SUITE.erl24
-rw-r--r--lib/compiler/src/beam_utils.erl61
-rw-r--r--lib/compiler/src/beam_validator.erl4
-rw-r--r--lib/compiler/test/beam_utils_SUITE.erl17
5 files changed, 101 insertions, 36 deletions
diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c
index 71c64997c1..b4e611f01b 100644
--- a/erts/emulator/beam/erl_bits.c
+++ b/erts/emulator/beam/erl_bits.c
@@ -1321,7 +1321,14 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term,
goto badarg;
}
}
+
+ if((ERTS_UINT_MAX - build_size_in_bits) < erts_bin_offset) {
+ c_p->freason = SYSTEM_LIMIT;
+ return THE_NON_VALUE;
+ }
+
used_size_in_bits = erts_bin_offset + build_size_in_bits;
+
sb->is_writable = 0; /* Make sure that no one else can write. */
pb->size = NBYTES(used_size_in_bits);
pb->flags |= PB_ACTIVE_WRITER;
@@ -1395,9 +1402,21 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term,
goto badarg;
}
}
- used_size_in_bits = erts_bin_offset + build_size_in_bits;
- used_size_in_bytes = NBYTES(used_size_in_bits);
- bin_size = 2*used_size_in_bytes;
+
+ if((ERTS_UINT_MAX - build_size_in_bits) < erts_bin_offset) {
+ c_p->freason = SYSTEM_LIMIT;
+ return THE_NON_VALUE;
+ }
+
+ used_size_in_bits = erts_bin_offset + build_size_in_bits;
+ used_size_in_bytes = NBYTES(used_size_in_bits);
+
+ if(used_size_in_bits < (ERTS_UINT_MAX / 2)) {
+ bin_size = 2 * used_size_in_bytes;
+ } else {
+ bin_size = NBYTES(ERTS_UINT_MAX);
+ }
+
bin_size = (bin_size < 256) ? 256 : bin_size;
/*
@@ -1487,6 +1506,12 @@ erts_bs_private_append(Process* p, Eterm bin, Eterm build_size_term, Uint unit)
* Calculate new size in bytes.
*/
erts_bin_offset = 8*sb->size + sb->bitsize;
+
+ if((ERTS_UINT_MAX - build_size_in_bits) < erts_bin_offset) {
+ p->freason = SYSTEM_LIMIT;
+ return THE_NON_VALUE;
+ }
+
pos_in_bits_after_build = erts_bin_offset + build_size_in_bits;
pb->size = (pos_in_bits_after_build+7) >> 3;
pb->flags |= PB_ACTIVE_WRITER;
diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl
index b79f4b995d..ce50bcdd86 100644
--- a/erts/emulator/test/bs_construct_SUITE.erl
+++ b/erts/emulator/test/bs_construct_SUITE.erl
@@ -905,14 +905,28 @@ bs_add_overflow(_Config) ->
_ when Memsize < (2 bsl 30) ->
{skip, "Less then 2 GB of memory"};
4 ->
- Large = <<0:((1 bsl 30)-1)>>,
- {'EXIT',{system_limit,_}} =
- (catch <<Large/bits, Large/bits, Large/bits, Large/bits,
- Large/bits, Large/bits, Large/bits, Large/bits,
- Large/bits>>),
+ {'EXIT', {system_limit, _}} = (catch bs_add_overflow_signed()),
+ {'EXIT', {system_limit, _}} = (catch bs_add_overflow_unsigned()),
ok
end.
+bs_add_overflow_signed() ->
+ %% Produce a large result of bs_add that, if cast to signed int, would
+ %% overflow into a negative number that fits a smallnum.
+ Large = <<0:((1 bsl 30)-1)>>,
+ <<Large/bits, Large/bits, Large/bits, Large/bits,
+ Large/bits, Large/bits, Large/bits, Large/bits,
+ Large/bits>>.
+
+bs_add_overflow_unsigned() ->
+ %% Produce a large result of bs_add that goes beyond the limit of an
+ %% unsigned word. This used to succeed but produced an incorrect result
+ %% where B =:= C!
+ A = <<0:((1 bsl 32)-8)>>,
+ B = <<2, 3>>,
+ C = <<A/binary,1,B/binary>>,
+ true = byte_size(B) < byte_size(C).
+
id(I) -> I.
memsize() ->
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index cc6e54ca16..e39fbdc3b7 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -789,39 +789,48 @@ live_opt([{recv_mark,_}=I|Is], Regs, D, Acc) ->
live_opt([], _, _, Acc) -> Acc.
-live_opt_block([{set,Ds,Ss,Op}=I0|Is], Regs0, D, Acc) ->
+live_opt_block([{set,Ds,Ss,Op0}|Is], Regs0, D, Acc) ->
Regs1 = x_live(Ss, x_dead(Ds, Regs0)),
- {I,Regs} = case Op of
- {alloc,Live0,Alloc} ->
- %% The life-time analysis used by the code generator
- %% is sometimes too conservative, so it may be
- %% possible to lower the number of live registers
- %% based on the exact liveness information.
- %% The main benefit is that more optimizations that
- %% depend on liveness information (such as the
- %% beam_bool and beam_dead passes) may be applied.
- Live = live_regs(Regs1),
- true = Live =< Live0, %Assertion.
- I1 = {set,Ds,Ss,{alloc,Live,Alloc}},
- {I1,live_call(Live)};
- _ ->
- {I0,Regs1}
- end,
+ {Op, Regs} = live_opt_block_op(Op0, Regs1, D),
+ I = {set, Ds, Ss, Op},
+
case Ds of
- [{x,X}] ->
- case (not is_live(X, Regs0)) andalso Op =:= move of
- true ->
- live_opt_block(Is, Regs0, D, Acc);
- false ->
- live_opt_block(Is, Regs, D, [I|Acc])
- end;
- _ ->
- live_opt_block(Is, Regs, D, [I|Acc])
+ [{x,X}] ->
+ case (not is_live(X, Regs0)) andalso Op =:= move of
+ true ->
+ live_opt_block(Is, Regs0, D, Acc);
+ false ->
+ live_opt_block(Is, Regs, D, [I|Acc])
+ end;
+ _ ->
+ live_opt_block(Is, Regs, D, [I|Acc])
end;
live_opt_block([{'%live',_,_}|Is], Regs, D, Acc) ->
live_opt_block(Is, Regs, D, Acc);
live_opt_block([], Regs, _, Acc) -> {Acc,Regs}.
+live_opt_block_op({alloc,Live0,AllocOp}, Regs0, D) ->
+ Regs =
+ case AllocOp of
+ {Kind, _N, Fail} when Kind =:= gc_bif; Kind =:= put_map ->
+ live_join_label(Fail, D, Regs0);
+ _ ->
+ Regs0
+ end,
+
+ %% The life-time analysis used by the code generator is sometimes too
+ %% conservative, so it may be possible to lower the number of live
+ %% registers based on the exact liveness information. The main benefit is
+ %% that more optimizations that depend on liveness information (such as the
+ %% beam_bool and beam_dead passes) may be applied.
+ Live = live_regs(Regs),
+ true = Live =< Live0,
+ {{alloc,Live,AllocOp}, live_call(Live)};
+live_opt_block_op({bif,_N,Fail} = Op, Regs, D) ->
+ {Op, live_join_label(Fail, D, Regs)};
+live_opt_block_op(Op, Regs, _D) ->
+ {Op, Regs}.
+
live_join_labels([{f,L}|T], D, Regs0) when L =/= 0 ->
Regs = gb_trees:get(L, D) bor Regs0,
live_join_labels(T, D, Regs);
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index f726625510..622e00bb2b 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -928,9 +928,9 @@ verify_call_match_context(Lbl, Ctx, #vst{ft=Ft}) ->
error({unsuitable_bs_start_match2,I})
end.
-allocate(Zero, Stk, Heap, Live, #vst{current=#st{numy=none}=St}=Vst0) ->
+allocate(Zero, Stk, Heap, Live, #vst{current=#st{numy=none}}=Vst0) ->
verify_live(Live, Vst0),
- Vst = prune_x_regs(Live, Vst0),
+ Vst = #vst{current=St} = prune_x_regs(Live, Vst0),
Ys = init_regs(Stk, case Zero of
true -> initialized;
false -> uninitialized
diff --git a/lib/compiler/test/beam_utils_SUITE.erl b/lib/compiler/test/beam_utils_SUITE.erl
index a3f1bb93fe..710cb050d4 100644
--- a/lib/compiler/test/beam_utils_SUITE.erl
+++ b/lib/compiler/test/beam_utils_SUITE.erl
@@ -260,6 +260,14 @@ otp_8949_b(A, B) ->
liveopt(_Config) ->
F = liveopt_fun(42, pebkac, user),
void = F(42, #alarmInfo{type=sctp,cause=pebkac,origin=user}),
+
+
+ A = {#alarmInfo{cause = {abc, def}}, ghi},
+ A = liveopt_guard_bif(A),
+
+ B = {#alarmInfo{cause = {abc}}, def},
+ {#alarmInfo{cause = {{abc}}}, def} = liveopt_guard_bif(B),
+
ok.
liveopt_fun(Peer, Cause, Origin) ->
@@ -271,6 +279,15 @@ liveopt_fun(Peer, Cause, Origin) ->
void
end.
+liveopt_guard_bif({#alarmInfo{cause=F}=R, X}=A) ->
+ %% ERIERL-48
+ if
+ is_tuple(F), tuple_size(F) == 2 -> A;
+ true ->
+ R2 = R#alarmInfo{cause={F}},
+ {R2,X}
+ end.
+
%% Thanks to QuickCheck.
coverage(_Config) ->
42+7 = merchant([[],7,false]),