mthom / scryer-prolog

A modern Prolog implementation written mostly in Rust.
BSD 3-Clause "New" or "Revised" License
2.08k stars 125 forks source link

Likely dereferencing bug when comparing exception terms #1823

Closed pmoura closed 1 year ago

pmoura commented 1 year ago

Several tests in the Logtalk distribution check for expected exceptions using the subsumes_term/2 predicate. While all current tests for this predicate pass, we still see test failures like:

!     iso_get_byte_2_05: failure (in 0.0 seconds)
!       test goal throws the wrong error:
!         expected error(permission_error(input,stream,user_output),A)
!         but got  error(permission_error(input,stream,user_output),get_byte/2)
!       in file logtalk/tests/prolog/predicates/get_byte_2/tests.lgt between lines 58-61
!     lgt_get_byte_2_16: failure (in 0.0 seconds)
!       test goal throws the wrong error:
!         expected error(permission_error(input,stream,s),A)
!         but got  error(permission_error(input,stream,s),get_byte/2)
!       in file logtalk/tests/prolog/predicates/get_byte_2/tests.lgt between lines 109-113
!     iso_get_char_2_06: failure (in 0.0 seconds)
!       test goal throws the wrong error:
!         expected error(permission_error(input,stream,user_output),A)
!         but got  error(permission_error(input,stream,user_output),get_char/2)
!       in file logtalk/tests/prolog/predicates/get_char_2/tests.lgt between lines 66-69
!     lgt_get_char_2_19: failure (in 0.0 seconds)
!       test goal throws the wrong error:
!         expected error(permission_error(input,stream,s),A)
!         but got  error(permission_error(input,stream,s),get_char/2)
!       in file logtalk/tests/prolog/predicates/get_char_2/tests.lgt between lines 131-135
!     iso_get_code_2_06: failure (in 0.0 seconds)
!       test goal throws the wrong error:
!         expected error(permission_error(input,stream,user_output),A)
!         but got  error(permission_error(input,stream,user_output),get_code/2)
!       in file logtalk/tests/prolog/predicates/get_code_2/tests.lgt between lines 66-69

As you can see, in all cases above (and other not show here), the expected exception subsumes the actual exception. But the implicit subsumes_term/2 call fails. This may be due to a dereferencing bug in the subsumes_term/2 predicate implementation or elsewhere. As typical of dereferencing bugs, the same calls succeed in the top-level. Fixing this bug will fix a few dozen test failures in Prolog standards compliance test suite.

triska commented 1 year ago

Great find!

I have constructed a query that exhibits the issue, using ($)/1 from library(debug):

?- catch(get_byte(user_input, C), E, true),
   Err = error(permission_error(_,_,user_input),_),
   $subsumes_term(Err, E).
call:subsumes_term(error(permission_error(A,B,user_input),C),error(permission_error(input,text_stream,user_input),get_byte/2)).
   false.

Whereas the portrayed goal succeeds in isolation:

?- subsumes_term(error(permission_error(A,B,user_input),C),error(permission_error(input,text_stream,user_input),get_byte/2)).
   true.
triska commented 1 year ago

Unification also fails unexpectedly:

?- catch(get_byte(user_input, C), E, true),
   Err = error(permission_error(_,_,user_input),_),
   $Err = E.
call:(error(permission_error(A,B,user_input),C)=error(permission_error(input,text_stream,user_input),get_byte/2)).
   false.
triska commented 1 year ago

I think this may also make #1472 work as intended!

pmoura commented 1 year ago

Confirmed.

notoria commented 1 year ago

But:

?- catch(get_byte(user_input, C), error(permission_error(_,_,S),_), true),
   Si = user_input,
   Si = S.
   S = user_input, Si = user_input.
?- catch(get_byte(user_input, C), error(permission_error(_,_,S),_), true),
   Si = user_input,
   Si == S.
   false.
?-