[m-dev.] [Mercury-Language/mercury] Segfault in only Mercury after solutions in a particular code path (#72)

Peter Wang novalazy at gmail.com
Tue Nov 17 11:23:52 AEDT 2020

On Mon, 16 Nov 2020 17:40:42 +1100 "Zoltan Somogyi" <zoltan.somogyi at runbox.com> wrote:
> The idea is that this pass would transform the gh72b.m test case,
> which crashes, to the attached code, which works.
> The only fly in the ointment I can see is that not all references to
> a cloned procedure are calls to that procedure. This approach
> would not handle the case where the program constructs a closure
> using a cloned procedure. In most cases, the closure is then passed
> to code that knows its declared signature, and whose implementation
> works only with that signature, so this transformation, which changes
> the signature, wouldn't work. But at least, the scan of the procedure
> bodies can easily be made to find such situations, so we can at least
> generate a "sorry, not implemented" error message from the compiler,
> instead of a runtime crash.

Can you give an example where this would occur? Is it possible to
construct a closure where one of the captured arguments is not ground?

I think the idea would work.

What about a term that contains a direct arg functor with a free
argument, e.g.

    R0 = unreviewed(_),	% direct arg functor
    Foo = foo(R0, 123),
    fill(R0, R),

Could it be possible to write something in the ... such that the
construction of Foo cannot be delayed after the call to fill,
so that the reference to R0 would be replaced by R?
I wasn't able to get the attached example to compile but
perhaps it is possible somehow.

-------------- next part --------------
% vim: ft=mercury ts=4 sw=4 et
% This is an instance of the same kind of bug that gh72a.m tests for,
% but with a user-written predicate instead of an automatically constructed
% type-specific unification predicate.

:- module gh72d.
:- interface.

:- import_module io.

:- pred main(io::di, io::uo) is det.

:- implementation.

:- import_module list.
:- import_module string.

:- type maybe_reviewed
    --->    reviewed(package)
    ;       unreviewed(package).

:- type package
    --->    package(string, string).

:- type foo
    --->    foo(maybe_reviewed, int).

:- inst foo_inst for foo/0
    --->    foo(maybe_reviewed_inst, ground).

:- inst maybe_reviewed_inst for maybe_reviewed/0
    --->    unreviewed(free).

main(!IO) :-
    R0 = unreviewed(_),
    Foo = foo(R0, 123),
    use_foo(Foo, !IO),
    fill(R0, R),
    io.write_string(dump_maybe_reviewed(R), !IO),

:- pred use_foo(foo, io, io).
:- mode use_foo(foo_inst >> foo_inst, di, uo) is det.
:- pragma no_inline(use_foo/3).

use_foo(_, !IO).

:- pred fill(maybe_reviewed, maybe_reviewed).
:- mode fill(bound(unreviewed(free)) >> ground, out) is det.
:- pragma no_inline(fill/2).

fill(H1 @ unreviewed(P), H1) :-
    P = package("a", "b").

:- func dump_maybe_reviewed(maybe_reviewed) = string.
:- pragma no_inline(dump_maybe_reviewed/1).

dump_maybe_reviewed(reviewed(P)) = "reviewed " ++ dump_package(P).
dump_maybe_reviewed(unreviewed(P)) = "unreviewed " ++ dump_package(P).

:- func dump_package(package) = string.
:- pragma no_inline(dump_package/1).

dump_package(package(A, B)) = A ++ B.

More information about the developers mailing list