# \[FATAL ERROR: Too many stacked strings\] when using the C++ version 1 interface

**URL:** <https://swi-prolog.discourse.group/t/fatal-error-too-many-stacked-strings-when-using-the-c-version-1-interface/6775>\
**Category:** General\
**Created:** [August 18, 2023, 3:13pm UTC](https://swi-prolog.discourse.group/t/fatal-error-too-many-stacked-strings-when-using-the-c-version-1-interface/6775 "2023-08-18T15:13:22Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![hharryyf](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/hharryyf/32/5461_2.png) [@hharryyf](https://swi-prolog.discourse.group/u/hharryyf)\
**Post date:** [August 18, 2023, 3:13pm UTC](https://swi-prolog.discourse.group/t/fatal-error-too-many-stacked-strings-when-using-the-c-version-1-interface/6775/1 "2023-08-18T15:13:22Z")

</div>

Hi, I’m using the prolog C++ interface for some a recursive C++ program. Basically, the program keeps calling “assertz”, “retractall”, and do some query. But after around 20 seconds, the program would throw the [FATAL ERROR: Too many stacked strings] error. I read some posts and tried those methods such as pl\_strings\_mark() + pl\_strings\_release(). But they cannot fix my problem. When I used the python interface it didn’t have such an issue. I’m wondering, how can I fix the problem in the C++ version 1 interface?

Thanks.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [August 18, 2023, 3:43pm UTC](https://swi-prolog.discourse.group/t/fatal-error-too-many-stacked-strings-when-using-the-c-version-1-interface/6775/2 "2023-08-18T15:43:22Z")

</div>

Without seeing your code, it’s difficult to know what’s going wrong.

C++ version 1 is deprecated and is unlikely to have any fixes. I strong suggest converting to version 2. Amongst other things, it has better error checking (both at compile and run time), which might help you find your problem.

Instead of using the C macros `PL_STRINGS_MARK()` etc., I suggest using the `PlStringBuffers` class. This makes sure that the “mark” and “release” calls are properly nested, using RAII.

In general, it’s best to avoid the `char*` APIs and instead use `std::string` – this can avoid lifetime issues: a `char*` might point to garbage whereas a `std::string` contains a copy of the value. Also, use of the `std::string` interfaces usually avoids the need for `PlStringBuffers` (or `PL_STRINGS_MARK()`).

[There are a few places in the C++ version 2 API where `char*` is used instead of `std::string` … I’m in the process of fixing those. But you’re unlikely to encounter them if you use the non-deprecated methods.]

---

<div class="post-metadata">

**Author:** ![hharryyf](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/hharryyf/32/5461_2.png) [@hharryyf](https://swi-prolog.discourse.group/u/hharryyf)\
**Post date:** [August 19, 2023, 3:09am UTC](https://swi-prolog.discourse.group/t/fatal-error-too-many-stacked-strings-when-using-the-c-version-1-interface/6775/3 "2023-08-19T03:09:34Z")

</div>

Thanks for your reply. After I switch to version 2, the error did not appear as the original. However, it changed to PlExceptionFail after the program ran for like 50 seconds. In these 50 seconds, the program did 4e6 many assertz/1 and 4e6 many retractall/1, however, the total number of facts never exceeded 20 (i.e. assertz/1 call minus retractall/1 call at any time never exceed 20). I’m wondering, is there a limit on the total call to assertz/1 even if I remove the fact with retractall/1 later? If not, how should I fix this issue, if my program needs massive call to assertz/1 and retractall/1?

```prolog
Thread 1 (main): foreign predicate system:retractall/1 did not clear exception:
        error(resource_error(stack),stack_overflow{choicepoints:1,depth:1,environments:2,globalused:760499,localused:233612,stack:[frame(1,system:call(retractall/1),[]),frame(0,system: $c_call_prolog,[])],stack_limit:1048576,trailused:53330})

```

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [August 19, 2023, 3:54am UTC](https://swi-prolog.discourse.group/t/fatal-error-too-many-stacked-strings-when-using-the-c-version-1-interface/6775/4 "2023-08-19T03:54:32Z")

</div>

I don’t know what’s causing your stack overflow or how to isolate that; and without seeing your full code, it’s not clear to me how to figure that out.

The “did not clear exception” message indicates that a Prolog error happened and you didn’t handle it. If any of your `PlCall()`s are outside a try-catch, or if any of them don’t check the return code, then that could be the cause (I should probably put `[[nodiscard]]` on `PlCall()`).

I’ll have to think about the best way of doing error handling in your situation – I’ve been concentrating on error handling for C++ code that’s called by Prolog, not the C++ calling Prolog. But at minimum, you should check the return code from `PlCall()`.

`PlCall()` doesn’t have as nice of an interface because there are two possible sets of return codes (see the documentation on `PL_next_solution()` if you want to know more), although you’re using the simple one, namely success/failure (1 or 0). It’s a bit more complicated because 0 can also mean an error. If you look at the code for `PlQuery::next_solution()`, you’ll see that it uses `PlEx_fail()`, which checks the Prolog return code and then throw a C++ error if there was a Prolog error.  
[I’ve been thinking about how to improve `PlCall()`, but haven’t done anything with it so far.]

---

<div class="post-metadata">

**Author:** ![hharryyf](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/hharryyf/32/5461_2.png) [@hharryyf](https://swi-prolog.discourse.group/u/hharryyf)\
**Post date:** [August 19, 2023, 5:13am UTC](https://swi-prolog.discourse.group/t/fatal-error-too-many-stacked-strings-when-using-the-c-version-1-interface/6775/5 "2023-08-19T05:13:09Z")

</div>

I tried to recreate the error with a simple example. Suppose the prolog program is:

```prolog
hello(X) :- fact(X).

```

The C++ program would face an error after i ~ 4e6.

```prolog
#include <bits/stdc++.h>
#include <SWI-Prolog.h>
#include <SWI-cpp2.h>
#include <SWI-cpp2.cpp>

std::vector<std::string> run_query() {
    PlTermv av(1);
    PlQuery q("hello", av);
    std::vector<std::string> ret;
    try {
        while( q.next_solution() ) {
            
            auto res = av[0].as_string();
            ret.push_back(res);
        }
    } catch ( PlExceptionBase &ex ) { 
        std::cerr << ex.what() << std::endl;
    }

    return ret;
}

// g++ -std=c++17 trial.cpp -o trial -L/usr/lib/swi-prolog/lib/x86_64-linux -lswipl

int main(int argc, char **argv)
{
    Plx_initialise(argc, argv);
    PlCall("consult('example.pl')");
    PlCall("assertz(fact(1))");
    for (int i = 0 ; i < 100000000; ++i) {
        if (i % 10000 == 0) {
            std::cout << i << std::endl;
        }
        PlCall("assertz(fact(2))");
        PlCall("assertz(fact(3))");
        run_query();
        PlCall("retractall(fact(2))");
        PlCall("retractall(fact(3))");
    }
    
    PL_halt(0);
    return 0;
}

```

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [August 19, 2023, 7:02am UTC](https://swi-prolog.discourse.group/t/fatal-error-too-many-stacked-strings-when-using-the-c-version-1-interface/6775/6 "2023-08-19T07:02:45Z")

</div>

I have a feeling that the problem is that there’s no “close” for any query that doesn’t try all of the solutions (because the close would throw away bindings, even though you don’t have any), so stack frames accumulate. I need to go back through some notes I made about how this should be handled. Unfortunately, there are a lot of variations of how queries are done, and they don’t map nicely into C++ … I also need to look at how `PL_Q_CATCH_EXCEPTION` works with this.

Looking at your code, your `PlQuery` gets all its solutions, and that should call `PlQuery::close_destroy()` or `PlQuery::cut()` when there are no more solutions; I suspect that the `PlCall()`s are the problem because they don’t try all solutions. I’ll try some variations tomorrow, but I think that if you change your `PlCall()`s to something like the following, it’ll work:

```prolog
{ PlQuery q("assertz(fact(2))");
  PlCheckFail(q::next_solution());
  q.close_destroy(); // or q.cut()
}

```

(I’m on Pacific Daylight Time, and it’s too late in the evening for looking into this further today.)

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [August 19, 2023, 9:05am UTC](https://swi-prolog.discourse.group/t/fatal-error-too-many-stacked-strings-when-using-the-c-version-1-interface/6775/7 "2023-08-19T09:05:29Z")

</div>

> [@hharryyf](#):
>
> ```prolog
> std::vector<std::string> run_query() {
> PlTermv av(1);
> PlQuery q("hello", av);
> 
> ```

I think this needs to be like this. We need to create a Prolog “foreign frame” such that the PlTermv av is reclaimed. Otherwise each invocation of run\_query() will push more term references to the stack, eventually causing an overflow.

```prolog
std::vector<std::string> run_query() {
    PlFrame fr();
    PlTermv av(1);
    PlQuery q("hello", av);

```

As for @peter.ludemann , I guess the PlQuery destructor deals with cutting the query, no?

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [August 19, 2023, 5:20pm UTC](https://swi-prolog.discourse.group/t/fatal-error-too-many-stacked-strings-when-using-the-c-version-1-interface/6775/8 "2023-08-19T17:20:57Z")

</div>

> [@jan](#):
>
> I guess the PlQuery destructor deals with cutting the query, no?

Yes.  
But the problem is that the the result of the query may need to outlive the query; will a call to `PL_cut_query()` preserve the result? (`PL_close_query()` will, I think). And is `PL_cut_query()` sufficient, or is `PL_close_query()` also required? (I think you answered this, but I need to look through my notes)

I think that this isn’t a problem usually because if the query is done withing a `PREDICATE`, things will get cleaned up (although if a lot of queries are done inside a `PREDICATE`, the same problem could arise, I suppose).

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [August 20, 2023, 6:32am UTC](https://swi-prolog.discourse.group/t/fatal-error-too-many-stacked-strings-when-using-the-c-version-1-interface/6775/9 "2023-08-20T06:32:03Z")

</div>

> [@peter.ludemann](#):
>
> But the problem is that the the result of the query may need to outlive the query; will a call to `PL_cut_query()` preserve the result? (`PL_close_query()` will, I think). And is `PL_cut_query()` sufficient, or is `PL_close_query()` also required? (I think you answered this, but I need to look through my notes)

PL\_cut\_query() discards the query itself. PL\_close\_query() does the same, but also discards any bindings created. As long as the PlTerms that provide access to these bindings are recovered, GC will get rid of them in the normal Prolog way. So no, there is no need for PL\_close\_query() and it is in general undesirable as e.g., changes to backtrackable global variables are lost. Only, notably before global variables existed, in most scenarios the two have the same effect and PL\_close\_query() avoids the need for GC. There was a time that didn’t exist either 🙂
