DevNotes #2. Short, Safe and Informative Error Messages from MEX

by Pavel Holoborodko on February 14, 2016

MEX API provides two functions for proper handling of erroneous situations: mexErrMsgTxt and mexErrMsgIdAndTxt. Both show error message, interrupt execution of a MEX module and return to MATLAB immediately.

Under the hood the functions are implemented through C++ exceptions. The reason for such design choice is unclear. Throwing C++ exceptions across module boundary (e.g. from dynamic library to host process) is unsafe and generally considered as bad practice in software design. Exceptions are part of C++ run-time library and different versions of it might have incompatible implementations.

This restricts MEX to use only the same version of C++ run-time and GCC which were used to build that particular version of MATLAB itself. This is one of the reasons why TMW distributes its own version of GCC/libstdc++ along with every release of MATLAB and pushes developers to use it for MEX compilation.

Such unfortunate design decision have two unpleasant consequences: (1) developers must use some old version of GCC (forget all the fancy stuff from C++11, C++14, etc.); (2) compiled MEX modules most likely will not work on older/newer versions of MATLAB (re-compilation is required).

The good news is that both issues are solvable and we will write more about this in future.

Here we propose just first step towards freedom – avoid direct usage of mexErrMsg** functions. Use simple wrapper instead:

void mxShowCriticalErrorMessage(const char *msg)
{
    mxArray *arg;
    arg = mxCreateString(msg);
    mexCallMATLAB(0,0,1,&arg,"error");
}

The mxShowCriticalErrorMessage calls MATLAB’s built-in error function through interpreter with message as parameter.

Besides being safe, this approach potentially gives us better control over what additional information is shown together with error messages. Instead of a string, we can use errorStruct as argument to error with its fields tuned to our requirements (Not shown as we want to keep example simple).

Even without tuning, output of mxShowCriticalErrorMessage is much more informative and user-friendly:

  • Error message for built-in functionality:
    >> A = magic(3);
    >> A(0)
    'Subscript indices must either be real positive integers or logicals.'

    Nice one-line message without any distracting information.

  • Error message from MEX using mexErrMsgTxt/mexErrMsgIdAndTxt:

    >> A = mp(magic(3));         % convert matrix to arbitrary precision type, provided by our toolbox
    >> A(0)                      % subsref is called from toolbox, it is implemented in mpimpl.mex.
    'Error using mpimpl'
    'Subscript indices must either be real positive integers or logicals.'
    'Error in mp/subsref (line 860)'
                 '[varargout{1:nargout}] = mpimpl(170, varargin{:});'

    Intimidating four lines with actual error message lost in the middle. All the additional information is meaningless for end-user and actually misleading.

    The worst thing is that such error message is very different from what user get used to (see above one-liner), which leads to confusion if MEX plugin is properly working at all.

  • Error message from MEX using mxShowCriticalErrorMessage:

    >> A = magic(3);
    >> A(0)
    'Error using mp/subsref (line 860)'
    'Subscript indices must either be real positive integers or logicals.'

    Now message is clear and short, with error description in the last line where user focus is.

Footnote

†It is actually possible to create single binary MEX module, which will work on any GNU Linux flavor regardless of the versions of libc/libstc++/gcc installed in the system or used in MATLAB.

{ 0 comments… add one now }

Leave a Comment

Previous post:

Next post: