Skip to content

Replace Python's deprecated tempfile.mktemp() with secure temp APIs#210123

Merged
vitalybuka merged 2 commits into
llvm:mainfrom
ZacharyHenkel:replace-deprecated-mktemp
Jul 17, 2026
Merged

Replace Python's deprecated tempfile.mktemp() with secure temp APIs#210123
vitalybuka merged 2 commits into
llvm:mainfrom
ZacharyHenkel:replace-deprecated-mktemp

Conversation

@ZacharyHenkel

Copy link
Copy Markdown
Contributor

Python's tempfile.mktemp() is deprecated and insecure: it returns a path without creating the file, leaving a TOCTOU/symlink window before the file is opened. Replace every use, choosing the temp API by lifetime:

  • compiler-rt android_common.py adb(): tempfile.TemporaryFile (anonymous, auto-deleted), read back via seek(0); drops manual close()/unlink().
  • compiler-rt android_common.py pull_from_device(): tempfile.TemporaryDirectory so "adb pull" writes into a private, auto-cleaned directory.
  • lldb examples delta.py / gdbremote.py start_gdb_log(): tempfile.NamedTemporaryFile(delete=False); the log must outlive the call for a later stop_gdb_log, so it is intentionally not auto-deleted.

Reported by internal static analysis and contributed upstream for the benefit of the wider community.

Assisted-by: GitHub Copilot CLI (Claude Opus 4.8)

I do not have commit access and will need someone to submit on my behalf.

…temp APIs

tempfile.mktemp() is deprecated and insecure: it returns a path without
creating the file, leaving a TOCTOU/symlink window before the file is
opened. Replace every use, choosing the temp API by lifetime:

- compiler-rt android_common.py adb(): tempfile.TemporaryFile (anonymous,
  auto-deleted), read back via seek(0); drops manual close()/unlink().
- compiler-rt android_common.py pull_from_device():
  tempfile.TemporaryDirectory so "adb pull" writes into a private,
  auto-cleaned directory.
- lldb examples delta.py / gdbremote.py start_gdb_log():
  tempfile.NamedTemporaryFile(delete=False); the log must outlive the
  call for a later stop_gdb_log, so it is intentionally not auto-deleted.

Reported by internal static analysis and contributed upstream for the
benefit of the wider community.

Assisted-by: GitHub Copilot CLI (Claude Opus 4.8)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0261dfbe-a4a8-4868-a4a8-2ca5b15c33e8
@llvmorg-github-actions

llvmorg-github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown

@llvm/pr-subscribers-lldb

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Zachary Henkel (ZacharyHenkel)

Changes

Python's tempfile.mktemp() is deprecated and insecure: it returns a path without creating the file, leaving a TOCTOU/symlink window before the file is opened. Replace every use, choosing the temp API by lifetime:

  • compiler-rt android_common.py adb(): tempfile.TemporaryFile (anonymous, auto-deleted), read back via seek(0); drops manual close()/unlink().
  • compiler-rt android_common.py pull_from_device(): tempfile.TemporaryDirectory so "adb pull" writes into a private, auto-cleaned directory.
  • lldb examples delta.py / gdbremote.py start_gdb_log(): tempfile.NamedTemporaryFile(delete=False); the log must outlive the call for a later stop_gdb_log, so it is intentionally not auto-deleted.

Reported by internal static analysis and contributed upstream for the benefit of the wider community.

Assisted-by: GitHub Copilot CLI (Claude Opus 4.8)

I do not have commit access and will need someone to submit on my behalf.


Full diff: https://github.com/llvm/llvm-project/pull/210123.diff

3 Files Affected:

  • (modified) compiler-rt/test/sanitizer_common/android_commands/android_common.py (+18-23)
  • (modified) lldb/examples/python/delta.py (+2-1)
  • (modified) lldb/examples/python/gdbremote.py (+2-1)
diff --git a/compiler-rt/test/sanitizer_common/android_commands/android_common.py b/compiler-rt/test/sanitizer_common/android_commands/android_common.py
index 4e7d15c9ebc23..6c7c410108a74 100644
--- a/compiler-rt/test/sanitizer_common/android_commands/android_common.py
+++ b/compiler-rt/test/sanitizer_common/android_commands/android_common.py
@@ -18,33 +18,28 @@ def host_to_device_path(path):
 def adb(args, attempts=1, timeout_sec=600):
     if verbose:
         print(args)
-    tmpname = tempfile.mktemp()
-    out = open(tmpname, "w")
-    ret = 255
-    while attempts > 0 and ret != 0:
-        attempts -= 1
-        ret = subprocess.call(
-            ["timeout", str(timeout_sec), ADB] + args,
-            stdout=out,
-            stderr=subprocess.STDOUT,
-        )
-    if ret != 0:
-        print("adb command failed", args)
-        print(tmpname)
-        out.close()
-        out = open(tmpname, "r")
-        print(out.read())
-    out.close()
-    os.unlink(tmpname)
+    with tempfile.TemporaryFile(mode="w+") as out:
+        ret = 255
+        while attempts > 0 and ret != 0:
+            attempts -= 1
+            ret = subprocess.call(
+                ["timeout", str(timeout_sec), ADB] + args,
+                stdout=out,
+                stderr=subprocess.STDOUT,
+            )
+        if ret != 0:
+            print("adb command failed", args)
+            out.seek(0)
+            print(out.read())
     return ret
 
 
 def pull_from_device(path):
-    tmp = tempfile.mktemp()
-    adb(["pull", path, tmp], 5, 60)
-    text = open(tmp, "r").read()
-    os.unlink(tmp)
-    return text
+    with tempfile.TemporaryDirectory() as tmp_dir:
+        tmp = os.path.join(tmp_dir, "pulled")
+        adb(["pull", path, tmp], 5, 60)
+        with open(tmp, "r") as f:
+            return f.read()
 
 
 def push_to_device(path):
diff --git a/lldb/examples/python/delta.py b/lldb/examples/python/delta.py
old mode 100755
new mode 100644
index 35f155bdea100..e84185b1ae05a
--- a/lldb/examples/python/delta.py
+++ b/lldb/examples/python/delta.py
@@ -35,7 +35,8 @@ def start_gdb_log(debugger, command, result, dict):
     else:
         args_len = len(args)
         if args_len == 0:
-            log_file = tempfile.mktemp()
+            with tempfile.NamedTemporaryFile(delete=False) as tmp:
+                log_file = tmp.name
         elif len(args) == 1:
             log_file = args[0]
 
diff --git a/lldb/examples/python/gdbremote.py b/lldb/examples/python/gdbremote.py
old mode 100755
new mode 100644
index 2f2d82c3d3d54..a215a878ef0a0
--- a/lldb/examples/python/gdbremote.py
+++ b/lldb/examples/python/gdbremote.py
@@ -229,7 +229,8 @@ def start_gdb_log(debugger, command, result, dict):
     else:
         args_len = len(args)
         if args_len == 0:
-            g_log_file = tempfile.mktemp()
+            with tempfile.NamedTemporaryFile(delete=False) as tmp:
+                g_log_file = tmp.name
         elif len(args) == 1:
             g_log_file = args[0]
 

args_len = len(args)
if args_len == 0:
log_file = tempfile.mktemp()
with tempfile.NamedTemporaryFile(delete=False) as tmp:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lldb and compiler-rt could be 2 independent PRs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the only two usages of mktemp in the whole llvm tree so bundling the fixes felt appropriate. If required, I can split the changes into 2 PRs.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If one of this cases is incorrect, unlikely it will apply to the rest of the patch. So I slightly prefer to keep them separate for convenience of revert. And I see no benefits of keeping them together.

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown

🐧 Linux x64 Test Results

  • 41312 tests passed
  • 1824 tests skipped

✅ The build succeeded and all tests passed.

@vitalybuka

Copy link
Copy Markdown
Contributor

🐧 Linux x64 Test Results

  • 34085 tests passed
  • 506 tests skipped
  • 1 test failed

Failed Tests

(click on a test name to see its output)

lldb-api

lldb-api.python_api/run_locker/TestRunLocker.py

Script:
--
/usr/bin/python3 /home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/./lib --env LLVM_INCLUDE_DIR=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include --env LLVM_TOOLS_DIR=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin --libcxx-include-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/include/c++/v1 --libcxx-include-target-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/include/x86_64-unknown-linux-gnu/c++/v1 --libcxx-library-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./lib/x86_64-unknown-linux-gnu --triple x86_64-unknown-linux-gnu --build-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build --lldb-module-cache-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build/module-cache-lldb/lldb-api --clang-module-cache-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build/module-cache-clang/lldb-api --executable /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin/lldb --lldb-python-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/local/lib/python3.12/dist-packages --compiler /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin/clang --dsymutil /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin --lldb-obj-root /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/lldb --lldb-libs-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./lib --cmake-build-type Release /home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/test/API/python_api/run_locker -p TestRunLocker.py
--
Exit Code: 1

Command Output (stdout):
--
"can't evaluate expressions when the process is running."
Skipping the following test categories: msvcstl, dsym, pdb, gmodules, debugserver, objc

--
Command Output (stderr):
--
FAIL: LLDB (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-x86_64) :: test_run_locker (TestRunLocker.TestRunLocker.test_run_locker)
Log Files:
 - /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build/python_api/run_locker/TestRunLocker/Failure_test_run_locker.log
PASS: LLDB (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-x86_64) :: test_run_locker_stop_at_entry (TestRunLocker.TestRunLocker.test_run_locker_stop_at_entry)
======================================================================
FAIL: test_run_locker (TestRunLocker.TestRunLocker.test_run_locker)
   Test that the run locker is set correctly when we launch
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/packages/Python/lldbsuite/test/decorators.py", line 175, in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/test/API/python_api/run_locker/TestRunLocker.py", line 23, in test_run_locker
    self.runlocker_test(False)
  File "/home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/test/API/python_api/run_locker/TestRunLocker.py", line 126, in runlocker_test
    self.assertIn(
AssertionError: "can't evaluate expressions when the process is running" not found in ''
Config=x86_64-/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang
----------------------------------------------------------------------
Ran 2 tests in 0.516s

FAILED (failures=1)

--

If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the infrastructure label.

Could this be related?

@DavidSpickett

Copy link
Copy Markdown
Contributor

No it's not related - #193787.

@DavidSpickett DavidSpickett left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LLDB parts look correct to me. Putting them in their own PR is ideal but I'm not bothered too much because the examples are not critical to lldb.

Ping me on the other PR if you do make one.

@vitalybuka

Copy link
Copy Markdown
Contributor

CI looks green, so merging this time without splitting.

@vitalybuka
vitalybuka merged commit bcb4590 into llvm:main Jul 17, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants