0

Edit

Same behavior without FORTRAN and undocumented part. What can be wrong in this case? LibraryFunction below is supposed to be just an identity function.

(* wrapper *)
wra = "
#include \"WolframLibrary.h\"
#include \"WolframCompileLibrary.h\" 
DLLEXPORT mint WolframLibrary_getVersion(){
    return WolframLibraryVersion ;
}
DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData){
    return 0 ;
}           

EXTERN_C DLLEXPORT int plus(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res){
    MTensor A ;
    mint I, J ;
    A = MArgument_getMTensor(Args[0]) ;
    MArgument_setMTensor(Res,A) ;
    return LIBRARY_NO_ERROR ;
}
" ;

(* export wrapper  *)
SetDirectory[NotebookDirectory[]] ;
Export["wrapper.cc",wra,"String"] ;

(* create library *)
Needs["CCompilerDriver`"]
CreateLibrary[
    {"wrapper.cc"},
    "plus",
    Rule["TargetDirectory",NotebookDirectory[]],
    Rule["CleanIntermediate",True],
    Rule["CompileOptions"," "],
    Rule["Debug",False]
] ;

(* load library *)
LIB = LibraryFunctionLoad[StringJoin[NotebookDirectory[],"plus"],"plus",List[List[Real,1]],List[Real,1]] 

(* version with check for arg *)
FUN[VAR_] := LIB[VAR] /; Apply[And,Map[NumberQ,VAR]] ;

Repeated execution of this cell results in kernel crash

OUT = NestList[LIB,INI,100] ;

Original post

For some reason using Nestlist with LibraryFunction can lead to kernel crash. It looks like something non-numerical is passed to LibraryFunction. There is no problem if the argument is checked, but my argument can be a long list and the number of NestList iterations can be large too. Is there a better workaround in this case?

$Version
(* 12.0.0 for Linux x86 (64-bit) (April 7, 2019) *)

(* wrapper *)
wra = "
#include \"WolframLibrary.h\"
#include \"WolframCompileLibrary.h\" 
DLLEXPORT mint WolframLibrary_getVersion(){
    return WolframLibraryVersion ;
}
DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData){
    return 0 ;
}           
extern \"C\" {
    void plus_(mreal a[]) ;
}       
EXTERN_C DLLEXPORT int plus(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res){
    MTensor A ;
    A = MArgument_getMTensor(Args[0]) ;
    plus_(MTensor_getRealDataMacro(A)) ;
    MArgument_setMTensor(Res,A) ;
    return LIBRARY_NO_ERROR ;
}
" ;

(* program *)
pro = "
    pure subroutine plus(x)
        implicit none
        real(8),intent(inout), dimension(10) :: x
        x = x + 1.0_8
    end subroutine plus
" ;

(* export wrapper & program *)
SetDirectory[NotebookDirectory[]] ;
Export["wrapper.cc",wra,"String"] ;
Export["plus.f90",pro,"String"] ;

(* compile program *)
Run["gfortran -c  plus.f90 "] 

(* create library *)
Needs["CCompilerDriver`"]
CreateLibrary[
    {"wrapper.cc","plus.o"},
    "plus",
    Rule["TargetDirectory",NotebookDirectory[]],
    Rule["CleanIntermediate",True],
    Rule["CompileOptions"," "],
    Rule["Debug",False]
] ;

(* load library *)
LIB = LibraryFunctionLoad[StringJoin[NotebookDirectory[],"plus"],"plus",List[List[Real,1]],List[Real,1]] 

(* version with check for arg *)
FUN[VAR_] := LIB[VAR] /; Apply[And,Map[NumberQ,VAR]] ;

Works fine

INI = ConstantArray[0.,10] ;
FUN[INI]
LIB[INI]

Works fine

OUT = NestList[FUN,INI,100] ;

Repeated execution of this cell results in kernel crash

OUT = NestList[LIB,INI,100] ;
I.M.
  • 2,926
  • 1
  • 13
  • 18
  • If there is a crash in a situation like this, it is almost certainly in your C or Fortran code. Passing a symbol to a LibraryLink function will not result in a crash. It will simply fail to evaluate, and it might issue a friendly error message. But it won't crash. – Szabolcs Aug 17 '19 at 10:45
  • BTW I find your code very hard to read. Please do not use the full form of expressions for no good reason. Rule[1,2] and List[1,2] become very hard to follow once they're nested. Use 1 -> 2 and {1, 2}. – Szabolcs Aug 17 '19 at 10:48
  • Another comment (keep in mind that I'm not very familiar with Fortran): You seem to be using arrays of real numbers, but you never retrieve their size. You seem to be assuming a size 10 without ever checking that that's what you get. I'd add a check at the beginning of the C function. You are also using undocumented constructs like MTensor_getRealDataMacro instead of the documented API libData->MTensor_getRealData. Is there any reason you want to do this? – Szabolcs Aug 17 '19 at 10:55
  • No particular reason for MTensor_getRealDataMacro, just seen it here, I'll test the code with automatic fortran array size, not sure fixed size is the problem – I.M. Aug 17 '19 at 12:14
  • My point is that you should make sure that you are not accidentally indexing over the end of the array ... – Szabolcs Aug 17 '19 at 16:42
  • I tried the code without Fortran. I cannot reproduce the problem. Can you try with a fresh kernel? (But please, use readable notation and remove irrelevant options.) – Szabolcs Aug 19 '19 at 12:45

0 Answers0