Ticket #1764 (closed todo: wontfix)

Opened 4 years ago

Last modified 4 years ago

Infinite loop in exit handler

Reported by: nwellnhof Owned by: whiteknight
Priority: normal Milestone:
Component: core Version: trunk
Severity: high Keywords: exceptions
Cc: Language:
Patch status: Platform: all

Description

$ ./parrot -o tmp2.pbc t/pmc/exception-old_17.pir
$ ./parrot tmp2.pbc

Running the PIR file directly works.

Change History

  Changed 4 years ago by nwellnhof

  • version changed from 2.6.0 to trunk
  • component changed from none to core

  Changed 4 years ago by nwellnhof

There seem to be two unrelated problems. The following PIR loops infinitely, no matter if it's run directly or compiled:

.sub main :main
    push_eh handler
    exit 0
handler:
    .tailcall exit_handler()
.end

.sub exit_handler
    say "at exit"
    null $P0
    say $P0
.end

The following PIR doesn't work when compiled to PBC:

.sub main :main
    .local pmc a
    .lex 'a', a
    a = new ['Integer']
    a = 42
    f()
.end

.sub f :outer(main)
    .local pmc a
    a = find_lex 'a'
    say a
.end

Maybe related to #1171.

  Changed 4 years ago by pmichaud

On Sun, Sep 05, 2010 at 03:29:48PM -0000, Parrot wrote:
> Comment(by nwellnhof):
> 
>  There seem to be two unrelated problems. The following PIR loops
>  infinitely, no matter if it's run directly or compiled:
> 
>  {{{
>  .sub main :main
>      push_eh handler
>      exit 0
>  handler:
>      .tailcall exit_handler()
>  .end
> 
>  .sub exit_handler
>      say "at exit"
>      null $P0
>      say $P0
>  .end
>  }}}


The handler that is being set in 'main' is never being removed--
i.e, there's no 'pop_eh'.  Thus when exit_handler() is 
called, it's generating a "Null PMC in say" exception
which then invokes the handler (which generates a
"Null PMC in say exception, which invokes the handler...).

You probably need a "pop_eh" right after 'handler:'.

Pm

  Changed 4 years ago by plobsing

.lex and :outer don't seem to be working correctly. The infinite loop is caused by a null PMC access exception after find_lex has failed to find the lexical.

There are 2 primary causes for the lookup failure:

  • the main sub does not remember that it is an outer sub (SUB_FLAG_IS_OUTER is not preserved)
  • the freeze/thaw process creates a clone of the main sub as the exit_handler sub's outer_sub attribute. The clone does not have its ->ctx field updated (only the original gets the update)

On a higher level though, something smells wrong with using the outer sub's ->ctx attribute for much of anything, let alone using it for find_lex lookups.

follow-up: ↓ 6   Changed 4 years ago by pmichaud

On Mon, Sep 06, 2010 at 12:35:58AM -0000, Parrot wrote:
> Comment(by plobsing):
>  There are 2 primary causes for the lookup failure:
>   - the main sub does not remember that it is an outer sub
>  (SUB_FLAG_IS_OUTER is not preserved)
>   - the freeze/thaw process creates a clone of the main sub as the
>  exit_handler sub's outer_sub attribute. The clone does not have its ->ctx
>  field updated (only the original gets the update)
> 
>  On a higher level though, something smells wrong with using the outer
>  sub's ->ctx attribute for much of anything, let alone using it for
>  find_lex lookups.

The ->ctx attribute on subs is a long-standing feature known as 
"autoclose".  In fact, the problem is resolved if 'main' correctly
does a capture_lex on its inner sub (as all lexical outers are
supposed to do to their inner subs):

  pmichaud@plum:~/parrot/trunk$ cat x.pir
  .sub main :main
      .const 'Sub' $P0 = 'f'
      capture_lex $P0
      .local pmc a
      .lex 'a', a
      a = new ['Integer']
      a = 42
      f()
  .end
  
  .sub f :outer(main)
      .local pmc a
      a = find_lex 'a'
      say a
  .end
  
  pmichaud@plum:~/parrot/trunk$ ./parrot -o x.pbc x.pir
  pmichaud@plum:~/parrot/trunk$ ./parrot x.pbc
  42
  pmichaud@plum:~/parrot/trunk$ 

With the capture_lex in place, I'd lean towards closing
this as a non-bug.

Pm

in reply to: ↑ 5   Changed 4 years ago by plobsing

  • status changed from new to closed
  • resolution set to fixed

Replying to pmichaud:

{{{ On Mon, Sep 06, 2010 at 12:35:58AM -0000, Parrot wrote:

Comment(by plobsing): There are 2 primary causes for the lookup failure: - the main sub does not remember that it is an outer sub (SUB_FLAG_IS_OUTER is not preserved) - the freeze/thaw process creates a clone of the main sub as the exit_handler sub's outer_sub attribute. The clone does not have its ->ctx field updated (only the original gets the update) On a higher level though, something smells wrong with using the outer sub's ->ctx attribute for much of anything, let alone using it for find_lex lookups.

The ->ctx attribute on subs is a long-standing feature known as "autoclose". In fact, the problem is resolved if 'main' correctly does a capture_lex on its inner sub (as all lexical outers are supposed to do to their inner subs):

I'm not sure exactly what autoclose is (there are only 5 mentions of it in the repo), but I suspect that may be what is broken when thawing from PBC.

pmichaud@plum:~/parrot/trunk$ cat x.pir .sub main :main .const 'Sub' $P0 = 'f' capture_lex $P0 .local pmc a .lex 'a', a a = new Integer? a = 42 f() .end .sub f :outer(main) .local pmc a a = find_lex 'a' say a .end pmichaud@plum:~/parrot/trunk$ ./parrot -o x.pbc x.pir pmichaud@plum:~/parrot/trunk$ ./parrot x.pbc 42 pmichaud@plum:~/parrot/trunk$ With the capture_lex in place, I'd lean towards closing this as a non-bug.

After inserting the capture_lex, this no longer hangs. The ticket can be closed.

Pm }}}

  Changed 4 years ago by nwellnhof

  • status changed from closed to reopened
  • resolution fixed deleted

There's still an infinite loop if any kind of exception is thrown in the exit handler.

  Changed 4 years ago by NotFound

This has been discussed several times. An exception handler can catch its own exceptions. If while doing that it throws again, it recurses indefinitely. This is by design, and can't be fixed without changing the design.

  Changed 4 years ago by nwellnhof

  • type changed from bug to RFC

I think it's a bad idea to allow an inifinite loop in this case. Unhandled exceptions in exit or exception handlers should be ignored.

I'm changing the type of the ticket from bug to RFC.

  Changed 4 years ago by whiteknight

  • keywords exceptions added
  • platform set to all
  • status changed from reopened to new
  • severity changed from medium to high
  • owner set to whiteknight

  Changed 4 years ago by whiteknight

  • type changed from RFC to todo

  Changed 4 years ago by whiteknight

  • status changed from new to assigned

We have changed the way fatal exceptions are handled with the embed_api merge. Can somebody verify that this issue still happens in modern parrot?

  Changed 4 years ago by whiteknight

  • status changed from assigned to closed
  • resolution set to wontfix

I'm going to close this ticket as "WONTFIX". Here's why: First, there's no real way that the program knows that this is an "exit handler" as opposed to any other type of handler. Second, Parrot does legitimately allow the use of exceptions for control flow, including use in loops. The correct way to write an exception handler is a label, likely followed immediately by a 'pop_eh'. If you include a 'pop_eh' in this example, it doesn't loop forever and terminates as we expect.

This is the design of the subsystem. If we want to change the design that's one thing, but right now this isn't a problem.

  Changed 4 years ago by coke

  • status changed from closed to reopened
  • resolution wontfix deleted
FWIW, the original example listed here does NOT have a pop_eh, and it
now works as described either run directly or compiled to PBC and then
run.

  Changed 4 years ago by coke

  • status changed from reopened to closed
  • resolution set to wontfix

apparently responding via email auto-reopens the ticket.

Note: See TracTickets for help on using tickets.