foreign interface term reference validity

18 views
Skip to first unread message

Marijn Schraagen

unread,
Oct 1, 2015, 12:08:11 PM10/1/15
to SWI-Prolog
Hi,

Using the foreign interface I try to store a term reference in a loop if a condition is met. However, the reference turns out to become invalid if there are other Prolog calls in between.

Consider the following C/C++ code as a MWE:
#include <SWI-Prolog.h>
#include <SWI-cpp.h>
#include <SWI-Stream.h>

int main(int argc, char* argv[]){
   
PlEngine e(argc,argv);

   
PlCall("assertz(test(a))");
   
PlCall("assertz(test(b))");
   
    functor_t pt
= PL_new_functor(PL_new_atom("writeln"),1);
    term_t write
= PL_new_term_ref();
   
    predicate_t pred
= PL_pred(PL_new_functor(PL_new_atom("test"),1),NULL);
    term_t arg
= PL_new_term_ref();

    term_t ch_cpy
;
    qid_t qr
= PL_open_query(NULL,PL_Q_NORMAL,pred,arg);

   
bool first=true;
   
while(PL_next_solution(qr)){
       
if(first){
            ch_cpy
= PL_copy_term_ref(arg);
            first
=false;
       
}
       
PlCall("writeln('abcd')");
        PL_cons_functor
(write,pt,ch_cpy);
        PL_call
(write,NULL);
   
}
    PL_close_query
(qr);

   
return 0;
}
This code performs the query test(X), loops through the (two) solutions, and copies only the first solution to the term reference ch_cpy. In the loop, the queries writeln('abcd') and writeln(ch_cpy) are performed. The output is
abcd
a
abcd
1.25342913e-316
This shows that the term reference ch_cpy is invalid in the second iteration. This situation does not occur when the reference is copied both times:
while(PL_next_solution(qr)){
   ch_cpy
= PL_copy_term_ref(arg);
   
PlCall("writeln('abcd')");
   PL_cons_functor
(write,pt,ch_cpy);
   PL_call
(write,NULL);
}
Output:
abcd
a
abcd
b
or when the writeln('abcd') is not performed:
while(PL_next_solution(qr)){
   
if(first){
       ch_cpy
= PL_copy_term_ref(arg);
       first
=false;
   
}
   PL_cons_functor
(write,pt,ch_cpy);
   PL_call
(write,NULL);
}
Output:
a
a
So, the question is: how can a term reference be prevented from becoming invalid in this kind of situation?

Jan Wielemaker

unread,
Oct 1, 2015, 2:37:43 PM10/1/15
to Marijn Schraagen, SWI-Prolog
On 10/01/2015 06:08 PM, Marijn Schraagen wrote:
> Hi,
>
> Using the foreign interface I try to store a term reference in a loop if
> a condition is met. However, the reference turns out to become invalid
> if there are other Prolog calls in between.

PL_copy_term_ref() creates a second reference to the same term, but
does not change the scoping of the term. If you call PL_next_solution()
in a loop, you basically backtrack, resetting all terms to the state
before the first call to PL_next_solution(). If you want to remember
things, there is PL_record() and friends. But, these make copies of
the term and you must get rid of them explicitly do avoid memory leaks.

Hope this helps

--- Jan
> --
> You received this message because you are subscribed to the Google
> Groups "SWI-Prolog" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to swi-prolog+...@googlegroups.com
> <mailto:swi-prolog+...@googlegroups.com>.
> Visit this group at http://groups.google.com/group/swi-prolog.
> For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages