Matlab crashes when running a specific Fortan MEX file under MacOS

1 view (last 30 days)
I succesfully compile a MEX file from two Fortran files using Intel Fortran Composer XE but Matlab crashes when I tried to run the MEX (mexmaci64) file. The person who originally coded the gateway was running it on Windows (probably Matlab 2020b) and it was all working fine, so I suspect there might be a compatiblity issue. I am using Matlab 2022b on MacOS Ventura 13.0.1.
I have tested with another file (https://es.mathworks.com/help/matlab/matlab_external/create-fortran-source-mex-file.html) and I managed to compile and run it smoothly.
Here is the gateway code (I can't provide the other file):
#include <fintrf.h>
SUBROUTINE mexFunction(nlhs, plhs, nrhs, prhs)
!!!pointers to input data: prhs and output: plhs
mwPointer plhs(*), prhs(*)
!!!number of inputs on right and left hand side
INTEGER nlhs, nrhs
!!!pointers to intrinsic functions of the matlab library
mwPointer mxgetpr,mxgetscalar!!, mxCreateString
mwPointer mxgetm, mxgetn, mxCreateDoubleMatrix
mwPointer mxCreateCharMatrixFromStrings
C Array information:
mwSize v_size, cblk_size !!, pname_size, props_size, psys_size
C Arguments for computational routine:
include 'parameters.h'
double precision cblk_i(k5)!! k5 = 12
double precision v_i(l2)!!l2 = 5
c double precision props_o(k5,12+k5)
c double precision psys_o(1,10+k5)
double precision props_o(k5,9+k5) !! double precision props_o(k5,12+k5)
double precision psys_o(1,9+k5)
c character*14 names(k5)
character*14 pname_o(k5)
double precision iPs, ido
integer props_r, props_c, psys_r, psys_c !!, pname_r, pname_c
integer props_s, psys_s, iPs_s, idead_s !!, pname_s
C Get the sizes of the input arrays.
v_row = mxgetm(prhs(1))
v_col = mxgetn(prhs(1))
v_size = v_row*v_col
CALL mxCopyPtrToReal8(mxGetPr(prhs(1)), v_i, v_size)
cblk_row = mxgetm(prhs(2))
cblk_col = mxgetn(prhs(2))
cblk_size = cblk_row*cblk_col
CALL mxCopyPtrToReal8(mxGetPr(prhs(2)), cblk_i, cblk_size)
c Call the FORTRAN routine
CALL main(pname_o,props_o,psys_o,iPs,ido,v_i,cblk_i)
c Creating null matrices as default output
c pname_r = 1
c pname_c = k5
c pname_s = pname_r*pname_c
plhs(1) = mxCreateCharMatrixFromStrings(k5, pname_o)
props_r = size(props_o,1)
props_c = size(props_o,2)
props_s = props_r*props_c
plhs(2)= mxCreateDoubleMatrix(props_r, props_c, 0)
psys_r = size(psys_o,1)
psys_c = size(psys_o,2)
psys_s = psys_r*psys_c
plhs(3)= mxCreateDoubleMatrix(psys_r, psys_c, 0)
plhs(4) = mxCreateDoubleMatrix(1, 1, 0)
plhs(5) = mxCreateDoubleMatrix(1, 1, 0)
c Copy output data from local variables to matlab output variables
c CALL mxCopyCharacterToPtr(pname_o,mxGetData(plhs(1)),pname_s)
CALL mxCopyReal8ToPtr(props_o, mxGetPr(plhs(2)), props_s)
CALL mxCopyReal8ToPtr(psys_o, mxGetPr(plhs(3)), psys_s)
CALL mxCopyReal8ToPtr(iPs, mxGetPr(plhs(4)), 1)
CALL mxCopyReal8ToPtr(ido, mxGetPr(plhs(5)), 1)
return
end
The MEX is compiled as follows (I can provide the verbose report):
mex -v gateway.F main.f
It is then run from two double variable inputs as follows (that's where it crashes - I can provide the crash log):
[a,b,c,d,e]=gateway(v,cblk);
Any help would be greatly appreciated!
  1 Comment
James Tursa
James Tursa on 9 May 2023
Be very wary of the timestwo.f example given in the MATLAB doc. This code has several serious errors in it and I have been unable to get TMW to fix their doc. In particular, the code doesn't do variable type or size checks properly, so you can easily crash MATLAB by doing something as simple as passing in an array instead of a scalar.

Sign in to comment.

Answers (1)

James Tursa
James Tursa on 9 May 2023
The MATLAB Fortran API interface needs to be treated as a pass-by-reference interface. That means you need to have the exact types in the arguments or things will not work properly. The only way to ensure this, especially across different platforms, is to always use variables for arguments, and never use literal constants. You just can't be sure that the integer sizes are going to match. So, first thing you should do before doing any more debugging is replacing all of the literal constant arguments with variables that match the API signatures exactly.
E.g., take this line:
plhs(4) = mxCreateDoubleMatrix(1, 1, 0)
Those literal 1's and 0 should never be used in Fortran calls to API functions. Instead, first look at the signature in the doc:
#include "fintrf.h"
mwPointer mxCreateDoubleMatrix(m, n, ComplexFlag)
mwSize m, n
integer*4 ComplexFlag
Then use those exact variable types in your call. E.g., the above code should look something like this instead:
mwSize :: ONE = 1
integer*4 :: ComplexFlag = 0
:
plhs(4) = mxCreateDoubleMatrix(ONE,ONE,ComplexFlag)
Do this for every single API call that you currently have constants for arguments. Only then can you reliably start any further debugging that is needed, such as checking input variable sizes and types, etc.
Also, I am going to knock the original programmer for not using IMPLICIT NONE in their code. Seriously, this is one of the few helps that the compiler has available to you for detecting variable type mismatches etc. IMO this should always be used in Fortran code.
  6 Comments
Romain Tilhac
Romain Tilhac on 15 May 2023
Edited: Romain Tilhac on 15 May 2023
#include <fintrf.h>
! mwSize declarations for nrows and ncolumns from https://es.mathworks.com/help/matlab/matlab_external/upgrading-mex-files-to-use-64-bit-api.html
! #if MX_HAS_INTERLEAVED_COMPLEX from https://es.mathworks.com/help/matlab/matlab_external/create-fortran-source-mex-file.html
! ComplexFlag and ONE from James Tursa's comments on Mathworks
! -----------------------------------------------------------------------
! Gateway routine
SUBROUTINE mexFunction(nlhs, plhs, nrhs, prhs)
! Declarations
implicit none
! mexFunction arguments
mwPointer plhs(*), prhs(*)
INTEGER nlhs, nrhs ! number of inputs (prhs) and outputs (plhs)
! Intrinsic functions of the matlab library
! mwPointer mxgetpr ! Real data elements in mxDOUBLE_CLASS array (NOT RECOMMENDED)
#if MX_HAS_INTERLEAVED_COMPLEX
mwPointer mxGetDoubles
#else
mwPointer mxGetPr
#endif
mwPointer mxgetscalar ! Real component of first data element in array
mwPointer mxGetM, mxGetN ! Number of rows (mxGetM) and columns (mxGetN) in mxArray
mwPointer mxCreateDoubleMatrix ! 2-D, double-precision, floating-point array
mwPointer mxCreateCharMatrixFromStrings ! 2-D mxChar array initialized to specified value
! Pointers to input/output mxArrays:
mwPointer v_ptr, cblk_ptr
mwPointer props_ptr, psys_ptr, iPs_ptr, ido_ptr
! Array information:
mwSize v_size, cblk_size
mwSize v_row, v_col, cblk_row, cblk_col
mwSize props_s, psys_s, iPs_s, idead_s
mwSize props_r, props_c, psys_r, psys_c
! Arguments for computational routine:
include 'perplex_parameters.h'
double precision cblk_i(k5) ! k5 = 12
double precision v_i(l2) ! l2 = 5
double precision psys_o(1,9+k5) ! array of numerical output properties of bulk system
double precision props_o(k5,9+k5) ! array of numerical output properties per phase
double precision iPs, ido ! iPs stable phases, ido?
character*14 pname_o(k5)
mwSize :: ONE = 1
integer*4 :: ComplexFlag = 0
! -----------------------------------------------------------------------
! Get the sizes of the input arrays.
v_row = mxGetM(prhs(1))
v_col = mxGetN(prhs(1))
v_size = v_row*v_col
#if MX_HAS_INTERLEAVED_COMPLEX
v_ptr = mxGetDoubles(prhs(1))
#else
v_ptr = mxGetPr(prhs(1))
#endif
CALL mxCopyPtrToReal8(v_ptr,v_i,v_size)
! CALL mxCopyPtrToReal8(mxGetPr(prhs(1)), v_i, v_size)
cblk_row = mxGetM(prhs(2))
cblk_col = mxGetN(prhs(2))
cblk_size = cblk_row*cblk_col
#if MX_HAS_INTERLEAVED_COMPLEX
cblk_ptr = mxGetDoubles(prhs(2))
#else
cblk_ptr = mxGetPr(prhs(2))
#endif
CALL mxCopyPtrToReal8(cblk_ptr,cblk_i,v_size)
! CALL mxCopyPtrToReal8(mxGetPr(prhs(2)), cblk_i, cblk_size)
! -----------------------------------------------------------------------
! Call the FORTRAN routine
CALL main(pname_o,props_o,psys_o,iPs,ido,v_i,cblk_i)
! -----------------------------------------------------------------------
! Get the sizes of the output arrays.
props_r = size(props_o,1)
props_c = size(props_o,2)
props_s = props_r*props_c
psys_r = size(psys_o,1)
psys_c = size(psys_o,2)
psys_s = psys_r*psys_c
! Creating null matrices as default output
plhs(1) = mxCreateCharMatrixFromStrings(k5, pname_o)
plhs(2)= mxCreateDoubleMatrix(props_r, props_c, ComplexFlag)
plhs(3)= mxCreateDoubleMatrix(psys_r, psys_c, ComplexFlag)
plhs(4) = mxCreateDoubleMatrix(ONE,ONE,ComplexFlag)
plhs(5) = mxCreateDoubleMatrix(ONE,ONE,ComplexFlag)
! -----------------------------------------------------------------------
! Copy output data from local variables to matlab output variables
!! CALL mxCopyCharacterToPtr(pname_o,mxGetData(plhs(1)),pname_s)
! CALL mxCopyReal8ToPtr(props_o, mxGetPr(plhs(2)), props_s)
! CALL mxCopyReal8ToPtr(psys_o, mxGetPr(plhs(3)), psys_s)
! CALL mxCopyReal8ToPtr(iPs, mxGetPr(plhs(4)), ONE)
! CALL mxCopyReal8ToPtr(ido, mxGetPr(plhs(5)), ONE)
#if MX_HAS_INTERLEAVED_COMPLEX
props_ptr = mxGetDoubles(plhs(2))
psys_ptr = mxGetDoubles(plhs(3))
iPs_ptr = mxGetDoubles(plhs(4))
ido_ptr = mxGetDoubles(plhs(5))
#else
props_ptr = mxGetPr(plhs(2))
psys_ptr = mxGetPr(plhs(3))
iPs_ptr = mxGetPr(plhs(4))
ido_ptr = mxGetPr(plhs(5))
#endif
CALL mxCopyReal8ToPtr(props_o, props_ptr, props_s)
CALL mxCopyReal8ToPtr(psys_o, psys_ptr, psys_s)
CALL mxCopyReal8ToPtr(iPs, iPs_ptr, ONE)
CALL mxCopyReal8ToPtr(ido, ido_ptr, ONE)
return
end
Romain Tilhac
Romain Tilhac on 15 May 2023
Edited: Romain Tilhac on 16 May 2023
But, I am now quite convinced that the issue is the computational routine (see my message).

Sign in to comment.

Products


Release

R2022b

Community Treasure Hunt

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

Start Hunting!