[pypy-dev] pytest test_rposix.py with mingw32

bookaa rorsoft at gmail.com
Sat May 26 15:47:31 CEST 2012


keywords: _PyVerify_fd __pioinfo _msize

PyPy can not pass this test:
 pytest.py --cc=mingw32-gcc pypy\rlib\test\test_rposix.py::TestPosixUnicode::()::test_is_valid_fd
After 2 days of hard work, I finally realise why. Patch file attached.

The problem is in _PyVerify_fd:
  FILE* f = fopen("d:\\55.txt","w");
  int no = fileno(f);
  int flg1 = _PyVerify_fd(no);
  fclose(f);
  int flg2 = _PyVerify_fd(no);
  printf("flg1 %d should be 1, flg2 %d should be 0", flg1, flg2)

in file rposix.py, source of function _PyVerify_fd is write to a c file, and will be compile to a Windows
DLL file. In this function, it use 
 extern __declspec(dllimport) char * __pioinfo[];
__pioinfo as a global variable.

I find use __pioinfo in a DLL file is not safe. the __pioinfo and _msize may export from many DLL:
 msvcrt.dll
 msvcr90.dll
 msvcr90d.dll
 or maybe msvcr70.dll ...
If we fopen and fileno in a EXE file, and call _PyVerify_fd in a DLL file, its very danger. The EXE
and DLL may reference different __pioinfo and get error.

So I think test_rposix.py::TestPosixUnicode::()::test_is_valid_fd can pass in MSVC is only a coincidence.
_PyVerify_fd in a DLL and use dllimport __pioinfo is not safe.

In my fix, I do not assume any DLL we should use. I try to find the current DLL which export __pioinfo already
loaded. Sure this is not very good. But I think if we must place _PyVerify_fd in a DLL, no good solution.

After this path, this tests are pass:
 pytest.py --cc=mingw32-gcc pypy\rlib\test\test_rposix.py
 pytest.py pypy\rlib\test\test_rposix.py

-----------

diff -crN pypy-pypy-4a38b43757e3/_pytest/config.py pypy-pypy-4a38b43757e3.bookaa/_pytest/config.py
*** pypy-pypy-4a38b43757e3/_pytest/config.py Tue May 22 14:03:20 2012
--- pypy-pypy-4a38b43757e3.bookaa/_pytest/config.py Sat May 26 20:47:43 2012
***************
*** 157,162 ****
--- 157,164 ----
          for arg in args + [current]:
              if hasattr(arg, 'startswith') and arg.startswith("--"):
                  continue
+             if arg.find('::') != -1:
+                 arg = arg[:arg.find('::')]
              anchor = current.join(arg, abs=1)
              if anchor.check(): # we found some file object
                  self._path2confmods[None] = self.getconftestmodules(anchor)
diff -crN pypy-pypy-4a38b43757e3/pypy/conftest.py pypy-pypy-4a38b43757e3.bookaa/pypy/conftest.py
*** pypy-pypy-4a38b43757e3/pypy/conftest.py Tue May 22 14:03:20 2012
--- pypy-pypy-4a38b43757e3.bookaa/pypy/conftest.py Sat May 26 20:59:51 2012
***************
*** 33,38 ****
--- 33,42 ----
          raise ValueError("%s not in %s" % (value, PLATFORMS))
      set_platform(value, None)
  
+ def _set_compiler(opt, opt_str, value, parser): #add by bookaa
+     from pypy.translator.platform import set_platform
+     set_platform('host', value)
+ 
  def pytest_addoption(parser):
      group = parser.getgroup("pypy options")
      group.addoption('--view', action="store_true", dest="view", default=False,
***************
*** 46,51 ****
--- 50,58 ----
      group.addoption('-P', '--platform', action="callback", type="string",
             default="host", callback=_set_platform,
             help="set up tests to use specified platform as compile/run target")
+     group.addoption('--cc', action="callback", type="string", #add by bookaa
+            default="host", callback=_set_compiler,
+            help="set up tests to use specified compiler")    
      group = parser.getgroup("JIT options")
      group.addoption('--viewloops', action="store_true",
             default=False, dest="viewloops",
diff -crN pypy-pypy-4a38b43757e3/pypy/rlib/rposix.py pypy-pypy-4a38b43757e3.bookaa/pypy/rlib/rposix.py
*** pypy-pypy-4a38b43757e3/pypy/rlib/rposix.py Tue May 22 14:03:20 2012
--- pypy-pypy-4a38b43757e3.bookaa/pypy/rlib/rposix.py Sat May 26 20:51:13 2012
***************
*** 24,34 ****
      separate_module_sources =['''
          /* Lifted completely from CPython 3.3 Modules/posix_module.c */
          #include <malloc.h> /* for _msize */
          typedef struct {
              intptr_t osfhnd;
              char osfile;
          } my_ioinfo;
!         extern __declspec(dllimport) char * __pioinfo[];
          #define IOINFO_L2E 5
          #define IOINFO_ARRAY_ELTS   (1 << IOINFO_L2E)
          #define IOINFO_ARRAYS 64
--- 24,35 ----
      separate_module_sources =['''
          /* Lifted completely from CPython 3.3 Modules/posix_module.c */
          #include <malloc.h> /* for _msize */
+         #include <windows.h>
          typedef struct {
              intptr_t osfhnd;
              char osfile;
          } my_ioinfo;
!         //extern __declspec(dllimport) char * __pioinfo[];
          #define IOINFO_L2E 5
          #define IOINFO_ARRAY_ELTS   (1 << IOINFO_L2E)
          #define IOINFO_ARRAYS 64
***************
*** 36,41 ****
--- 37,58 ----
          #define FOPEN 0x01
          #define _NO_CONSOLE_FILENO (intptr_t)-2
  
+         char** Get_pioinfo(void** pp)
+         {
+           HMODULE hm;
+           hm = GetModuleHandleA("msvcr90.dll");
+           if (hm == 0)
+             hm = GetModuleHandleA("msvcr90d.dll");
+           if (hm == 0)
+             hm = GetModuleHandleA("msvcrt.dll");
+           if (hm)
+           {
+             void * p = GetProcAddress(hm, "__pioinfo");
+             *pp = GetProcAddress(hm, "_msize");
+             return (char**)p;
+           }
+           return 0;
+         }
          /* This function emulates what the windows CRT
              does to validate file handles */
          int
***************
*** 45,56 ****
              const int i2 = fd & ((1 << IOINFO_L2E) - 1);
  
              static size_t sizeof_ioinfo = 0;
  
              /* Determine the actual size of the ioinfo structure,
               * as used by the CRT loaded in memory
               */
              if (sizeof_ioinfo == 0 && __pioinfo[0] != NULL) {
!                 sizeof_ioinfo = _msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS;
              }
              if (sizeof_ioinfo == 0) {
                  /* This should not happen... */
--- 62,77 ----
              const int i2 = fd & ((1 << IOINFO_L2E) - 1);
  
              static size_t sizeof_ioinfo = 0;
+             int (*my_msize)(char*) = 0;
+             char** __pioinfo = Get_pioinfo((void**)&my_msize);
+             if (__pioinfo == 0)
+                 return 0;
  
              /* Determine the actual size of the ioinfo structure,
               * as used by the CRT loaded in memory
               */
              if (sizeof_ioinfo == 0 && __pioinfo[0] != NULL) {
!                 sizeof_ioinfo = my_msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS;
              }
              if (sizeof_ioinfo == 0) {
                  /* This should not happen... */
***************
*** 75,80 ****
--- 96,105 ----
              return 0;
          }
      ''',]
+     from pypy.translator.platform import platform
+     if platform.name == 'mingw32':
+         separate_module_sources[0] = '''#include <stdint.h> /* for intptr_t */
+         ''' + separate_module_sources[0]
      export_symbols = ['_PyVerify_fd']
  else:
      separate_module_sources = []
diff -crN pypy-pypy-4a38b43757e3/pypy/rpython/tool/rfficache.py pypy-pypy-4a38b43757e3.bookaa/pypy/rpython/tool/rfficache.py
*** pypy-pypy-4a38b43757e3/pypy/rpython/tool/rfficache.py Tue May 22 14:03:20 2012
--- pypy-pypy-4a38b43757e3.bookaa/pypy/rpython/tool/rfficache.py Sat May 26 20:47:42 2012
***************
*** 13,19 ****
  from pypy.tool.gcc_cache import build_executable_cache
  
  def ask_gcc(question, add_source=""):
!     includes = ['stdlib.h', 'stdio.h', 'sys/types.h']
      if os.name != 'nt':
          includes += ['inttypes.h']
      include_string = "\n".join(["#include <%s>" % i for i in includes])
--- 13,23 ----
  from pypy.tool.gcc_cache import build_executable_cache
  
  def ask_gcc(question, add_source=""):
!     from pypy.translator.platform import platform
!     if platform.name == 'mingw32':
!         includes = ['stdlib.h', 'stdio.h', 'sys/types.h', 'stdint.h']
!     else:
!         includes = ['stdlib.h', 'stdio.h', 'sys/types.h']
      if os.name != 'nt':
          includes += ['inttypes.h']
      include_string = "\n".join(["#include <%s>" % i for i in includes])
diff -crN pypy-pypy-4a38b43757e3/pypy/translator/platform/posix.py pypy-pypy-4a38b43757e3.bookaa/pypy/translator/platform/posix.py
*** pypy-pypy-4a38b43757e3/pypy/translator/platform/posix.py Tue May 22 14:03:20 2012
--- pypy-pypy-4a38b43757e3.bookaa/pypy/translator/platform/posix.py Sat May 26 20:47:42 2012
***************
*** 55,60 ****
--- 55,62 ----
  
          if relto:
              response_file = relto.bestrelpath(response_file)
+         if self.name == 'mingw32':
+             return ["-Wl,--export-all-symbols,--version-script=%s" % (response_file,)]
          return ["-Wl,--export-dynamic,--version-script=%s" % (response_file,)]
  
      def _link(self, cc, ofiles, link_args, standalone, exe_name):

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/pypy-dev/attachments/20120526/bfe5dd9e/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: bookaa26.dif
Type: application/octet-stream
Size: 7411 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/pypy-dev/attachments/20120526/bfe5dd9e/attachment-0001.obj>


More information about the pypy-dev mailing list