This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Title: ctypes.util.find_library can delete /dev/null
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.10
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: barry.c.davis
Priority: normal Keywords:

Created on 2022-03-08 14:58 by barry.c.davis, last changed 2022-04-11 14:59 by admin.

Messages (1)
msg414756 - (view) Author: Barry Davis (barry.c.davis) Date: 2022-03-08 14:58
This bug exists again:

In ctypes/util we defend against gcc removing /dev/null by using a temp file, but similar code for ld still uses /dev/null, resulting in it removing /dev/null if it has permission, i.e. if running as root.

Reproduction steps in the original bug still work I think.

I found this when running pyinstaller.
I slimmed the test case down to:
 import ctypes.util
 libname = ctypes.util.find_library("ApplicationServices")

Here's my patch (indentation is wrong to just show the actual change needed):

--- Python-3.10.2/Lib/ctypes/    2022-03-08 14:34:52.188808751 +0000
+++ Python-3.10.2/Lib/ctypes/    2022-03-08 14:40:23.604615242 +0000
@@ -305,9 +305,11 @@
             if libpath:
                 for d in libpath.split(':'):
                     cmd.extend(['-L', d])
-            cmd.extend(['-o', os.devnull, '-l%s' % name])
-            result = None
+            temp = tempfile.NamedTemporaryFile()
+              cmd.extend(['-o',, '-l%s' % name])
+              result = None
+              try:
                 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
@@ -320,8 +322,15 @@
                     if not _is_elf(file):
                     return os.fsdecode(file)
-            except Exception:
+              except Exception:
                 pass  # result will be None
+            finally:
+                try:
+                    temp.close()
+                except FileNotFoundError:
+                    # Raised if the file was already removed, which is the normal
+                    # behaviour if linking fails
+                    pass
             return result

         def find_library(name):
Date User Action Args
2022-04-11 14:59:57adminsetgithub: 91115
2022-03-08 14:58:43barry.c.daviscreate