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

Peter Wang novalazy at gmail.com
Mon Aug 26 15:00:55 AEST 2019


On Mon, 26 Aug 2019 13:36:33 +1000 (AEST), "Zoltan Somogyi" <zoltan.somogyi at runbox.com> wrote:
> 
> The root of the problem is the parameter passing. In the inlined version,
> when we fill in the argument of R_4, we update R_4. In the non-inlined version,
> when we fill in the argument of HeadVar__1, for which main passes R_4,
> we update HeadVar__1, but do NOT update R_4 in main. Normally, this is
> not a problem: the filled in argument is normally on the heap, and the caller's
> pointer also points to it, so the caller also sees the field as being filled in.
> However, with the direct arg optimization, the field being filled in is NOT
> on the heap; it is in the pointer, next to the primary tag. It is the lack of
> any update to this field in the caller's R_4 that leaves the value of R_4 as a
> tagged NULL pointer, whose dereferencing leads to the crash.
> 
> I see two obvious approaches to fixing this. The quick-and-dirty fix would be
> to insist that the calls to unify predicates that have this problem (i.e. they are
> for a type with one or more direct arg functors, and some args of those direct-arg
> functors are initially free) be inlined even in the presence of --no-inlining.
> The other would be to modify the parameter passing conventions for such
> unifications, which would require not just nontrivial changes to the code
> that handles both the caller and the callee sides of such calls, but probably
> also significant changes in all the code generators. Currently all code generators
> assume that a call's outputs define *new* variables; making them handle situations
> in which a call has one or two outputs that update *existing* variables would also
> not be trivial.
> 
> On that basis, the first approach would seem more pragmatic, even though
> conceptually it is far from satisfying.
> 
> Opinions?

Unfortunately the problem is not limited to unify predicates, as in the
attached test case. We may need to disable the direct arg optimization
until the calling convention can be changed.

Peter
-------------- next part --------------
%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%

:- module bug72b.
:- 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).

main(!IO) :-
    R = unreviewed(_),
    fill(R),
    io.write_string(dump_maybe_reviewed(R), !IO),
    io.nl(!IO).

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

fill(unreviewed(P)) :-
    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