segfault when using "matmul" function in FORTRAN mex code

16 vues (au cours des 30 derniers jours)
Ugur
Ugur le 18 Juin 2015
Commenté : Ugur le 24 Juin 2015
When I try to multiply two matrices of complex type using "matmul" function, I receive a segfault with the following code;
matD = matmul(transpose(matB),matC*matB)
while this runs without an error
matC = matC*matB
matD = matmul(transpose(matB),matC)
I tried to run a similar code directly in Fortran and it did not give any error (as expected). What may cause such an instability in mex?

Réponse acceptée

James Tursa
James Tursa le 18 Juin 2015
Modifié(e) : James Tursa le 18 Juin 2015
How large are your variables? I would hazard a guess that they are large, in the 10's or 100's MB or larger.
One of the problems with Fortran is that temporary variables typically get memory from the stack (relatively small memory available), rather than the heap (relatively large memory available). So calculations that immediately get used as arguments or in other calculations are temporary variables that take stack memory, whereas calculations that immediately get assigned to a variable do not ... such calculations are done in-place in the left-hand-side variable. So look at your two formulations:
matD = matmul(transpose(matB),matC*matB)
Here transpose(matB) is a temporary result that is only used as an argument, so the memory for it will typically be taken from the stack. Likewise, matC*matB is a temporary result that is only used for an argument, so its memory will also be taken from the stack. If they are too large, you will blow the stack memory (a fixed amount of memory much smaller than the heap) and the program will crash.
Now look at your second formulation:
matC = matC*matB
matD = matmul(transpose(matB),matC)
The matC*matB calculation is assigned to a variable. Thus, the result does not require additional stack memory ... the results can be done "in-place" in the matC variable (since the * is "element-wise multiplication" in Fortran). There is still an issue with the transpose(matB) calculation taking stack memory, but it appears that was not a tipping point for the crash.
As to why your Fortran stand-alone program worked fine but the mex routine using the same code failed, it is likely simply the result of having different amounts of stack memory available for the two different implementations. E.g., had you started MATLAB with some type of command that would increase its stack space, the mex routine may have worked fine.
That is one reason I tend to avoid certain constructs like using "any" on a temporary calculation result. E.g.,
if( any( A == B ) ) then
! etc
endif
If A and B are large, then the result A == B will be large and come from the stack, potentially crashing the program. To guard against this, I often fall back to F77 style programming because it is protected against this. E.g., the above could be coded as follows:
flag = .false.
do i=1,n
if( A(i) == B(i) ) then
flag = .true.
exit
endif
enddo
if( flag ) then
! etc
endif
Seems kind of backwards to have to resort to F77 style code to protect against stack overflows, but there it is. There might be compiler directives to tell the compiler to create temporary and local variables from the heap, but doing so ties your code to non-standard compiler directives. Rather than doing this, I tend to just fall back on F77 style coding because I know it will be safe for large variables. I don't want to have to rely on compiler directives, or increasing the stack size when starting the program, etc. I would rather write code from the outset that I know will work regardless of stack size (unless of course the heap runs out).
Another potential issue is the matB, matC, and matC variables themselves. If they are non-allocated variables then their memory will also typically come from the stack. So you should never do something like this in Fortran (actually you can have this exact problem in other languages such as C or C++ as well):
subroutine whatever(large_number)
integer large_number
real*8 X(large_number)
The reason is that X will take stack memory, and potentially crash the program. Local large variables should always be allocated since that memory will come from the heap. E.g.,
subroutine whatever(large_number)
integer large_number, status
real*8, allocatable :: X(:)
allocate( X(large_number), stat = status )
if( status /= 0 ) then
! handle the memory allocation error
endif
! code to use X
deallocate(X)
  8 commentaires
Ugur
Ugur le 24 Juin 2015
Many thanks for your interest on the issue! I am doing now exactly what you suggested, indeed. When I try a standalone application that just inverts a matrix, it works. But when I try to introduce a bunch of matrix operations in advance, there the problem begins. Maybe I can ask one last question about the issue: When I debug the code using Valgrind-memcheck, it indicates an "illegal write" whenever I allocate a matrix. I think the way Fortran allocates a block in heap memory is considered illegal in C environment (and so in MATLAB) but MATLAB can compensate this up to a certain extent. And when too much allocation/deallocation takes place, it crashes. (I know it sounds silly but that's the only explanation I can give after this many trials) Can you suggest me a better way to allocate some memory, which is valid in Fortran and not illegal in MATLAB?
Ugur
Ugur le 24 Juin 2015
Hi James,
Please ignore all the things I wrote above. I found where the memory corruption comes from! It was my mistake, indeed. At a certain point the code was writing outside an array (stupid me!) But gdb was indicating the segmentation fault error when I try to launch another function, or allocate another array. And this was changing everytime I changed the code since different memory blocks were put next to each other I guess. Anyway, many many thanks for all your interest in the issue :)

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Write C Functions Callable from MATLAB (MEX Files) dans Help Center et File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by