- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I was playing around with polymorphic types in Fortran, and I seem to have stumbled over a potential bug in the Intel Fortran compiler. Compilation with GNU gfortran compiler yields the expected results, while ifort produces an odd trace. I am using polymorphism to allocate a general type depending on the source object (which has a type extending the general type), and then returning that newly allocated object as the function result. It looks like, the object does not survive the end of the function.
The respective compiler versions are:
% gfortran -v gcc version 4.9.2 (GCC) % icc -v icc version 15.0.0 (gcc version 4.9.0 compatibility)
Here are the respective results for ifort and gfortran:
% gfortran -c parameter-minimal.f90 % gfortran -o polymorphic-minimal{,.f90} parameter-minimal.o % ./polymorphic-minimal 2.00000000 2.00000000
% ifort -standard-semantics -c parameter-minimal.f90 % ifort -standard-semantics -o polymorphic-minimal{,.f90} parameter-minimal.o % ./polymorphic-minimal 2.000000 forrtl: severe (71): integer divide by zero Image PC Routine Line Source polymorphic-minim 000000000047A621 Unknown Unknown Unknown polymorphic-minim 0000000000478D77 Unknown Unknown Unknown polymorphic-minim 000000000042C994 Unknown Unknown Unknown polymorphic-minim 000000000042C7A6 Unknown Unknown Unknown polymorphic-minim 000000000040BB5F Unknown Unknown Unknown polymorphic-minim 00000000004111BF Unknown Unknown Unknown libpthread.so.0 00007F4CAD642200 Unknown Unknown Unknown Unknown 00007FFF55107B48 Unknown Unknown Unknown zsh: exit 71 ./polymorphic-minimal
Here is the MWE of the program; the main file:
program polymorphic use parameter_minimal implicit none class(generic_evaluator), allocatable :: evaluator allocate(evaluator, source=return_eval_type()) print *, evaluator%eval(1.0) contains function return_eval_type() result(evaluator) !{{{ class(generic_evaluator), allocatable :: evaluator type(function_evaluator) :: function_type function_type%f_ptr => linear allocate(evaluator, source=function_type) print *, evaluator%eval(1.0) end function return_eval_type !}}} real pure function linear(x) result(y) !{{{ real, intent(in) :: x y = 1 + x end function linear !}}} end program polymorphic
And the module file:
module parameter_minimal implicit none private public generic_evaluator, function_evaluator type, abstract :: generic_evaluator contains procedure(eval_with), deferred, pass :: eval end type generic_evaluator abstract interface real pure function generic_func(x) result(y) real, intent(in) :: x end function generic_func real function eval_with(this,x) result(y) import generic_evaluator class(generic_evaluator), intent(in) :: this real,intent(in) :: x end function eval_with end interface type, extends(generic_evaluator) :: function_evaluator !{{{ procedure(generic_func), pointer, nopass :: f_ptr contains procedure :: eval => eval_with_function end type function_evaluator !}}} contains real function eval_with_function(this,x) result(y) !{{{ class(function_evaluator), intent(in) :: this !procedure(generic_func) :: f real, intent(in) :: x y = this%f_ptr(x) end function eval_with_function !}}} end module parameter_minimal
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I made a slight mistake above (why can't I edit my post??); the error actually had error code 174 (also, it seems to be changing from time to time; I saw 71, 168 and 174 so far).
forrtl: severe (174): SIGSEGV, segmentation fault occurred Image PC Routine Line Source polymorphic-minim 000000000047A4E1 Unknown Unknown Unknown polymorphic-minim 0000000000478C37 Unknown Unknown Unknown polymorphic-minim 000000000042C854 Unknown Unknown Unknown polymorphic-minim 000000000042C666 Unknown Unknown Unknown polymorphic-minim 000000000040BA1F Unknown Unknown Unknown polymorphic-minim 000000000041087D Unknown Unknown Unknown libpthread.so.0 00007F9A9491B200 Unknown Unknown Unknown Unknown 00007FFF2BEC3567 Unknown Unknown Unknown
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You may want to track down the requirements and restrictions around internal procedures as procedure pointers, especially in the Fortran 2008 standard. I vaguely remember running into something very similar to this and finding the code worked in Intel Fortran when the function pointed to by the procedure pointer is not an internal procedure. Not saying there isn't a bug somewhere or there shouldn't be better diagnostics, but could this be a workaround?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Amazing! How do you even get the idea of putting that into an extra module to check if that might be the problem?
To understand you correctly: you assume that the problem essentially is the pointer to the function “linear” contained in my program block above, correct? Indeed, simply moving the function to that module imported in the first line already fixes the issue.
I punched some of these keywords into Google and got this as a result:
According to that post, at least the Intel Visual Fortran compiler has supported that Fortran 2008 feature since 2012.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
"To understand you correctly: you assume that the problem essentially is the pointer to the function “linear” contained in my program block above, correct? Indeed, simply moving the function to that module imported in the first line already fixes the issue."
- yes, that's exactly what I meant. So is that an acceptable workaround for you?
Some of my derived types have constructs somewhat similar to yours and I recall one of my unit tests having an internal procedure pointee which got flagged as invalid per Fortran 2008 standard and had problems.
Yes, even though Intel Fortran is not fully compliant yet with 2008 standard, it has been incrementally getting 2008 features added to it and I like that - a lot of our work wouldn't have taken place in Fortran but for this. I can't wait for the day Intel Fortran supports all of the 2008 standard as well as the advanced interoperability features from the next standard (2015?).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think you need to read Doctor Fortran in "Think, Thank, Thunk" While your situation is expressed differently, it's the same problem. Yes, you can assign an internal procedure to a procedure pointer, but once you return from the host procedure, that pointer becomes invalid. Whether or not it works depends on how memory is laid out and gets reused.
FWIW, we've supported internal procedures as arguments and pointers for a long, long time.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
So this is working as intended? I am not sure I exactly grok the article...
For my own understanding: what is the qualitative difference between having an internal procedure as compared to one in a module? Do all variables/procedures from the module stay in scope?
If I understood that part correctly, the pointer is losing its reference the moment the functions ends. But why is that exactly? The host function, within which the pointer is assigned, does not have an internal procedure itself. It makes the pointer point to a procedure contained in the host (in my mind, they are on the same “level”).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
An internal procedure has context of its containing procedure that is valid only as long as the call to the containing procedure is active. A module procedure has static context so there is no issue about going out of scope.
I may have misinterpreted what your program is doing. I'll look at it closer next week.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, I just tried this in the 15.0 compiler and it works correctly. I can't make it fail.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
That is odd. :/ In my case, I can make it always fails as long as the function pointed to is contained in the main program. Moving the function to the external module will fix it. Any ideas what else I could look at?
I have changed the class of the allocated object to the type of the source object, see below (the module is kept the same); it looks like the compiler believes that the pointer in the allocated, polymorphic object is indeed associated with something, but it will still fail to actually call the function (I have dropped the -standard-semantics flag here and also when compiling the module):
% ifort -o polymorphic-minimal polymorphic-minimal.f90 parameter-minimal.o % ./polymorphic-minimal 2.000000 T forrtl: severe (168): Program Exception - illegal instruction Image PC Routine Line Source polymorphic-minim 000000000047A531 Unknown Unknown Unknown polymorphic-minim 0000000000478C87 Unknown Unknown Unknown polymorphic-minim 000000000042C8A4 Unknown Unknown Unknown polymorphic-minim 000000000042C6B6 Unknown Unknown Unknown polymorphic-minim 000000000040BA6F Unknown Unknown Unknown polymorphic-minim 0000000000411121 Unknown Unknown Unknown libpthread.so.0 00007F90D9105200 Unknown Unknown Unknown Unknown 00007FFFF84AE6DC Unknown Unknown Unknown zsh: exit 168 ./polymorphic-minimal
program polymorphic use parameter_minimal implicit none !class(generic_evaluator), allocatable :: evaluator class(function_evaluator), allocatable :: evaluator allocate(evaluator, source=return_eval_type()) print *, associated(evaluator%f_ptr) print *, evaluator%eval(1.0) contains function return_eval_type() result(evaluator) !{{{ !class(generic_evaluator), allocatable :: evaluator class(function_evaluator), allocatable :: evaluator type(function_evaluator) :: function_type function_type%f_ptr => linear allocate(evaluator, source=function_type) print *, evaluator%eval(1.0) end function return_eval_type !}}} real pure function linear(x) result(y) !{{{ real, intent(in) :: x y = 1 + x end function linear !}}} end program polymorphic
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Please show the result of ifort -logo You didn't show us the ifort version (just the icc version).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Was a bit late and didn't realize I posted icc instead of ifort. Here is the info you asked for
% ifort -logo Intel(R) Fortran Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 15.0 Build 20140723 Copyright (C) 1985-2014 Intel Corporation. All rights reserved. FOR NON-COMMERCIAL USE ONLY
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, thanks. I'll see what I can figure out.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, now that I'm back in the office I can look at this more closely.
I can now reproduce the error, though it is elusive. My guess is that my earlier reference to thunks is still relevant, though I don't yet see that you're doing anything wrong. I'd be more comfortable if "linear" was an external procedure rather than an internal procedure of the main program.
I'll pass this on to the developers for them to take a look. Issue ID is DPD200363031.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve Lionel (Intel) wrote:
... I'd be more comfortable if "linear" was an external procedure rather than an internal procedure of the main program.
..
Steve,
Also, do you think Intel Fortran is correct in its warning that Fortran 2008 standard disallows an procedure pointer target to be an internal procedure: [plain]warning #8266: Standard F2008 does not allow an internal procedure to be a procedure target. [LINEAR][/plain]. I've not had the chance to look this up, but you can better comment on this aspect in the 2008 standard and its relevance to the code by OP.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The warning is wrong. F2008 says (in discussing pointer assignment):
"C729 (R740) A procedure-name shall be the name of an internal, module, or dummy procedure, a procedure pointer, a specific intrinsic function listed in 13.6 and not marked with a bullet, or an external procedure that is accessed by use or host association, referenced in the scoping unit as a procedure or that has the EXTERNAL attribute." (Text modified by interpretation F08/0060). I will report this to the developers. Issue ID is DPD200363033.

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