aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/test/basic_SUITE_data/basic_bugs_beam.erl
blob: 964b0f423a0e428c30034139c6f64f7e4db9faf8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
%%% -*- erlang-indent-level: 2 -*-
%%%-------------------------------------------------------------------
%%% Author: Kostis Sagonas
%%%
%%% Contains code examples that exhibited bugs in the BEAM compiler.
%%%-------------------------------------------------------------------
-module(basic_bugs_beam).

-export([test/0]).

%% the following is needed for the test_weird_message
-export([loop/1]).
%% the following are needed for the test_catch_bug
-behaviour(gen_server).
-export([start_link/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2, code_change/3]).

test() ->
  ok = test_fp_basic_blocks(),
  ok = test_weird_message(),
  ok = test_catch_bug(),
  ok.

%%--------------------------------------------------------------------
%% Test which shows that BEAM's splitting of basic blocks should take
%% into account that arithmetic operations implemented as BIFs can
%% also cause exceptions and thus calls to BIFs should end basic blocks.
%%
%% Investigated and fixed in the beginning of April 2004.
%%--------------------------------------------------------------------

test_fp_basic_blocks() ->
  ok = t1(),
  ok = t2().

t1() ->
  X = (catch bad_arith1(2.0, 1.7)),
  case X of
    {'EXIT', {badarith, _}} ->
      ok;
    _ ->
      error
  end.

bad_arith1(X, Y) when is_float(X) ->
  X1 = X * 1.7e+308,
  X2 = X1 + 1.0,
  Y1 = Y * 2,
  {X2, Y1}.

%% Similarly, it is not kosher to have anything that can fail inside
%% the fp block since it will throw the exception before the fp
%% exception and we will get the same problems.

t2() ->
  case catch bad_arith2(2.0, []) of
    {'EXIT', {badarith, _}} ->
      ok;
    _ ->
      error
  end.

bad_arith2(X, Y) when is_float(X) ->
  X1 = X * 1.7e+308,
  Y1 = element(1, Y),
  {X1 + 1.0, Y1}.

%%--------------------------------------------------------------------
%% Sending 'test' to this process should return 'ok'.  But:
%%
%% 1> MOD:test().
%% Weird: received true
%% timeout
%%
%% Surprisingly, the message has been bound to the value of 'ena'
%% in the record! The problem was visible in the .S file.
%%--------------------------------------------------------------------

-record(state, {ena = true}).

test_weird_message() ->
  P = spawn_link(?MODULE, loop, [#state{}]),
  P ! {msg, self()},
  receive
    What -> What
  after 42 -> timeout
  end.

loop(S) ->
  receive
    _ when S#state.ena == false ->
        io:format("Weird: ena is false\n");
        % loop(S);
    {msg, Pid} ->
        Pid ! ok;
        % loop(S);
    Other ->
        io:format("Weird: received ~p\n", [Other])
        % loop(S)
  end.

%%--------------------------------------------------------------------
%% This was posted on the Erlang mailing list as a question:
%%
%%   Given the module below and the function call
%%     "catch_bug:start_link(foo)."
%%   from the Erlang shell, why does Erlang crash with "Catch not found"?
%%
%% The BEAM compiler was generating wrong code for this case;
%% this was fixed in R9C-0.  Native code generation was OK.
%%--------------------------------------------------------------------

test_catch_bug() ->
  ignore = start_link(foo),
  ok.

start_link(Param) ->
  gen_server:start_link(?MODULE, Param, []).

init(Param) ->
  process_flag(trap_exit, true),
  (catch begin
           dummy(Param),
           (catch exit(bar))
         end
  ),
  ignore.

dummy(_) -> ok.

%% gen_server callbacks below
handle_call(_Call, _From, State) -> {noreply, State}.
handle_cast(_Msg, State) -> {noreply, State}.
handle_info(_Msg, State) -> {noreply, State}.
terminate(_Reason, _State) -> ok.
code_change(_OldVsn, State, _Extra) -> {ok, State}.