Skip to content

Commit

Permalink
bug mhammond#752 - fix ERROR_BAD_LENGTH in GetFileInformationByHandle…
Browse files Browse the repository at this point in the history
…Ex in x86 builds

When called with FileBasicInfo, GetFileInformationByHandleEx may throw
pywintypes.error(24, 'GetFileInformationByHandleEx',
'The program issued a command but the command length is incorrect.').

With some older SDKs an odd pragma pack(4) directive is issued
in <winsock2.h> before including of <windows.h>:

#if (!defined(_WIN64) && !defined(WIN32))
#include <pshpack4.h>
#endif
...no pragma pack(pop)
#include <windows.h>

If windows.h has not been seen earlier, it gets compiled with non default
alignment. This makes sizeof and layout of some structs incorrect,
including FILE_BASIC_INFO used in GetFileInformationByHandleEx.

Neither distutils nor setup.py defines 'WIN32' so we are affected.

Among SDKs with this quirk are 7.0a, the one that goes
with 'Visual C++ for Python 2.7' and apparently 7.1.
SDK known to be not affected are 8.0 and 8.1 from VS2015-update3,
but pythonwin's setup.py does not seem to support them now.
  • Loading branch information
behemotl authored and mhammond committed Jan 2, 2018
1 parent 46daaec commit 3623bff
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ However contributors are encouraged to add their own entries for their work.

Since build 221:
----------------
* win32file - fix ERROR_BAD_LENGTH in GetFileInformationByHandleEx
in x86 builds(issue #752, rbschk)

* MakeModuleForTypelib no longer catches COM exceptions, so no longer can
return None. This is what the docstring always claimed the behaviour was
and makes things less error prone. If you explicitly call this function and
Expand Down
16 changes: 16 additions & 0 deletions win32/src/win32file.i
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,22 @@
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif

// bug #752
// Include windows.h before winsock2 because with older SDKs the latter may
// include windows.h with wrong pragma pack directive in effect, making
// incorrect sizeof and layout of some WINAPI structs.
// One does not simple include windows.h before winsock2, because windows.h
// pulls old winsock.h (MSDN: for historical reasons) which conflicts with
// winsock2 causing compilation errors.
// To avoid inclusion of winsock.h we define WIN32_LEAN_AND_MEAN macro to
// drop some headers from compilation. We then have to explicitly include ole2
// and windefs affected by the macro.
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#include "ole2.h"
#include "Winefs.h"

#include "winsock2.h"
#include "mswsock.h"
#include "pywintypes.h"
Expand Down
31 changes: 31 additions & 0 deletions win32/test/test_win32file.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,37 @@ def testFileTimes(self):
f.Close()
os.unlink(filename)

class TestGetFileInfoByHandleEx(unittest.TestCase):
__handle = __filename = None
def setUp(self):
fd, self.__filename = tempfile.mkstemp()
os.close(fd)

def tearDown(self):
if self.__handle is not None:
self.__handle.Close()
if self.__filename is not None:
try:
os.unlink(self.__filename)
except OSError:
pass
self.__handle = self.__filename = None

def testFileBasicInfo(self):
attr = win32file.GetFileAttributes(self.__filename)
f = win32file.CreateFile(self.__filename, win32file.GENERIC_READ, 0, None,
win32con.OPEN_EXISTING, 0, None)
self.__handle = f
ct, at, wt = win32file.GetFileTime(f)

# bug #752: this throws ERROR_BAD_LENGTH (24) in x86 binaries of build 221
basic_info = win32file.GetFileInformationByHandleEx(f, win32file.FileBasicInfo)

self.assertEqual(ct, basic_info['CreationTime'])
self.assertEqual(at, basic_info['LastAccessTime'])
self.assertEqual(wt, basic_info['LastWriteTime'])
self.assertEqual(attr, basic_info['FileAttributes'])

class TestOverlapped(unittest.TestCase):
def testSimpleOverlapped(self):
# Create a file in the %TEMP% directory.
Expand Down

0 comments on commit 3623bff

Please sign in to comment.