- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have a derived type that contains an allocatable array. A bound procedure exists that allows adding elements to that array. The adding involves a call to move_alloc. I call a procedure in a DLL with an argument of that derived type. The DLL procedure adds an element to the array. If after the return from the DLL procedure I add another element to the array -> crash.
I think this is somehow related to the fact that a Windows DLL has its own heap and pointers from allocations done in a DLL must not be used in the main program. However before I completely rework the way our derived type works, I would like to know if actually this is the cause or if it is perhaps a bug in my program or ifort (hope's small but you never know). Someone might even know a magic workaround !
Here is a small reproducer, our real code is a lot more complex:
the module that defines the derived type
module m_t_x type t_x integer, allocatable :: ints(:) contains procedure :: add end type contains subroutine add(this, val) class(t_x), intent(inout) :: this integer, intent(in) :: val integer, allocatable :: temp(:) integer s if (.not. allocated(this%ints)) then allocate(this%ints(1:1)) this%ints(1) = val else s = size(this%ints) allocate(temp(1:s+1)) temp(1:s) = this%ints temp(s+1) = val call move_alloc(temp, this%ints) endif end subroutine end module
the dll:
subroutine add_dll(x,i) !DEC$ ATTRIBUTES DLLEXPORT :: ADD_DLL use m_t_x type(t_x), intent(inout) :: x integer, intent(in) :: i call x%add(i) end subroutine
and the main program:
program test use m_t_x type(t_x) :: var1, var2, var3, var4 interface subroutine add_dll(x, i) import type(t_x), intent(inout) :: x integer, intent(in) :: i end subroutine end interface print *, "Adding local" call var1%add(1) print *, var1%ints call var1%add(2) print *, var1%ints print *, "Add in dll" call add_dll(var2,1) print *, var2%ints call add_dll(var2,2) print *, var2%ints print *, "Add local first, then in dll" call var3%add(1) print *, var3%ints call add_dll(var3,2) print *, var3%ints ! actually we never get here because the previous crashes print *, "Add in dll first, then local" call add_dll(var4,1) print *, var4%ints call var4%add(1) print *, var4%ints end program
I am running Windows 8.1 and the compiler version is
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 16.0.0.110 Build 20150815
I build the example like this:
ifort mod.f90 /c ifort dll.f90 mod.obj /dll ifort test.f90 mod.obj dll.lib
And when I run it:
C:\TEMP\x>test Adding local 1 1 2 Add in dll 1 1 2 Add local first, then in dll 1 forrtl: severe (157): Program Exception - access violation Image PC Routine Line Source ntdll.dll 00007FFF7E8F6CC9 Unknown Unknown Unknown libifcoremd.dll 00007FFF628478D8 Unknown Unknown Unknown libifcoremd.dll 00007FFF6284AB76 Unknown Unknown Unknown libifcoremd.dll 00007FFF627BBD70 Unknown Unknown Unknown dll.dll 00007FFF7A6A137F Unknown Unknown Unknown dll.dll 00007FFF7A6A10C6 Unknown Unknown Unknown test.exe 00007FF7E8AF1484 Unknown Unknown Unknown test.exe 00007FF7E8B453DE Unknown Unknown Unknown test.exe 00007FF7E8B31224 Unknown Unknown Unknown KERNEL32.DLL 00007FFF7E6516AD Unknown Unknown Unknown ntdll.dll 00007FFF7E9334A5 Unknown Unknown Unknown C:\TEMP\x>
In our real program, the crash in Visual Studio looks like this:
Thanks for any feedback
Johny
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I can reproduce the problem and I think I have a solution. What struck me is that you need mod.obj in the link statement for the program itself. I used gfortran to check if that was behaving in the same way, but that was not the case - and I did not need the second use of mod.obj, as that was already contained in the DLL. IIRC, the GCC compilers export everything by default.
So my solution was to export the subroutine ADD from mod.f90/.obj. And then it works fine. I think the problem is the dual occurrence of the ADD subroutine - there is a copy in the program and in the DLL. But that is just a hunch, it is not based on any deep understanding of what goes on with linking a program and its components.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I can reproduce the problem and I think I have a solution. What struck me is that you need mod.obj in the link statement for the program itself. I used gfortran to check if that was behaving in the same way, but that was not the case - and I did not need the second use of mod.obj, as that was already contained in the DLL. IIRC, the GCC compilers export everything by default.
So my solution was to export the subroutine ADD from mod.f90/.obj. And then it works fine. I think the problem is the dual occurrence of the ADD subroutine - there is a copy in the program and in the DLL. But that is just a hunch, it is not based on any deep understanding of what goes on with linking a program and its components.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Arjen,
A quick test shows that your solution works here also. As we have several types with an "ADD" procedure, I tried a test case with a second type, identical to t_x, just multiplying the values by 2 to make sure the right ADD is called which is what happens.
The only small worry are warnings about the exported procedures:
C:\TEMP\x>ifort mod.f90 /c Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 16.0.0.110 Build 20150815 Copyright (C) 1985-2015 Intel Corporation. All rights reserved. C:\TEMP\x>ifort dll.f90 mod.obj /dll Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 16.0.0.110 Build 20150815 Copyright (C) 1985-2015 Intel Corporation. All rights reserved. ipo: warning #11082: C:\TEMP\x\dll.obj: locally defined symbol __imp_M_T_X_mp_ADD_X imported ipo: warning #11082: C:\TEMP\x\dll.obj: locally defined symbol __imp_M_T_X_mp_ADD_Z imported Microsoft (R) Incremental Linker Version 11.00.61030.0 Copyright (C) Microsoft Corporation. All rights reserved. -out:dll.dll -dll -implib:dll.lib dll.obj mod.obj Creating library dll.lib and object dll.exp LINK : warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs; use /NODEFAULTLIB:library dll.obj : warning LNK4217: locally defined symbol M_T_X_mp_ADD_X imported in function ADD_DLL dll.obj : warning LNK4217: locally defined symbol M_T_X_mp_ADD_Z imported in function ADD_DLL_Z C:\TEMP\x>
I will try your solution on our real project, which involves several complex types.
Many thanks for your very insightful answer
Johny
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Johny,
I hope this works indeed in the larger context too. I have seen such warnings from time to time myself, but I have no idea if they are important or not.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Arjen,
there are about 8 types involved, with all in all about a hundred type bound procedures. It will take me a day or two before I can post back the outcome.
But anyway it will be fun to see what comes out of it :-)
Johny
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@Johny,
See this thread: per Intel and Steve Lionel, "there isn't anything special a DLL":
https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/518615
So a rule of thumb that seems to serve us well is to first check if the problem in question can be reproduced with a typical Fortran program where a validation case is put together in the form a Fortran main program and all the library code that might normally be in DLLs are instead linked directly with the main program. If there is a problem with such a test case, then the issues are most likely in the Fortran code itself; if not, then the issues with the DLL case are usually external to standard Fortran code i,e., they may have to do with compiler options/directives (e.g., missing/invalid/inconsistent use of STDCALL calling convention in the DLL compared to the calling executive) and/or linker configurations (wrong/multiple object files) and so forth.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@FortranFan
That is of course sound advice, and it's what we did to isolate the cause of the problem.
While concerning the pure Fortran part, it is true that there is nothing special to a DLL, it is important to understand the way memory is managed. A DLL has its own heap and all allocations done by code running in the DLL are done from this heap and not from the one of the calling program. I have done a fair lot of programming in C and C++ and the rule is that either the caller or the callee is solely managing allocations and deallocations.
However, I am now doing things in Fortran that involve allocations and deallocations inside type bound procedures and it was not immediately obvious to me that I have to observe the same rule. You learn by your mistakes :-)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Arjen
Putting the shared code in a DLL and exporting all the type bound procedures resolves our memory issues.
Thanks again for your helpful advice.
Johny

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page