scryer-prolog icon indicating copy to clipboard operation
scryer-prolog copied to clipboard

between/3 leaking

Open UWN opened this issue 3 years ago • 4 comments

ulrich@p0:/opt/gupu/scryer-prolog$ ulimit -v
50000
ulrich@p0:/opt/gupu/scryer-prolog$ target/release/scryer-prolog -f
?- use_module(library(between)).
   true.
?- between(1,100000,I),I<0.
false.
?- between(1,150000,I),I<0.
Segmentation fault (core dumped)

UWN avatar Feb 05 '22 09:02 UWN

Failure or missing Prolog garbage collection? Relying solely on Rust smart pointers? Sloppy built-in implementation?

And why a Segmentation fault error? Also there is something wrong with its speed: https://github.com/mthom/scryer-prolog/issues/1291

Jean-Luc-Picard-2021 avatar Feb 23 '22 14:02 Jean-Luc-Picard-2021

Rust uses guard pages on its stack, is it a stack overflow? Also this may behave differently on rebis-dev branch.

infogulch avatar Feb 23 '22 16:02 infogulch

@infogulch : There should not be any overflow in this example at all. But in general, such overflows should be handled with the exception mechanism in Prolog #16

UWN avatar Mar 07 '22 08:03 UWN

Looking at it, it seems the disjunction is not compiled properly. In any case, here is a version without disjunction replacing the existing between_/3.

between_(Lower, Upper, X) :-
   Lower < Upper,
   !,
   between_or(Lower, Upper, X).
between_(Lower, Lower, Lower).

between_or(Lower, _, Lower).
between_or(Lower, Upper, X) :-
   Lower0 is Lower + 1,
   between_(Lower0, Upper, X).

So I looked at the WAM code:

?- [user].
between_or(Lower, Upper, X) :-
   Lower0 is Lower + 1,
   between_(Lower0, Upper, X).


?- wam_instructions(between_or/3,Ls),maplist(portray_clause,Ls).
allocate(3).
get_variable(y(2),2).
get_variable(y(1),3).
get_variable(x(3),1).
put_variable(y(3),1).
set_local_value(x(3)).
add(x(3),1,1).
call(is,2).
put_unsafe_value(3,1).
put_unsafe_value(2,2).
put_unsafe_value(1,3).
deallocate.
execute(between_,3).

At best there is one put_unsafe_value for the Lower0. But here are 3! Also, that instruction in itself should not cause any memory overflows since it should first look at the value that might be unsafe. Clearly, all three values are safe. The first two because they are nonvar, the last one might be put unsafe the first time, but then it is on the heap and from then on it is safe (even if that should not happen at all, since X comes from the head).

UWN avatar Jul 24 '22 18:07 UWN

... and it is also independent of the (is)/2 compilation.

?- [user].
between_or(Lower, Upper, X) :-
   succ(Lower, Lower0),
    between_(Lower0, Upper, X).

?- wam_instructions(between_or/3,Ls),maplist(portray_clause,Ls).
allocate(3).
get_variable(y(3),2).
get_variable(y(1),3).
put_variable(y(2),2).
call(succ,2).
put_unsafe_value(2,1).
put_unsafe_value(3,2).
put_unsafe_value(1,3).
deallocate.
execute(between_,3).
   Ls = [allocate(3),get_variable(y(3),2),get_variable(y(1),3),put_variable(y(2),2),call(succ,2),put_unsafe_value(2,1),put_unsafe_value(3,2),put_unsafe_value(1,3),deallocate,execute(between_,3)].

Here, the two put_unsafe_value related to argument 2 and 3 are superfluous.

UWN avatar Oct 11 '22 08:10 UWN

It seems that there is also another somewhat related error:

$ ulimit -v 250000; target/release/scryer-prolog -f
?- use_module(library(between)).
   true.
?- between(1,65000,I), I < 0.
   false.   % thus, it works with 65000
?- between(1,60000,I), I < 0.
   false.   % and of course also with less
?- repeat, between(1,60000,I), I < 0.
Segmentation fault (core dumped) 

How can this happen? This uses definitely less space, than the first query.

UWN avatar Mar 08 '23 11:03 UWN

Current reproduction:

ulrich@TU-Wien:/opt/gupu/scryer-prolog$ ulimit -v 70000
ulrich@TU-Wien:/opt/gupu/scryer-prolog$ target/release/scryer-prolog -f
?- use_module(library(between)).
   true.
?- between(1,2000000,I),I<0.
memory allocation of 2097152 bytes failed
Aborted (core dumped)

UWN avatar Apr 04 '23 07:04 UWN

I think the latest improvements to compilation successfully address this issue?

triska avatar Jul 04 '23 21:07 triska