on_signal(int, _, throw) gets "did not clear exception"

136 views
Skip to first unread message

Peter Ludemann

unread,
Jan 27, 2019, 4:33:19 PM1/27/19
to SWI-Prolog
The documentation for on_signal says "Two predicate names have special meaning. throw implies Prolog will map the signal onto a Prolog exception as described in section 4.11."

So, I put this into my code:
    on_signal(int, _, throw).

And when I interrupted the running program (it was in an infinite loop, I think), this was output:

Thread 1 (main): foreign predicate system:sort/2 did not clear exception: 
error(signal(int,2),context(sort/2,_19079312))

(I tried again, and got the same result, although for a different predicate. After trying this 4 times, I no longer got a response.)

All I want to do is cause the running program to stop with a traceback ... what's the magic incantation, please?

Peter Ludemann

unread,
Jan 27, 2019, 7:53:04 PM1/27/19
to SWI-Prolog
This happened with "SWI-Prolog version 8.1.0 for x86_64-linux"

And here's what happened when I ran the code again, repeatedly doing ctrl-C:

Thread 1 (main): foreign predicate system:$current_source_module/1 did not clear exception:
        error(signal(int,2),context(call_goal_expansion/5,_52514774))
Thread 1 (main): foreign predicate format/3 did not clear exception:
        error(signal(int,2),context(format/3,_21103714))
Thread 1 (main): foreign predicate system:$get_predicate_attribute/3 did not clear exception:
        error(signal(int,2),context($get_predicate_attribute/3,_28631344))
Thread 1 (main): foreign predicate system:$get_predicate_attribute/3 did not clear exception:
        error(signal(int,2),context($get_predicate_attribute/3,_23365882))
Thread 1 (main): foreign predicate system:$current_source_module/1 did not clear exception:
        error(signal(int,2),context(call_goal_expansion/5,_22041234))
Thread 1 (main): foreign predicate system:$current_source_module/1 did not clear exception:
        error(signal(int,2),context(call_goal_expansion/5,_22362858))
Thread 1 (main): foreign predicate system:$get_predicate_attribute/3 did not clear exception:
        error(signal(int,2),context(property_predicate/2,_22524926))
Thread 1 (main): foreign predicate system:current_prolog_flag/2 did not clear exception:
        error(signal(int,2),context(current_prolog_flag/2,_2099618))
Thread 1 (main): foreign predicate system:sort/2 did not clear exception:
        error(signal(int,2),context(sort/2,_6145768))

SWI-Prolog [thread 1 (main) at Sun Jan 27 16:47:32 2019]: received fatal signal 11 (segv)
C-stack trace labeled "crash":
  [0] PL_strtod() at ??:? [0x7f15644f134b]
  [1] bstore_print_backtrace_named() at ??:? [0x7f15644f150e]
  [2] bstore_print_backtrace_named() at ??:? [0x7f15644f1601]
  [3] PL_get_signum_ex() at ??:? [0x7f1564491bb3]
  [4] killpg() at ??:? [0x7f1564047f20]
  [5] PL_check_stacks() at ??:? [0x7f1564463a38]
  [6] PL_check_stacks() at ??:? [0x7f156446460e]
  [7] PL_check_stacks() at ??:? [0x7f1564464baf]
  [8] PL_next_solution() at ??:? [0x7f156443385f]
  [9] pl_skip_list3_va() at ??:? [0x7f1564477d50]
  [10] pl_skip_list3_va() at ??:? [0x7f156447857b]
  [11] PL_toplevel() at ??:? [0x7f156442cf0d]
  [12] /usr/bin/swipl(main+0x15) [0x55a85bca2805]
  [13] __libc_start_main() at ??:? [0x7f156402ab97]
  [14] /usr/bin/swipl(_start+0x2a) [0x55a85bca284a]
Running on_halt hooks with status 139
Killing 17388 with default signal handlers
[FATAL ERROR: at Sun Jan 27 16:47:32 2019
        Async exception handler for signal segv (11) raised an exception]
Command terminated by signal 11

Jan Wielemaker

unread,
Jan 28, 2019, 2:55:38 AM1/28/19
to Peter Ludemann, SWI-Prolog
On 27/01/2019 22:33, Peter Ludemann wrote:
> The documentation for on_signal says "Two predicate names have special
> meaning. throw implies Prolog will map the signal onto a Prolog
> exception as described in section 4.11."
>
> So, I put this into my code:
>     on_signal(int, _, throw).
>
> And when I interrupted the running program (it was in an infinite loop,
> I think), this was output:
>
> Thread 1 (main): foreign predicate system:sort/2 did not clear
> exception:
> error(signal(int,2),context(sort/2,_19079312))
>
>
> (I tried again, and got the same result, although for a different
> predicate. After trying this 4 times, I no longer got a response.)

Seems throw doesn't work anymore. Probably stopped working when
exceptions no longer used longjmp(), years ago. I'll have a look.
Binding to a predicate and then throwing an exception probably works
fine.

> All I want to do is cause the running program to stop with a traceback
> ... what's the magic incantation, please?

What is wrong with this ^C using the standard setup? Should give you
a prompt from where you can get a stack using 'g'. Use 'h' for the
other options.

Cheers --- Jan

Jan Wielemaker

unread,
Jan 28, 2019, 8:45:08 AM1/28/19
to Peter Ludemann, SWI-Prolog
On 28/01/2019 08:55, Jan Wielemaker wrote:
> Seems throw doesn't work anymore.  Probably stopped working when
> exceptions no longer used longjmp(), years ago.  I'll have a look.
> Binding to a predicate and then throwing an exception probably works
> fine.

This assumption was correct. Pushed a fix.

Cheers --- Jan

Peter Ludemann

unread,
Jan 28, 2019, 8:09:12 PM1/28/19
to SWI-Prolog
Thank-you for the fix.

However, something seems to have broken with at_end_of_stream (or with json_read_dict). I have 2 JSON terms, and expect at_end_of_stream after reading them. This works with the current PPA swipl but at_end_of_stream fails with the code at github.

As to why ^C and "g" doesn't suffice -- I'm running swipl in the *compilation* window under Emacs (there's a *lot* of debug output). Of course, I could switch to running it in a shell, but I'd have to run the commands by hand, whereas currently they're in a Makefile.

Peter Ludemann

unread,
Jan 28, 2019, 10:39:23 PM1/28/19
to SWI-Prolog
I changed my code to allow testing this fix ... and it didn't work. Whereas before I'd get the weird error message I reported, I now get nothing from ^C.
(The at_end_of_stream bug is still there; I commented out my assertion check)

Jan Wielemaker

unread,
Jan 29, 2019, 9:02:37 AM1/29/19
to Peter Ludemann, SWI-Prolog
On 29/01/2019 02:09, Peter Ludemann wrote:
> Thank-you for the fix.
>
> However, something seems to have broken with at_end_of_stream (or with
> json_read_dict). I have 2 JSON terms, and expect at_end_of_stream after
> reading them. This works with the current PPA swipl but at_end_of_stream
> fails with the code at github.

Only if the input has one character following the JSON document
(typically \n). If the input has no characters after the JSON document
at_end_of_stream/1 succeeds. Tested using:

:- use_module(library(http/json)).

t :-
open('t.json', read, In),
json_read_dict(In, Dict),
pp(Dict),
( at_end_of_stream(In)
-> format('At end of stream~n', [])
; format('Not at end of stream~n', [])
),
close(In).

101 ?- t.
_{a:1}At end of stream
true.

So, yes this breaks your code (and this won't go into 8.0 stable), but
it is because you code is fragile. Add another newline or whatever to
your input and it breaks the same way. You should skip all white space
and then check for end-of-file or, more easily, call the JSON reader
again and check it returns the end-of-file code you specified.

> As to why ^C and "g" doesn't suffice -- I'm running swipl in the
> *compilation* window under Emacs (there's a *lot* of debug output). Of
> course, I could switch to running it in a shell, but I'd have to run the
> commands by hand, whereas currently they're in a Makefile.
>
> On Monday, January 28, 2019 at 5:45:08 AM UTC-8, Jan Wielemaker wrote:
>
> On 28/01/2019 08:55, Jan Wielemaker wrote:
> > Seems throw doesn't work anymore.  Probably stopped working when
> > exceptions no longer used longjmp(), years ago.  I'll have a look.
> > Binding to a predicate and then throwing an exception probably works
> > fine.
>
> This assumption was correct.  Pushed a fix.
>
>         Cheers --- Jan
>
> --
> You received this message because you are subscribed to the Google
> Groups "SWI-Prolog" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to swi-prolog+...@googlegroups.com
> <mailto:swi-prolog+...@googlegroups.com>.
> Visit this group at https://groups.google.com/group/swi-prolog.
> For more options, visit https://groups.google.com/d/optout.

Jan Wielemaker

unread,
Jan 29, 2019, 9:09:14 AM1/29/19
to Peter Ludemann, SWI-Prolog
On 29/01/2019 04:39, Peter Ludemann wrote:
> I changed my code to allow testing this fix ... and it didn't work.
> Whereas before I'd get the weird error message I reported, I now get
> nothing from ^C.

Could it be your code is stuck into something else than Prolog? If
foreign code is involved this should call PL_handle_signals() at regular
intervals and check for EINTR for blocking system calls.

It is not impossible there are predicates in the system that lack doing
so.

On the terminal you can hit ^C twice. That will force an interactive
prompt unless you are blocked in something that blocks signals.

Note that on Linux there is also the script `swipl-bt` that uses GDB to
get a C or Prolog stack trace from a running Prolog process. Run with
--help to find the options.

Cheers --- Jan


> (The at_end_of_stream bug is still there; I commented out my assertion
> check)
>
> On Monday, January 28, 2019 at 5:09:12 PM UTC-8, Peter Ludemann wrote:
>
> Thank-you for the fix.
>
> However, something seems to have broken with at_end_of_stream (or
> with json_read_dict). I have 2 JSON terms, and expect
> at_end_of_stream after reading them. This works with the current PPA
> swipl but at_end_of_stream fails with the code at github.
>
> As to why ^C and "g" doesn't suffice -- I'm running swipl in the
> *compilation* window under Emacs (there's a *lot* of debug output).
> Of course, I could switch to running it in a shell, but I'd have to
> run the commands by hand, whereas currently they're in a Makefile.
>
> On Monday, January 28, 2019 at 5:45:08 AM UTC-8, Jan Wielemaker wrote:
>
> On 28/01/2019 08:55, Jan Wielemaker wrote:
> > Seems throw doesn't work anymore. Probably stopped working when
> > exceptions no longer used longjmp(), years ago. I'll have a
> look.
> > Binding to a predicate and then throwing an exception probably
> works
> > fine.
>
> This assumption was correct. Pushed a fix.
>
> Cheers --- Jan
>

Peter Ludemann

unread,
Jan 29, 2019, 1:36:44 PM1/29/19
to Jan Wielemaker, SWI-Prolog
Is there a predicate for skipping whitespace? I didn't see any option in library(http/json) for specifying the end-of-file code...

Peter Ludemann

unread,
Jan 29, 2019, 1:47:53 PM1/29/19
to Jan Wielemaker, SWI-Prolog
On Tue, 29 Jan 2019 at 06:09, Jan Wielemaker <j...@swi-prolog.org> wrote:
On 29/01/2019 04:39, Peter Ludemann wrote:
> I changed my code to allow testing this fix ... and it didn't work.
> Whereas before I'd get the weird error message I reported, I now get
> nothing from ^C.

Could it be your code is stuck into something else than Prolog? If
foreign code is involved this should call PL_handle_signals() at regular
intervals and check for EINTR for blocking system calls.

It is not impossible there are predicates in the system that lack doing
so.

Yes, the code seems to be stuck in the "rdet" term expansion when re-consulting my main module. 
Very puzzling, because there's no reason for it to reconsult. (When I removed "rdet", things seemed to work)

Jan Wielemaker

unread,
Jan 29, 2019, 1:50:23 PM1/29/19
to Peter Ludemann, SWI-Prolog
On 29/01/2019 19:36, Peter Ludemann wrote:
>
> Is there a predicate for skipping whitespace? I didn't see any option in
> library(http/json) for specifying the end-of-file code...

?- help(json_read).

...
end_of_file(+ErrorOrTerm)
If end of file is reached after skipping white space but
before any
input is processed take the following action (default error):
• If ErrorOrTerm == error, throw an unexpected end of file
syntax error
• Otherwise return ErrorOrTerm.
Returning an status term is required to process Concatenated
JSON.
Suggested values are @(eof) or end_of_file.
...

There is unfortunately some dependency issue with the docs, so you only
get the above after `rm packages/http/json.tex` and rebuilding.

There is no predicate for skipping white space. There is skip/1,2
and get_code/2 followed by code_type/2 to build what you need.

Cheers --- Jan

Peter Ludemann

unread,
Feb 1, 2019, 4:07:22 PM2/1/19
to SWI-Prolog
A short summary of what seems to have been the problem (and thanks to Jan for filling in some gaps in my knowledge).

According to Jan:
backtrace/1 calls clause_info/5 (?) which figures out the source structure of the clause by reading it (again), applying the user transformations and match this against to clause in the database.

In some situations, the goal expansion from rdet seems to get into an infinite loop when backtrace/1 reads in the source (presumably, it can't get to a fixed-point). It's not clear what triggers this; usually there's no problem. I noticed that rdet creates some predicates named __aux_det_NNNN where NNNN is the byte-offset in the file, to keep track of what goals have been expanded, but normally this works fine.

(Another way to avoid this problem, according to Jan, is to set the Prolog flag backtrace_show_lines to false.)
Reply all
Reply to author
Forward
0 new messages