Shell is terminated (and then restarts) mysteriously

Taylor Venable <>
Sat Jan 22 04:12:38 CET 2011


On Thu, Jan 20, 2011 at 23:02, Taylor Venable <> wrote:
> Hi there. I'm trying to learn Erlang by working on some simple
> programs, and as I'm working with the shell I'm noticing some (what to
> me at least is) odd behaviour. Every once in a while, after compiling
> some code, it will state that the shell process was terminated.

OK, after much playing I finally have a working minimal example of how
to reproduce this every single time, at least for my installation.

But first, with R14B I hacked lib/kernel/src/user_drv.erl on line 202
to print out R, which I assume is the reason why the EXIT message was
received. The value of R was the atom 'killed'. Don't know if that has
any significance. Then I upgraded to an unmodified R14B01, but there
was no difference in behaviour.

After a few hours of coding, and about 10 shell restarts, I happened
to notice a pattern. From that I worked my way to this example. Start
with this in test.erl:

-module(test).
-export([test/0]).

test() ->
    F = fun (_, []) -> ok;
            (F, [_|Xs]) ->
                F(F, Xs, xxx)
        end,
    F(F, [foo]).

Note: the recursive invocation of F is an intentional bug. Fire up erl:

$ erl
Erlang R14B01 (erts-5.8.2) [source] [64-bit] [smp:2:2] [rq:2]
[async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.2  (abort with ^G)
1> c(test).
{ok,test}
2> test:test().
** exception error: test:'-test/0-fun-0-'/2 called with 3 arguments
     in function  test:'-test/0-fun-0-'/2

OK, good, that's what I expect. Now change "F(F, Xs, xxx)" to "F(F,
Xs)" and then compile and run again:

3> c(test).
{ok,test}
4> test:test().
ok

Again, good. Now put the buggy recursive invocation of F back (i.e.
undo the fix we just made so we have the original file again). Compile
and run again:

5> c(test).
*** ERROR: Shell process terminated! ***
Eshell V5.8.2  (abort with ^G)
1>

There is the shell termination. Using this method, I get the
termination every single time.

And, if I use either result(1), or history(1), at the beginning, I do
not get the termination. This sounds to me similar to what Dan
Gudmundsson said about the shell (probably through the history or
result list) keeping some kind of reference into the module's code.

However, constructing a similar dynamic function call does NOT cause
the problem:

-module(test).
-export([test/0]).

test() ->
    F = fun (F) -> F(xxx) end,
    G = fun () -> ok end,
    F(G).

1> c(test).
{ok,test}
2> test:test().
** exception error: test:'-test/0-fun-1-'/0 called with one argument
     in function  test:'-test/0-fun-0-'/1

This is what we expect, now remove the xxx and recompile.

3> c(test).
{ok,test}
4> test:test().
ok

OK, let's put the xxx back and try it again.

5> c(test).
{ok,test}
6> test:test().
** exception error: test:'-test/0-fun-1-'/0 called with one argument
     in function  test:'-test/0-fun-0-'/1

To my admittedly ignorant eyes, it seems like exactly the same kind of
error that I've created, but unlike before, this example does NOT
break the shell. It seems to me that the only difference of much
consequence is whether the buggy call is recursive or not. The
recursive call breaks the shell, the non-recursive call does not. So I
guess now the question for me is, is this an expected result? And if
so, why?

Thanks for reading.

-- 
Taylor C. Venable
http://metasyntax.net/


More information about the erlang-questions mailing list