Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28442 Discussions

WriteFile /integer_size:64 crash on Win32

Nick2
New Contributor I
752 Views

Using a program like this:

 

      program main
      call crash()
      end program
      
      
      subroutine crash()
      use kernel32
      integer(HANDLE) hFile
      integer(DWORD) iSize
      integer(DWORD) iSizeRW
      integer iTotalSize,iTotalSizeRW
      integer(BOOL) iResult
      
      iTotalSize=78439242
      hFile=0
      iSize = sizeof(iTotalSize)
      iResult = 1
      iSizeRW = iSize
      iResult=WriteFile(hFile,loc(iTotalSize),iSize,loc(iSizeRW),NULL)
      end subroutine
      

With /integer_size:64 (and only on the Win32 platform), and using ifort 2015 Update 4, at the end of subroutine crash(), I get ebp-esp = 4, and the error message:

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

 

So ... what did I mess up now?

0 Kudos
9 Replies
JVanB
Valued Contributor II
750 Views

When I tried your code with version 16.0.0.110 32 bits and /integer_size:64, it ran to completion with iResult = 0 and GetLastError() = 6 because hFile = 0 was an invalid handle. Maybe the version you are using messed up one of the KINDs of the arguments so that it pushed the wrong number of argument bytes onto the stack?

 

0 Kudos
Nick2
New Contributor I
750 Views

It looks like that's what it is.  I looked at the disassembly with 8-byte ints vs 4-byte ints;

00F81046  mov         eax,dword ptr [HFILE]  

00F81049  mov         dword ptr [esp],eax  
00F8104C  lea         eax,[ITOTALSIZE]  
00F8104F  mov         dword ptr [esp+4],eax  
00F81053  mov         eax,dword ptr [ISIZE]  
00F81056  mov         dword ptr [esp+8],eax  
00F8105A  lea         eax,[ISIZERW]  
00F8105D  mov         dword ptr [esp+0Ch],eax  
00F81061  mov         dword ptr [esp+10h],0  
00F81069  mov         dword ptr [esp+14h],0  
00F81071  call        _WriteFile@20 (0F826B0h)  
00F81076  mov         dword ptr [ebp-4],eax  
00F81079  mov         eax,dword ptr [ebp-4]  
00F8107C  mov         dword ptr [IRESULT],eax  

0032103F  mov         eax,dword ptr [HFILE]  
00321042  mov         dword ptr [esp],eax  
00321045  lea         eax,[ITOTALSIZE]  
00321048  mov         dword ptr [esp+4],eax  
0032104C  mov         eax,dword ptr [ISIZE]  
0032104F  mov         dword ptr [esp+8],eax  
00321053  lea         eax,[ISIZERW]  
00321056  mov         dword ptr [esp+0Ch],eax  
0032105A  mov         dword ptr [esp+10h],0  
00321062  call        _WriteFile@20 (0322670h)  
00321067  mov         dword ptr [ebp-4],eax  
0032106A  mov         eax,dword ptr [ebp-4]  
0032106D  mov         dword ptr [IRESULT],eax  

 

I'm really curious if there's a workaround.  I tried:  

      iResult = WriteFile(hFile, loc(iTotalSize), iSize, loc(iSizeRW),
     &                    null_overlapped)

But, because my debug build has /check:pointer, I get this error:

forrtl: severe (408): fort: (7): Attempt to use pointer NULL_OVERLAPPED when it is not associated with a target

0 Kudos
JVanB
Valued Contributor II
750 Views

Kewl! Looks like it may be a bug with /integer_size:64, ALLOW_NULL, and NULL as actual argument. Here is the short form:

module M
   use IFWIN
   use ISO_C_BINDING
   implicit none
   interface
      function f(x)
         import
         implicit none
!DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS: 'f' :: f
         integer(BOOL) f
!DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: x
         type(T_OVERLAPPED) x
      end function f
   end interface
end module M

subroutine S(i)
   use M
   implicit none
   integer i
   i = f(NULL)
end subroutine S

subroutine T(i)
   use M
   implicit none
   integer i
   type(T_OVERLAPPED), pointer :: x
   call C_F_POINTER(C_NULL_PTR,x)
   i = f(x)
end subroutine T

After compiling with ifort /c /FA /integer_size:64 test.f90 we can see the results in test.asm:

_S PROC NEAR 
; parameter 1: 4 + esp
.B2.1:                          ; Preds .B2.0
L2::
                                                           ;17.12
        sub       esp, 8                                        ;17.12
        pxor      xmm0, xmm0                                    ;21.8
        movq      QWORD PTR [esp], xmm0                         ;21.8
        call      _f@4                                          ;21.8
                                ; LOE eax ebx ebp esi edi
.B2.2:                          ; Preds .B2.1
        cdq                                                     ;21.4
        mov       ecx, DWORD PTR [4+esp]                        ;17.12
        movd      xmm1, eax                                     ;21.4
        movd      xmm0, edx                                     ;21.4
        punpckldq xmm1, xmm0                                    ;21.4
        movq      QWORD PTR [ecx], xmm1                         ;21.4
        ret                                                     ;22.1
        ALIGN     16
                                ; LOE
; mark_end;
_S ENDP
_T PROC NEAR 
; parameter 1: 4 + esp
.B3.1:                          ; Preds .B3.0
L3::
                                                           ;24.12
        push      OFFSET FLAT: _T$X.0.3                         ;29.9
        push      OFFSET FLAT: _ISO_C_BINDING_mp_C_NULL_PTR     ;29.9
        call      c_f_pointer_set_scalar                        ;29.9
                                ; LOE ebx ebp esi edi
.B3.6:                          ; Preds .B3.1
        add       esp, 8                                        ;29.9
                                ; LOE ebx ebp esi edi
.B3.2:                          ; Preds .B3.6
        push      DWORD PTR [_T$X.0.3]                          ;30.8
        call      _f@4                                          ;30.8
                                ; LOE eax ebx ebp esi edi
.B3.3:                          ; Preds .B3.2
        cdq                                                     ;30.4
        mov       ecx, DWORD PTR [4+esp]                        ;24.12
        movd      xmm1, eax                                     ;30.4
        movd      xmm0, edx                                     ;30.4
        punpckldq xmm1, xmm0                                    ;30.4
        movq      QWORD PTR [ecx], xmm1                         ;30.4
        ret                                                     ;31.1
        ALIGN     16
                                ; LOE
; mark_end;
_T ENDP

So we can see that when the actual argument was NULL as in subroutine S, the compiler made space for 8 bytes on the stack and filled it with zeros from xmm0.

When the actual argument was a Fortran pointer to TYPE(T_OVERLAPPED) with address of target set to C_NULL_PTR as in subroutine T, it pushed the DWORD address stored in the pointer descriptor (which may be all there is for a pointer to scalar).

So there's your bug reduced to a brief subroutine and a workaround.

 

0 Kudos
Steven_L_Intel1
Employee
750 Views

RO, thanks for the diagnosis and test case! I'll take it from here.

0 Kudos
JVanB
Valued Contributor II
750 Views

I was concerned that my workaround might not work if a pointer to a scalar doesn't contain any information beyond its address. If that's the case, the O.P. may have to provide his own interface body for WriteFile(). So to check, I came up with a test to measure the size of a pointer:

program P
   use IFWIN
   implicit none
   type T
      type(T_OVERLAPPED), pointer :: x
   end type T
!   type T_OVERLAPPED
!      integer x,y,z
!   end type T_OVERLAPPED
   type(T) y
   write(*,*) sizeof(y)
end program P

This got me the error (which I believe to be incorrect):

test1.f90(5): error #6457: This derived type name has not been declared.   [T_OV
ERLAPPED]
      type(T_OVERLAPPED), pointer :: x
-----------^

Now if I uncomment the T_OVERLAPPED derived type definition, I get errors as one might expect, but the error messages are a little funky:

test1.f90(9): error #6401: The attributes of this name conflict with those made
accessible by a USE statement.   [T_OVERLAPPED]
   end type T_OVERLAPPED
------------^
test1.f90(9): error #6148: The name on this END TYPE statement is different from
 the name on the corresponding derived type statement.   [T_OVERLAPPED]
   end type T_OVERLAPPED
------------^

Note that the first error message points at the END TYPE statement instead of the TYPE statement and the second message is just wrong.

Commenting out the USE IFWIN statement at this point allows the compilation to go through as expected, with output 4, indicating that the O.P. may indeed have to rework the interface body. If the lpOverlapped argument is OPTIONAL rather than ALLOW_NULL, will a non-present actual argument pass C_NULL_PTR by value in ifort's implementation?

 

0 Kudos
Steven_L_Intel1
Employee
750 Views

I have escalated the original issue as DPD200381259. I was a bit surprised to find that if I passed 0_4 that the error was still there. 

I think the simple workaround is:

type(T_OVERLAPPED), pointer :: NULL_OVERLAPPED => NULL()

and pass NULL_OVERLAPPED. 

Now to look at the issues in post 6.

0 Kudos
Steven_L_Intel1
Employee
750 Views

Post 6 issues escalated as DPD200381265. If the component isn't a pointer, or if the type is declared as a TYPE rather than a STRUCTURE, it's ok. (T_OVERLAPPED has to be a STRUCTURE because it has a UNION.)

I also reproduced the odd second error, though this may be just a fallout of the first one. I did ask the developers to look at that too.

0 Kudos
Nick2
New Contributor I
750 Views

I ended up declaring my own interface - seems like the simple solution of not having to worry about type definitions for something I'd like to be 0.  I changed use kernel32 to use ifwinty, and:

      INTERFACE

       FUNCTION WriteFile(
     &        hFile,
     &        lpBuffer,
     &        nNumberOfBytesToWrite,
     &        lpNumberOfBytesWritten,
     &        lpOverlapped)
       import
        integer(BOOL) :: WriteFile ! BOOL
        !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE :: WriteFile
        !DEC$ ATTRIBUTES ALIAS:'WriteFile' :: WriteFile
        integer(HANDLE) hFile ! HANDLE hFile
        integer(LPCVOID) lpBuffer ! LPCVOID lpBuffer
        integer(DWORD) nNumberOfBytesToWrite ! DWORD nNumberOfBytesToWrite
        integer(LPDWORD) lpNumberOfBytesWritten !LPDWORD lpNumberOfBytesWritten
        integer(INT_PTR_KIND()) lpOverlapped ! LPOVERLAPPED lpOverlapped
       END FUNCTION
C
      FUNCTION ReadFile(
     &        hFile,
     &        lpBuffer,
     &        nNumberOfBytesToRead,
     &        lpNumberOfBytesRead,
     &        lpOverlapped)
       import
        integer(BOOL) :: ReadFile ! BOOL
        !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE :: ReadFile
        !DEC$ ATTRIBUTES ALIAS:'ReadFile' :: ReadFile
        integer(HANDLE) hFile ! HANDLE hFile
        integer(LPVOID) lpBuffer ! LPVOID lpBuffer
        integer(DWORD) nNumberOfBytesToRead ! DWORD nNumberOfBytesToRead
        integer(LPDWORD) lpNumberOfBytesRead ! LPDWORD lpNumberOfBytesRead
        integer(INT_PTR_KIND()) lpOverlapped ! LPOVERLAPPED lpOverlapped
       END FUNCTION
      END INTERFACE

0 Kudos
Steven_L_Intel1
Employee
750 Views

The post 6 error is fixed for a major version later this year.

0 Kudos
Reply