2

I am developing an R package with C++ functions. I use Rcpp. Everything was fine when writing and testing. However, when I finished and ran it in a loop, I occasionally got the following warnings and errors: Warnings and Errors

Warning: stack imbalance in '.Call', 78 then 77

Warning: stack imbalance in '{', 75 then 74

Warning: stack imbalance in '.Call', 78 then 79

Warning: stack imbalance in '{', 75 then 76

Warning: stack imbalance in '.Call', 78 then 77

Warning: stack imbalance in '{', 75 then 74

So I googled stack imbalance and I found:

What is a stack imbalance?

This article states stack imbalance is usually caused by differences (mismatching) in calling convention among languages. As far as I know, callng convention is an agreement on whether the caller function to delete local variables or the callee functions to delete.

And I found this:

http://www.stats.uwo.ca/faculty/murdoch/software/compilingDLLs/

It says R is using cdecl while C++ uses stdcall.

"If your function uses stdcall instead of cdecl, there will likely be a crash when you return, because your parameters will be removed from the stack after they're already gone."

Please let me know if I made any mistakes in the statement.

This is the C++ function being called by my R code:

//[[Rcpp::export]]
int compute(SEXP p_in, Rcpp::NumericVector a) {
    Rcpp::XPtr<emcdf> p(p_in);
    p->cdf(a);
    return p->getResult();
}
//p_in is an external pointer(pointer to an emcdf object in C++)

So, my question is, how do I fix this?

I appreciate your help.

More details and code 2.14.2017

Thank you guys for answering. Here's more code:

//declaration of class "emcdf"
class emcdf{
public:
  explicit emcdf(Rcpp::NumericMatrix& x, int n);
  ~emcdf();
  void cdf(Rcpp::NumericVector& a);
  int getResult();
private:
  int num;
  int k;
  std::thread* t;
  std::vector<Rcpp::NumericMatrix*> data;
  int size;
  int* result;
  void (*ptr) (Rcpp::NumericMatrix*, Rcpp::NumericVector, int*);
  void find_func();
};

  //definition of class "emcdf"
  emcdf::emcdf(Rcpp::NumericMatrix& x, int n){
    //initialize members
    t = new std::thread[n];
    num = n;
    k = x.ncol();
    size = x.nrow()/num;
    result = new int[num];
    find_func();

    int i = 0;
    for(; i<num - 1; ++i)
      data.push_back(copy(x, i*size, size));

    data.push_back(copy(x, i*size, x.nrow() - i*size));

  }

  emcdf::~emcdf(){
    delete[] t;
    for(int i=0; i<num; ++i)
      delete data[i];
    delete[] result;
  }

  void emcdf::cdf(Rcpp::NumericVector& a){
    for(int i=0; i<num; ++i){
      t[i] = std::thread(*ptr, data[i], a, result + i);
    }
    for(int i=0; i<num; ++i)
      t[i].join();
  }

  int emcdf::getResult(){
    int sum = 0;
    for(int i=0; i<num; ++i)
      sum += result[i];
    return sum;
  }

//other functions
Rcpp::NumericMatrix* copy(Rcpp::NumericMatrix& x, int row, int nrow){

  NumericMatrix* out = new NumericMatrix(nrow, x.ncol());
  int firstRow = 0;
  while(firstRow < nrow){
    for(int j=0; j<x.ncol(); ++j){
      out->at(firstRow,j) = x.at(firstRow + row,j);
    }
    ++firstRow;
  }
  return out;
}

//makes "emcdf" pointer 
//[[Rcpp::export]]
RcppExport SEXP build(SEXP x_in, int num){

  Rcpp::NumericMatrix x(x_in);
  emcdf* em = new emcdf(x, num);
  Rcpp::XPtr<emcdf> p(em, true);
  return p;
}

//take pointer of "emcdf" from build() and compute cdf results
//[[Rcpp::export]]
int compute(SEXP& p_in, Rcpp::NumericVector& a){
  Rcpp::XPtr<emcdf> p(p_in);
  p->cdf(a);
  return p->getResult();
}

The parameter SEXP& p_in in compute() is passed from the return of build(). In my R code, I called compute() and got the stack imbalance error. It doesn't appear every time, but when called over 1000 times continuously, it's likely to go wrong.

Kevin Ushey suggested:
"It looks like the issue here is simply that you're attempting to use R / Rcpp within a separate thread, and that unfortunately won't work (as you can end up triggering the garbage collector from a separate thread)."

Does that mean if I avoid using Rcpp functions/ objects in separate threads, for example, don't use NumericMatrix in *ptr which my threads run, this error will be fixed?

Thank you.

Community
  • 1
  • 1
David
  • 819
  • 1
  • 11
  • 14
  • 2
    That is a basic bug in your code. If you use Rcpp, you *never* need to `PROTECT` and `UNPROTECT`. And as the questions stands, nobody can help you as there is *nothing* reproducible here. – Dirk Eddelbuettel Feb 08 '17 at 17:33
  • Dirk, you're right, I googled and this problem is hard to solve as it's hard to reproduce. Could you tell me what "basic bug" you think it might be or locate? Thank you. – David Feb 08 '17 at 20:29
  • 2
    You need to provide more detail, i.e. how was `p_in` created in the first place? How is the `emcdf` class defined? Additionally, there should be no reason to pass `p_in` as a `SEXP` and construct a local `Rcpp::XPtr`, you can just pass `p_in` as a `Rcpp::XPtr` and operate on it directly. – nrussell Feb 08 '17 at 21:05
  • I tried passing Rcpp::XPtr as parameter and it led to error: "emcdf was not declared in this scope" when building package. Then I followed an example (sorry I can't find it now) and got my current code. – David Feb 13 '17 at 12:04
  • I never use PROTECT and UNPROTECT in my code. – David Feb 13 '17 at 12:27

1 Answers1

6

I think you unfortunately are on the wrong track with your initial diagnosis.

When R reports a stack imbalance, it means the internal protection stack (which is used to protect R objects on the stack from the garbage collector) is unbalanced, indicating that something got out of sync in some C / C++ routine somewhere. This is unrelated to calling conventions.

Rcpp generally manages protection of its objects outside of the protection stack; it explicitly uses the R_PreserveObject() and R_ReleaseObject() APIs, which are not stack-based.

Without a reproducible example it's hard to say more, but the most likely cause is you have mismatched calls to PROTECT() / UNPROTECT() in separate code that you haven't yet shown.

Kevin Ushey
  • 20,530
  • 5
  • 56
  • 88
  • 1
    Thank you. I never use PROTECT or UNPROTECT in my code. I posted more code below. I found that when I called compute() over 1000 times, the stack imbalance error shows. – David Feb 13 '17 at 12:32