Issue: MATLAB crashes running mex function at inconsistent points in function.

5 views (last 30 days)
I am working on a mex function that utilizes a C++ class for operating with SQL. When the a.Search(MX_SR) is executed (which searches the database and returns a set of object IDs satisfying a range for sorting indices), the mex function crashes a different points. The two points it has halted at is after "Search matlab method entered" and immediately before return in class_interface_mex. I have a hunch it is something to do with not allocating/deallocating the std::vector variables. I am not sure exactly how to tackle it however. Several other articles mention issues with a compilation variable (on Windows). I am running on Ubuntu 14.04, MATLAB 2015a. Compiled using c++4.9.
Uses std library, boost, mysql libraries in underlying functions (i.e. DBInterface.hpp, DBInterface.cpp).
class_interface_mex.cpp:
#include "mex.h"
#include "class_handle.hpp"
// The class that we are interfacing to
#include "DBInterface.h"
#include "ML_Utility.cpp"
#include "DBInterface.cpp"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
// Get the command string
char cmd[64];
if (nrhs < 1 || mxGetString(prhs[0], cmd, sizeof(cmd)))
mexErrMsgTxt("First input should be a command string less than 64 characters long.");
// New
if (!strcmp("new", cmd)) {
// Check parameters
if (nlhs != 1)
mexErrMsgTxt("New: One output expected.");
// Return a handle to a new C++ instance
plhs[0] = convertPtr2Mat<DBInterface>(new DBInterface);
return;
}
// Check there is a second input, which should be the class instance handle
if (nrhs < 2)
mexErrMsgTxt("Second input should be a class instance handle.");
// Delete
if (!strcmp("delete", cmd)) {
// Destroy the C++ object
destroyObject<DBInterface>(prhs[1]);
// Warn if other commands were ignored
if (nlhs != 0 || nrhs != 2)
mexWarnMsgTxt("Delete: Unexpected arguments ignored.");
return;
}
// Get the class instance pointer from the second input
DBInterface *DB_instance = convertMat2Ptr<DBInterface>(prhs[1]);
// Call the various class methods
// Add2Buffer
if (!strcmp("Add2Buffer", cmd)) {
// Check parameters
if (nlhs < 0 || nrhs < 4)
mexErrMsgTxt("Add2Buffer: Unexpected arguments.");
// Call the method
std::vector<double> Found_Objects;
std::vector<double> New_Objects;
Found_Objects = MX2DoubleVector(prhs[2]);
New_Objects = MX2DoubleVector(prhs[3]);
DB_instance->Add2Buffer(Found_Objects, New_Objects);
return;
}
// Build
if (!strcmp("Build", cmd)) {
// Check parameters
if (nlhs > 0 || nrhs > 2)
mexErrMsgTxt("Build: Unexpected arguments.");
// Call the method
DB_instance->Build();
return;
}
// Search
if (!strcmp("Search", cmd)) {
mexPrintf("\n Search Entered.");
// Check parameters
if (nlhs != 1 || nrhs > 3)
mexErrMsgTxt("\n Search: Unexpected arguments.");
std::vector<int> SearchRange;
std::vector<int> Res;
mexPrintf("\n Search Variables Defined.");
SearchRange = MX2IntVector(prhs[2]);
mexPrintf("\n Search: Search Range is of size: %d", SearchRange.size());
if (SearchRange.size()!=40)
mexErrMsgTxt("\n Search: Failure to convert Search Range to proper size");
for (int i=0; i<SearchRange.size(); i++)
mexPrintf("\n Search: Search Range at %d is %d", i, SearchRange.at(i));
mexPrintf("\n Search: Size Check Complete.");
Res = DB_instance->Search(SearchRange);
mexPrintf("\n Search: Res is of size: %d", Res.size());
mexPrintf("\n Search: Res at first index is: %d", Res.at(0));
mexPrintf("\n Search: C++ program run complete.");
plhs[0] = IntVector2MX(Res);
mexPrintf("\n Conversion from Integer Vector to mxArray complete.");
return;
}
// Got here, so command not recognized
mexErrMsgTxt("Command not recognized.");
}
DatabaseInterface.m:
%CLASS_INTERFACE Example MATLAB class wrapper to an underlying C++ class
classdef DatabaseInterface < handle
properties (SetAccess = private, Hidden = true)
objectHandle; % Handle to the underlying C++ class instance
end
methods
%%Constructor - Create a new C++ class instance
function this = DatabaseInterface(varargin)
this.objectHandle = class_interface_mex('new', varargin{:});
end
%%Destructor - Destroy the C++ class instance
function delete(this)
class_interface_mex('delete', this.objectHandle);
end
%%Build - Build B and M.
function varargout = Build(this, varargin)
[varargout{1:nargout}] = class_interface_mex('Build', this.objectHandle, varargin{:});
end
%%Search - Search DB given an object.
function varargout = Search(this, varargin)
display('Search matlab method entered.');
[varargout{1:nargout}] = class_interface_mex('Search', this.objectHandle, varargin{:});
end
%%Add2Buffer - Add buffer to DB.
function varargout = Add2Buffer(this, varargin)
[varargout{1:nargout}] = class_interface_mex('Add2Buffer', this.objectHandle, varargin{:});
end
end
end
class_handle.hpp:
#ifndef __CLASS_HANDLE_HPP__
#define __CLASS_HANDLE_HPP__
#include "mex.h"
#include <stdint.h>
#include <string>
#include <cstring>
#include <typeinfo>
#define CLASS_HANDLE_SIGNATURE 0xFF00F0A5
template<class base> class class_handle
{
public:
class_handle(base *ptr) : ptr_m(ptr), name_m(typeid(base).name()) { signature_m = CLASS_HANDLE_SIGNATURE; }
~class_handle() { signature_m = 0; delete ptr_m; }
bool isValid() { return ((signature_m == CLASS_HANDLE_SIGNATURE) && !strcmp(name_m.c_str(), typeid(base).name())); }
base *ptr() { return ptr_m; }
private:
uint32_t signature_m;
std::string name_m;
base *ptr_m;
};
template<class base> inline mxArray *convertPtr2Mat(base *ptr)
{
mexLock();
mxArray *out = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);
*((uint64_t *)mxGetData(out)) = reinterpret_cast<uint64_t>(new class_handle<base>(ptr));
return out;
}
template<class base> inline class_handle<base> *convertMat2HandlePtr(const mxArray *in)
{
if (mxGetNumberOfElements(in) != 1 || mxGetClassID(in) != mxUINT64_CLASS || mxIsComplex(in))
mexErrMsgTxt("Input must be a real uint64 scalar.");
class_handle<base> *ptr = reinterpret_cast<class_handle<base> *>(*((uint64_t *)mxGetData(in)));
if (!ptr->isValid())
mexErrMsgTxt("Handle not valid.");
return ptr;
}
template<class base> inline base *convertMat2Ptr(const mxArray *in)
{
return convertMat2HandlePtr<base>(in)->ptr();
}
template<class base> inline void destroyObject(const mxArray *in)
{
delete convertMat2HandlePtr<base>(in);
mexUnlock();
}
#endif // __CLASS_HANDLE_HPP__
ML_Utility.cpp:
/*
* ML_Utility.cpp
*
* Created on: Jun 1, 2015
* Author: derek
*/
#include "mex.h"
#include <vector>
#include <string>
#include "matrix.h"
mxArray * DoubleVector2MX(const std::vector<double>& v){
mxArray * mx = mxCreateDoubleMatrix(1,v.size(), mxREAL);
std::copy(v.begin(), v.end(), mxGetPr(mx));
return mx;
}
std::vector<double> MX2DoubleVector(const mxArray prhs[]){
std::vector<double> Vec;
const mxArray *Cons_prhs = prhs;
size_t NRow = mxGetN(Cons_prhs);
size_t NCol = mxGetM(Cons_prhs);
std::string::size_type sz;
for (long int nn=0; nn<NRow; nn++){
for (long int mm=0; mm<NCol; mm++){
Vec.push_back((double)mxGetPr(Cons_prhs)[0]);
mxGetPr(Cons_prhs)[0]+=1;
}
}
return Vec;
}
mxArray * IntVector2MX(const std::vector<int>& v){
mxArray *mx;
mexPrintf("\n IntVector2MX: Pointer defined.");
mx = mxCreateNumericMatrix(1, v.size(),mxINT32_CLASS, mxREAL);
mexPrintf("\n IntVector2MX: Numeric array created.");
std::copy(v.begin(), v.end(), mxGetPr(mx));
mexPrintf("\n IntVector2MX: Pointer to Data allocated.");
mexPrintf("\n IntVector2MX: Copy Complete.");
return mx;
}
std::vector<int> MX2IntVector(const mxArray prhs[]){
std::vector<int> Vec;
unsigned int *pr;
pr = (unsigned int *)mxGetData(prhs);
mexPrintf("\n MX2IntVector: Variables defined.");
size_t NElem = mxGetNumberOfElements(prhs);
mexPrintf("\n MX2IntVector: Size aquired.");
std::string::size_type sz;
for (long int nn=0; nn<NElem; nn++){
mexPrintf("\n MX2IntVector: Entered copy iteration.");
Vec.push_back(*pr++);
mexPrintf("\n MX2IntVector: Copy Iteration Complete");
//mxGetPr(pr)[0]+=1;
mexPrintf("\n MX2IntVector: Pointer Increment complete.");
}
if (Vec.size()!=(NElem))
mexErrMsgTxt("\n MX2IntVector: Failure to populate vector. ");
return Vec;
}

Accepted Answer

James Tursa
James Tursa on 3 Jun 2015
Edited: James Tursa on 3 Jun 2015
I haven't looked at your code in detail, but I do have a couple of comments based on a cursory look.
1) It appears to me that your architecture is set up so that the only place the new object handle is kept is in a returned MATLAB variable (uint64). This puts a heavy reliance on the user to NEVER lose that variable. If they did then your routine could not recover. It is locked and there is no way to unlock it because there is no way to pass in a valid handle (via the uint64) to get it unlocked. I would advise keeping track of that handle in your mex routine (e.g., a top level variable) so that if you need to clear the mex function for some reason and you don't have the proper uint64 to pass in, you can still do so (e.g., add another input command so that the mex function can delete the object on its own and unlock itself).
2) It looks like this loop is intended to copy data from an mxArray variable into a C++ vector:
for (long int nn=0; nn<NRow; nn++){
for (long int mm=0; mm<NCol; mm++){
Vec.push_back((double)mxGetPr(Cons_prhs)[0]);
mxGetPr(Cons_prhs)[0]+=1;
}
}
But what looks to me like your "advance to next value" logic doesn't make sense. mxGetPr(Cons_prhs)[0] is the double value itself, not some pointer. So you end up incrementing the first element of the original mxArray by 1 each iteration, rather than stepping through the double elements. I think you meant something more like this instead:
double *pr = mxGetPr(Cons_prhs);
for (long int nn=0; nn<NRow; nn++){
for (long int mm=0; mm<NCol; mm++){
Vec.push_back(*pr++);
}
}
3) This memory copy doesn't look right either:
mxArray * IntVector2MX(const std::vector<int>& v){
mxArray *mx;
mexPrintf("\n IntVector2MX: Pointer defined.");
mx = mxCreateNumericMatrix(1, v.size(),mxINT32_CLASS, mxREAL);
mexPrintf("\n IntVector2MX: Numeric array created.");
std::copy(v.begin(), v.end(), mxGetPr(mx));
You are attempting to copy 32-bit integers, but mxGetPr returns a (double *) type, not a (int *) type. So I think you will end up calling the wrong copy method because it thinks it needs to copy into double memory. I can easily see this writing off the end of the array and crashing. Try this instead:
std::copy(v.begin(), v.end(), (int *)mxGetData(mx));
  4 Comments
Derek Kuether
Derek Kuether on 4 Jun 2015
I will definitely look at that. I am having another issue. Id make a new thread but I dont imagine it is a huge fix. The code below says (per the display outputs) that all the values are zero. Seems very strange since the same approach works with integers, with small changes for double.
std::vector<double> MX2DoubleVector(const mxArray prhs[]){
std::vector<double> Vec;
double *pr;
if (!mxIsDouble(prhs))
mexErrMsgTxt("MX2Double: Input not double.");
pr = mxGetPr(prhs);
double temp;
mexPrintf("\n MX2DoubleVector: Variables defined.");
size_t NElem = mxGetNumberOfElements(prhs);
mexPrintf("\n MX2DoubleVector: Size aquired.");
temp = *pr;
for (long int nn=0; nn<NElem; nn++){
mexPrintf("\n MX2DoubleVector: Entered copy iteration: %d", pr);
mexPrintf("\n MX2DoubleVector: Value: %d", temp);
temp = *pr++;
Vec.push_back(temp);
mexPrintf("\n MX2DoubleVector: Copy Iteration Complete");
}
if (Vec.size()!=(NElem))
mexErrMsgTxt("\n MX2DoubleVector: Failure to populate vector. ");
return Vec;
}
James Tursa
James Tursa on 5 Jun 2015
Edited: James Tursa on 5 Jun 2015
%d is an integer format but temp is a double, so they don't match up. You need to use a floating point format to print temp out (e.g., %f or %e or %g). Also, pr is a pointer, so you should really be using %p to print it out, not %d.

Sign in to comment.

More Answers (0)

Categories

Find more on Write C Functions Callable from MATLAB (MEX Files) in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!