1+ import _ctypes
12import os
3+ import platform
24import sys
5+ import test .support
36import unittest
4- import platform
7+ from ctypes import CDLL , c_int
8+ from ctypes .util import find_library
9+
510
611FOO_C = r"""
712#include <unistd.h>
2631
2732
2833@unittest .skipUnless (sys .platform .startswith ('linux' ),
29- 'Test only valid for Linux ' )
34+ 'test requires GNU IFUNC support ' )
3035class TestNullDlsym (unittest .TestCase ):
3136 """GH-126554: Ensure that we catch NULL dlsym return values
3237
@@ -53,14 +58,6 @@ def test_null_dlsym(self):
5358 import subprocess
5459 import tempfile
5560
56- # To avoid ImportErrors on Windows, where _ctypes does not have
57- # dlopen and dlsym,
58- # import here, i.e., inside the test function.
59- # The skipUnless('linux') decorator ensures that we're on linux
60- # if we're executing these statements.
61- from ctypes import CDLL , c_int
62- from _ctypes import dlopen , dlsym
63-
6461 retcode = subprocess .call (["gcc" , "--version" ],
6562 stdout = subprocess .DEVNULL ,
6663 stderr = subprocess .DEVNULL )
@@ -111,6 +108,8 @@ def test_null_dlsym(self):
111108 self .assertEqual (os .read (pipe_r , 2 ), b'OK' )
112109
113110 # Case #3: Test 'py_dl_sym' from Modules/_ctypes/callproc.c
111+ dlopen = test .support .get_attribute (_ctypes , 'dlopen' )
112+ dlsym = test .support .get_attribute (_ctypes , 'dlsym' )
114113 L = dlopen (dstname )
115114 with self .assertRaisesRegex (OSError , "symbol 'foo' not found" ):
116115 dlsym (L , "foo" )
@@ -119,5 +118,66 @@ def test_null_dlsym(self):
119118 self .assertEqual (os .read (pipe_r , 2 ), b'OK' )
120119
121120
121+ @unittest .skipUnless (os .name != 'nt' , 'test requires dlerror() calls' )
122+ class TestLocalization (unittest .TestCase ):
123+
124+ @staticmethod
125+ def configure_locales (func ):
126+ return test .support .run_with_locale (
127+ 'LC_ALL' ,
128+ 'fr_FR.iso88591' , 'ja_JP.sjis' , 'zh_CN.gbk' ,
129+ 'fr_FR.utf8' , 'en_US.utf8' ,
130+ '' ,
131+ )(func )
132+
133+ @classmethod
134+ def setUpClass (cls ):
135+ cls .libc_filename = find_library ("c" )
136+
137+ @configure_locales
138+ def test_localized_error_from_dll (self ):
139+ dll = CDLL (self .libc_filename )
140+ with self .assertRaises (AttributeError ) as cm :
141+ dll .this_name_does_not_exist
142+ if sys .platform .startswith ('linux' ):
143+ # On macOS, the filename is not reported by dlerror().
144+ self .assertIn (self .libc_filename , str (cm .exception ))
145+
146+ @configure_locales
147+ def test_localized_error_in_dll (self ):
148+ dll = CDLL (self .libc_filename )
149+ with self .assertRaises (ValueError ) as cm :
150+ c_int .in_dll (dll , 'this_name_does_not_exist' )
151+ if sys .platform .startswith ('linux' ):
152+ # On macOS, the filename is not reported by dlerror().
153+ self .assertIn (self .libc_filename , str (cm .exception ))
154+
155+ @unittest .skipUnless (hasattr (_ctypes , 'dlopen' ),
156+ 'test requires _ctypes.dlopen()' )
157+ @configure_locales
158+ def test_localized_error_dlopen (self ):
159+ missing_filename = b'missing\xff .so'
160+ # Depending whether the locale, we may encode '\xff' differently
161+ # but we are only interested in avoiding a UnicodeDecodeError
162+ # when reporting the dlerror() error message which contains
163+ # the localized filename.
164+ filename_pattern = r'missing.*?\.so'
165+ with self .assertRaisesRegex (OSError , filename_pattern ):
166+ _ctypes .dlopen (missing_filename , 2 )
167+
168+ @unittest .skipUnless (hasattr (_ctypes , 'dlopen' ),
169+ 'test requires _ctypes.dlopen()' )
170+ @unittest .skipUnless (hasattr (_ctypes , 'dlsym' ),
171+ 'test requires _ctypes.dlsym()' )
172+ @configure_locales
173+ def test_localized_error_dlsym (self ):
174+ dll = _ctypes .dlopen (self .libc_filename )
175+ with self .assertRaises (OSError ) as cm :
176+ _ctypes .dlsym (dll , 'this_name_does_not_exist' )
177+ if sys .platform .startswith ('linux' ):
178+ # On macOS, the filename is not reported by dlerror().
179+ self .assertIn (self .libc_filename , str (cm .exception ))
180+
181+
122182if __name__ == "__main__" :
123183 unittest .main ()
0 commit comments