• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from ctypes import *
2import os
3import shutil
4import subprocess
5import sys
6import unittest
7import test.support
8from test.support import import_helper
9from test.support import os_helper
10from ctypes.util import find_library
11
12libc_name = None
13
14def setUpModule():
15    global libc_name
16    if os.name == "nt":
17        libc_name = find_library("c")
18    elif sys.platform == "cygwin":
19        libc_name = "cygwin1.dll"
20    else:
21        libc_name = find_library("c")
22
23    if test.support.verbose:
24        print("libc_name is", libc_name)
25
26class LoaderTest(unittest.TestCase):
27
28    unknowndll = "xxrandomnamexx"
29
30    def test_load(self):
31        if libc_name is None:
32            self.skipTest('could not find libc')
33        CDLL(libc_name)
34        CDLL(os.path.basename(libc_name))
35        self.assertRaises(OSError, CDLL, self.unknowndll)
36
37    def test_load_version(self):
38        if libc_name is None:
39            self.skipTest('could not find libc')
40        if os.path.basename(libc_name) != 'libc.so.6':
41            self.skipTest('wrong libc path for test')
42        cdll.LoadLibrary("libc.so.6")
43        # linux uses version, libc 9 should not exist
44        self.assertRaises(OSError, cdll.LoadLibrary, "libc.so.9")
45        self.assertRaises(OSError, cdll.LoadLibrary, self.unknowndll)
46
47    def test_find(self):
48        for name in ("c", "m"):
49            lib = find_library(name)
50            if lib:
51                cdll.LoadLibrary(lib)
52                CDLL(lib)
53
54    @unittest.skipUnless(os.name == "nt",
55                         'test specific to Windows')
56    def test_load_library(self):
57        # CRT is no longer directly loadable. See issue23606 for the
58        # discussion about alternative approaches.
59        #self.assertIsNotNone(libc_name)
60        if test.support.verbose:
61            print(find_library("kernel32"))
62            print(find_library("user32"))
63
64        if os.name == "nt":
65            windll.kernel32.GetModuleHandleW
66            windll["kernel32"].GetModuleHandleW
67            windll.LoadLibrary("kernel32").GetModuleHandleW
68            WinDLL("kernel32").GetModuleHandleW
69            # embedded null character
70            self.assertRaises(ValueError, windll.LoadLibrary, "kernel32\0")
71
72    @unittest.skipUnless(os.name == "nt",
73                         'test specific to Windows')
74    def test_load_ordinal_functions(self):
75        import _ctypes_test
76        dll = WinDLL(_ctypes_test.__file__)
77        # We load the same function both via ordinal and name
78        func_ord = dll[2]
79        func_name = dll.GetString
80        # addressof gets the address where the function pointer is stored
81        a_ord = addressof(func_ord)
82        a_name = addressof(func_name)
83        f_ord_addr = c_void_p.from_address(a_ord).value
84        f_name_addr = c_void_p.from_address(a_name).value
85        self.assertEqual(hex(f_ord_addr), hex(f_name_addr))
86
87        self.assertRaises(AttributeError, dll.__getitem__, 1234)
88
89    @unittest.skipUnless(os.name == "nt", 'Windows-specific test')
90    def test_1703286_A(self):
91        from _ctypes import LoadLibrary, FreeLibrary
92        # On winXP 64-bit, advapi32 loads at an address that does
93        # NOT fit into a 32-bit integer.  FreeLibrary must be able
94        # to accept this address.
95
96        # These are tests for https://www.python.org/sf/1703286
97        handle = LoadLibrary("advapi32")
98        FreeLibrary(handle)
99
100    @unittest.skipUnless(os.name == "nt", 'Windows-specific test')
101    def test_1703286_B(self):
102        # Since on winXP 64-bit advapi32 loads like described
103        # above, the (arbitrarily selected) CloseEventLog function
104        # also has a high address.  'call_function' should accept
105        # addresses so large.
106        from _ctypes import call_function
107        advapi32 = windll.advapi32
108        # Calling CloseEventLog with a NULL argument should fail,
109        # but the call should not segfault or so.
110        self.assertEqual(0, advapi32.CloseEventLog(None))
111        windll.kernel32.GetProcAddress.argtypes = c_void_p, c_char_p
112        windll.kernel32.GetProcAddress.restype = c_void_p
113        proc = windll.kernel32.GetProcAddress(advapi32._handle,
114                                              b"CloseEventLog")
115        self.assertTrue(proc)
116        # This is the real test: call the function via 'call_function'
117        self.assertEqual(0, call_function(proc, (None,)))
118
119    @unittest.skipUnless(os.name == "nt",
120                         'test specific to Windows')
121    def test_load_dll_with_flags(self):
122        _sqlite3 = import_helper.import_module("_sqlite3")
123        src = _sqlite3.__file__
124        if src.lower().endswith("_d.pyd"):
125            ext = "_d.dll"
126        else:
127            ext = ".dll"
128
129        with os_helper.temp_dir() as tmp:
130            # We copy two files and load _sqlite3.dll (formerly .pyd),
131            # which has a dependency on sqlite3.dll. Then we test
132            # loading it in subprocesses to avoid it starting in memory
133            # for each test.
134            target = os.path.join(tmp, "_sqlite3.dll")
135            shutil.copy(src, target)
136            shutil.copy(os.path.join(os.path.dirname(src), "sqlite3" + ext),
137                        os.path.join(tmp, "sqlite3" + ext))
138
139            def should_pass(command):
140                with self.subTest(command):
141                    subprocess.check_output(
142                        [sys.executable, "-c",
143                         "from ctypes import *; import nt;" + command],
144                        cwd=tmp
145                    )
146
147            def should_fail(command):
148                with self.subTest(command):
149                    with self.assertRaises(subprocess.CalledProcessError):
150                        subprocess.check_output(
151                            [sys.executable, "-c",
152                             "from ctypes import *; import nt;" + command],
153                            cwd=tmp, stderr=subprocess.STDOUT,
154                        )
155
156            # Default load should not find this in CWD
157            should_fail("WinDLL('_sqlite3.dll')")
158
159            # Relative path (but not just filename) should succeed
160            should_pass("WinDLL('./_sqlite3.dll')")
161
162            # Insecure load flags should succeed
163            # Clear the DLL directory to avoid safe search settings propagating
164            should_pass("windll.kernel32.SetDllDirectoryW(None); WinDLL('_sqlite3.dll', winmode=0)")
165
166            # Full path load without DLL_LOAD_DIR shouldn't find dependency
167            should_fail("WinDLL(nt._getfullpathname('_sqlite3.dll'), " +
168                        "winmode=nt._LOAD_LIBRARY_SEARCH_SYSTEM32)")
169
170            # Full path load with DLL_LOAD_DIR should succeed
171            should_pass("WinDLL(nt._getfullpathname('_sqlite3.dll'), " +
172                        "winmode=nt._LOAD_LIBRARY_SEARCH_SYSTEM32|" +
173                        "nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)")
174
175            # User-specified directory should succeed
176            should_pass("import os; p = os.add_dll_directory(os.getcwd());" +
177                        "WinDLL('_sqlite3.dll'); p.close()")
178
179
180
181if __name__ == "__main__":
182    unittest.main()
183