[erlang-bugs] Segmentation fault when running HIPE-compilled code
Mikael Pettersson
mikpe@REDACTED
Wed Jan 21 21:33:39 CET 2009
Sergey S writes:
> Hello.
>
> While I was playing with +native option, I run into a bug in HIPE
> which leads to segmentation fault.
>
> To reproduce the bug just compile the code below using HIPE and run
> crash:start/0. Your will see the following:
>
> Erlang (BEAM) emulator version 5.6.5 [source] [smp:2]
> [async-threads:0] [hipe] [kernel-poll:false]
>
> Eshell V5.6.5 (abort with ^G)
> 1> crash:start().
> # This message will be printed only once when compiled with +native
> Segmentation fault
>
> Here is the code (don't look for intention of this example, it has not
> got that):
>
> %---------------------------------------------------
> -module(crash).
> -export([start/0]).
>
> start() ->
> spawn(fun() -> init() end).
>
> init() ->
> repeat(10, fun() -> void end),
> receive after infinity -> ok end.
>
> repeat(0, _) ->
> ok;
> repeat(N, Fun) ->
> io:format("# This message will be printed only once when compiled
> with +native~n"),
> Fun(),
> repeat(N - 1, Fun). % <------ It never will be called if you use HIPE
> %---------------------------------------------------
>
> The same code compiled without +native flag works well to me. I'm
> using Erlang R12B5.
Thanks for reporting this bug. Here's the patch fixing this bug for R12B-5.
There was an omission in the liveness information for the native compiler's
RTL intermediate representation, which in this very specific case caused it
to lose the fact that the heap pointer register was live into the recursive
function calls, which in turn caused the 'fun() -> void end' function closure
object to be corrupted.
/Mikael Pettersson
The HiPE group
--- otp_src_R12B-5/lib/hipe/amd64/hipe_amd64_registers.erl.~1~ 2007-11-26 19:59:44.000000000 +0100
+++ otp_src_R12B-5/lib/hipe/amd64/hipe_amd64_registers.erl 2009-01-21 14:54:23.000000000 +0100
@@ -268,8 +268,7 @@ tailcall_clobbered() -> % tailcall crap
| fp_call_clobbered()].
live_at_return() ->
- [{?RAX,tagged}
- ,{?RSP,untagged}
+ [{?RSP,untagged}
,{?PROC_POINTER,untagged}
,{?FCALLS,untagged}
,{?HEAP_LIMIT,untagged}
--- otp_src_R12B-5/lib/hipe/rtl/hipe_rtl.erl.~1~ 2008-11-04 11:51:39.000000000 +0100
+++ otp_src_R12B-5/lib/hipe/rtl/hipe_rtl.erl 2009-01-21 14:54:36.000000000 +0100
@@ -882,15 +882,17 @@ args(I) ->
#alub{} -> [alub_src1(I), alub_src2(I)];
#branch{} -> [branch_src1(I), branch_src2(I)];
#call{} ->
+ Args = call_arglist(I) ++ hipe_rtl_arch:call_used(),
case call_is_known(I) of
- false -> [call_fun(I)|call_arglist(I)];
- true -> call_arglist(I)
+ false -> [call_fun(I) | Args];
+ true -> Args
end;
#comment{} -> [];
#enter{} ->
+ Args = enter_arglist(I) ++ hipe_rtl_arch:tailcall_used(),
case enter_is_known(I) of
- false -> hipe_rtl_arch:add_ra_reg([enter_fun(I)|enter_arglist(I)]);
- true -> hipe_rtl_arch:add_ra_reg(enter_arglist(I))
+ false -> [enter_fun(I) | Args];
+ true -> Args
end;
#fconv{} -> [fconv_src(I)];
#fixnumop{} -> [fixnumop_src(I)];
@@ -910,7 +912,7 @@ args(I) ->
#move{} -> [move_src(I)];
#multimove{} -> multimove_srclist(I);
#phi{} -> phi_args(I);
- #return{} -> hipe_rtl_arch:add_ra_reg(return_varlist(I));
+ #return{} -> return_varlist(I) ++ hipe_rtl_arch:return_used();
#store{} -> [store_base(I), store_offset(I), store_src(I)];
#switch{} -> [switch_src(I)]
end.
@@ -924,7 +926,7 @@ defines(Instr) ->
#alu{} -> [alu_dst(Instr)];
#alub{} -> [alub_dst(Instr)];
#branch{} -> [];
- #call{} -> call_dstlist(Instr);
+ #call{} -> call_dstlist(Instr) ++ hipe_rtl_arch:call_defined();
#comment{} -> [];
#enter{} -> [];
#fconv{} -> [fconv_dst(Instr)];
@@ -990,7 +992,7 @@ subst_uses(Subst, I) ->
end;
#comment{} ->
I;
- #enter{} -> %% XXX: Check why ra_reg is added in uses() but not updated here
+ #enter{} ->
case enter_is_known(I) of
false ->
I0 = enter_fun_update(I, subst1(Subst, enter_fun(I))),
--- otp_src_R12B-5/lib/hipe/rtl/hipe_rtl_arch.erl.~1~ 2008-06-10 14:47:41.000000000 +0200
+++ otp_src_R12B-5/lib/hipe/rtl/hipe_rtl_arch.erl 2009-01-21 14:56:26.000000000 +0100
@@ -22,9 +22,12 @@
heap_pointer/0,
heap_limit/0,
fcalls/0,
- add_ra_reg/1,
reg_name/1,
is_precoloured/1,
+ call_defined/0,
+ call_used/0,
+ tailcall_used/0,
+ return_used/0,
live_at_return/0,
endianess/0,
load_big_2/4,
@@ -164,22 +167,6 @@ fcalls_from_pcb() ->
Reg = hipe_rtl:mk_new_reg(),
{pcb_load(Reg, ?P_FCALLS), Reg, pcb_store(?P_FCALLS, Reg)}.
--spec(add_ra_reg/1 :: ([X]) -> [X]).
-
-add_ra_reg(Rest) ->
- case get(hipe_target_arch) of
- ultrasparc ->
- [hipe_rtl:mk_reg(hipe_sparc_registers:return_address()) | Rest];
- powerpc ->
- Rest; % do not include LR: it's not a normal register
- arm ->
- [hipe_rtl:mk_reg(hipe_arm_registers:lr()) | Rest];
- x86 ->
- Rest;
- amd64 ->
- Rest
- end.
-
reg_name(Reg) ->
case get(hipe_target_arch) of
ultrasparc ->
@@ -225,6 +212,18 @@ is_precolored_regnum(RegNum) ->
hipe_amd64_registers:is_precoloured(RegNum)
end.
+call_defined() ->
+ call_used().
+
+call_used() ->
+ live_at_return().
+
+tailcall_used() ->
+ call_used().
+
+return_used() ->
+ tailcall_used().
+
live_at_return() ->
case get(hipe_target_arch) of
ultrasparc ->
--- otp_src_R12B-5/lib/hipe/x86/hipe_x86_registers.erl.~1~ 2007-11-26 19:58:49.000000000 +0100
+++ otp_src_R12B-5/lib/hipe/x86/hipe_x86_registers.erl 2009-01-21 14:53:33.000000000 +0100
@@ -224,14 +224,8 @@ all_x87_pseudos() ->
{4,double}, {5,double}, {6,double}].
live_at_return() ->
- [{?EAX,tagged}
- %% XXX: should the following (fixed) regs be included or not?
- ,{?ESP,untagged}
+ [{?ESP,untagged}
,{?PROC_POINTER,untagged}
- %% Lets try not!
- %% If these are included they will interfere with other
- %% temps during regalloc, but regs FCALLS and HEAP_LIMIT
- %% don't even exist at regalloc.
,{?FCALLS,untagged}
,{?HEAP_LIMIT,untagged}
| ?LIST_HP_LIVE_AT_RETURN
More information about the erlang-bugs
mailing list