Menu

#752 ERROR_BAD_LENGTH in winfile.GetFileInformationByHandleEx on x86 - a struct alignment issue.

v1.0 (example)
closed-fixed
nobody
None
5
2018-01-02
2017-06-15
robyschek
No

In latests x86 builds(211), both 2.7 and 3.6, when called with FileBasicInfo, GetFileInformationByHandleEx throws an exeption with winerror code ERROR_BAD_LENGTH:

Python 2.7.13 x86 with latest Pythonwin on windows 7sp1-64:

>>> from win32file import *; from win32con import *
>>> hfile = CreateFile(r'C:\Windows\notepad.exe', GENERIC_READ, FILE_SHARE_READ, None, OPEN_EXISTING, 0, None)
>>> GetFileInformationByHandleEx(hfile, FileBasicInfo)
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
error: (24, 'GetFileInformationByHandleEx', 'The program issued a command but the command length is incorrect.')

The cause of the error is a bug in <winsock2.h> included from win32file.i.
Here's some cl.exe output with /showIncludes switch:

Note: including file: \WinSDK\Include\winsock2.h
Note: including file:  \WinSDK\Include\pshpack4.h << pragma pack(push, 4) here
Note: including file:  \WinSDK\Include\windows.h  << all Windows stuff gets compiled with non default alignment
Note: including file:   \WinSDK\Include\sdkddkver.h
...cut
Note: including file:  \WinSDK\Include\poppack.h

This bug can tracked to 2003, it's present in 7.0a SDK and is fixed already in 8.1.

Struct FILE_BASIC_INFO contains four int64 fields and one int32 so its sizeof by default would be 40 bytes with padding, the odd packing directive decreases its size by omitting padding and GetFileInformationByHandleEx refuses to fill the struct.

The obvious fix would be to just include windows.h before winsock2 but it's not that easy due to conflict between winsock2 and winsock. The second option is to define WIN32 macro before inclusion of winsock2.h but I don't know will it work with all supported SDKs.

I'll attach a patch later today.

Discussion

  • robyschek

    robyschek - 2017-06-15

    Here is a test that reveals the error

     
  • robyschek

    robyschek - 2017-06-15

    fix v1: define WIN32 macro

     

    Last edit: robyschek 2017-06-15
  • robyschek

    robyschek - 2017-06-15

    fix v2: include windows before winsock2, tricky

     

    Last edit: robyschek 2017-06-15
  • Mark Hammond

    Mark Hammond - 2017-06-20

    Thanks for the patch! Note I wont be able to get to this for a couple of weeks (I will before the next release though!), but in the meantime could you please:

    • check we actually need to include winsock.h at all now you have added the windows.h include?
    • add a new entry to changes.txt which is a brief summary of the bug, and giving yourself credit for the fix.
    • upload a single patch with both the fix and the test, so I can commit it exactly as you provide.

    Thanks!

     
  • robyschek

    robyschek - 2017-06-21

    Yes we do need winsock2. Windows.h only pulls winsock.h,
    another beast from early 1990-ties, which does not provide API used in win32file.
    This old winsock also causes multiple redefinition errors when included before winsock2.

    MSDN recommends to just '#include <winsock2.h>' alone as it has been done in this module initially, but if '#include <windows.h>' is required MSDN suggests to define WIN32_LEAN_AND_MEAN to avoid collisions with the old winsock.
    We then have to explicitly include some not so lean headers,
    namely: ole2.h required by pywintypes.h and Winefs.h - NTFS encryption.

    I think WIN32_LEAN_AND_MEAN is the cleanest solution.

    Here is the unified patch

     
  • Mark Hammond

    Mark Hammond - 2018-01-02
    • status: open --> closed-fixed
     
  • Mark Hammond

    Mark Hammond - 2018-01-02

    Sorry for the delay - fixed via https://github.com/mhammond/pywin32/issues/752