didoudiaz/gprolog

Leak with simple arithmetics

Closed this issue · 4 comments

UWN commented

To my understanding, the following program should not allocate any term on the global stack at all. But somehow this global stack overflows. I try to simulate an overflow check with a depth variable that counts down for non-tail-recursions only.

ackermann(_, _, _,D) :-
   D == 0,
   !,
   throw(error(resource_error(stackdepth),ackermann/3)).
ackermann(M, _, _,_) :-
   M < 0,
   !,
   throw(error(domain_error(not_less_than_zero,M),ackermann/3)).
ackermann(M0,N0,A0,D1) :-
   M0 > 0,
   M1 is M0 - 1,
   N0 > 0,
   !,
   D2 is D1-1,
   N1 is N0 - 1,
   ackermann(M0,N1,A1,D2),
   ackermann(M1,A1,A0,D1).
ackermann(M0,0,A,D) :-
   M0 > 0,
   !,
   M1 is M0 - 1,
   ackermann(M1,1,A,D).
ackermann(0,N,A,_) :-
   A is N + 1.

| ?- ackermann(4,1,R,795).
uncaught exception: error(resource_error(stackdepth),ackermann/3)  % as intended
| ?- ackermann(4,1,R,798).

Fatal Error: global stack overflow (size: 100000 Kb, reached: 99997 Kb, environment variable used: GLOBALSZ)

I suppose you consulted the file under the top-level. In that case the code is compiled for consult (for byte-code). In this mode, some optimizations are not done (mainly to allow the user to trace the code under debugger). For instance, arithmetic is not inlined, thus something like D2 is D1-1 is really compiled as is(D2, D1-1) (obviously but the operator notation can hide a bit the real arguments passing), i.e. for the second argument, the WAM code looks like:

    put_variable(y(D2),0)
    put_structure((-)/2,1)
    unify_local_value(y(D1))
    unify_integer(1)
    call((is)/2)

The second argument of is/2 is really a compound term (thus stored on the heap).

On the other hand, compiling to native-code and running:

$ gplc acker.pl
$ ./acker
GNU Prolog 1.6.0 (64 bits)
Compiled Jul  9 2023, 23:50:29 with gcc
Copyright (C) 1999-2023 Daniel Diaz

| ?- ackermann(4,1,R,1000).
uncaught exception: error(resource_error(stackdepth),ackermann/3)
| ?- ackermann(4,1,R,2000).
uncaught exception: error(resource_error(stackdepth),ackermann/3)
| ?- ackermann(4,1,R,10000).
uncaught exception: error(resource_error(stackdepth),ackermann/3)
UWN commented

Thank you,

$ /opt/gupu/gprolog-1.6.0/bin/gplc acker.pl 
/usr/bin/ld: /tmp/gplcWa3nxh.o: relocation R_X86_64_32S against `.text' can not be used when making a PIE object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
compilation failed

Strange, I don't have this error on my x86_64/ubuntu box.
Can you report the output of

cd /path/to/gprolog/src
. SETVARS
uname -a
make distclean
./configure
make
make check

NB: . SETVARS (under bash) initializes PATH so that you can use the locally compiled gprolog (no need to make install).

UWN commented

(That was it... I believe I took too much faith into git reset --hard)

| ?- ackermann(4,1,R,1000000).

R = 65533

(396010 ms) yes