Leak with simple arithmetics
Closed this issue · 4 comments
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)
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
).
(That was it... I believe I took too much faith into git reset --hard
)
| ?- ackermann(4,1,R,1000000).
R = 65533
(396010 ms) yes