[llvm] [Support] Treat Windows "nul" as the null device in writeToOutput (PR #208179)

Wenju He via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 17:46:30 PDT 2026


https://github.com/wenju-he updated https://github.com/llvm/llvm-project/pull/208179

>From b50a6181634639717b054b9030682e32655f3a06 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Wed, 8 Jul 2026 11:22:56 +0200
Subject: [PATCH 1/3] [Support] Treat Windows "nul" as the null device in
 writeToOutput

llvm-objcopy (via writeToOutput) only special-cased "/dev/null", so on
Windows an output path of "nul" fell through to TempFile::create() +
rename. Windows reserves "nul" as a device name, so the rename fails
with "permission denied". This broke clang-offload-bundler's SYCL fat
object step when the driver is invoked with `-o nul` in downstream test
https://github.com/intel/llvm/blob/sycl/sycl/test/include_deps/header_reach.cpp

Assisted by: Claude
---
 llvm/lib/Support/raw_ostream.cpp            | 10 +++++++-
 llvm/unittests/Support/raw_ostream_test.cpp | 28 +++++++++++++++++++++
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index eebc4db5ac878..8bc00dc07d522 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -993,12 +993,20 @@ void buffer_ostream::anchor() {}
 
 void buffer_unique_ostream::anchor() {}
 
+static bool isNullDeviceName(StringRef OutputFileName) {
+#ifdef _WIN32
+  if (OutputFileName.equals_insensitive("nul"))
+    return true;
+#endif
+  return OutputFileName == "/dev/null";
+}
+
 Error llvm::writeToOutput(StringRef OutputFileName,
                           std::function<Error(raw_ostream &)> Write) {
   if (OutputFileName == "-")
     return Write(outs());
 
-  if (OutputFileName == "/dev/null") {
+  if (isNullDeviceName(OutputFileName)) {
     raw_null_ostream Out;
     return Write(Out);
   }
diff --git a/llvm/unittests/Support/raw_ostream_test.cpp b/llvm/unittests/Support/raw_ostream_test.cpp
index ed04721816476..ed059faec23b8 100644
--- a/llvm/unittests/Support/raw_ostream_test.cpp
+++ b/llvm/unittests/Support/raw_ostream_test.cpp
@@ -623,6 +623,34 @@ TEST(raw_ostreamTest, writeToDevNull) {
   EXPECT_TRUE(DevNullIsUsed);
 }
 
+#ifdef _WIN32
+TEST(raw_ostreamTest, writeToNul) {
+  // raw_null_ostream never touches the filesystem, so no "nul.temp-stream-*"
+  // file should exist in the CWD while Write() runs.
+  llvm::unittest::TempDir RootTestDirectory("writeToNul", /*Unique=*/true);
+  SmallString<128> SavedCWD;
+  ASSERT_FALSE(sys::fs::current_path(SavedCWD));
+  ASSERT_FALSE(sys::fs::set_current_path(RootTestDirectory.path()));
+
+  EXPECT_THAT_ERROR(
+      writeToOutput("nul",
+                    [&](raw_ostream &Out) -> Error {
+                      std::error_code EC;
+                      sys::fs::directory_iterator It(
+                          RootTestDirectory.path(), EC), End;
+                      EXPECT_FALSE(EC);
+                      EXPECT_EQ(It, End)
+                          << "unexpected temp file on disk during Write(): "
+                          << It->path();
+                      Out << "HelloWorld";
+                      return Error::success();
+                    }),
+      Succeeded());
+
+  ASSERT_FALSE(sys::fs::set_current_path(SavedCWD));
+}
+#endif
+
 TEST(raw_ostreamTest, nullStreamZeroBufferSize) {
   raw_ostream &NullStream = nulls();
   EXPECT_EQ(NullStream.GetBufferSize(), 0u);

>From 7fc90766b33635d02f171c1d1bdf1245cf714806 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Wed, 8 Jul 2026 11:33:25 +0200
Subject: [PATCH 2/3] clang-format

---
 llvm/unittests/Support/raw_ostream_test.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/unittests/Support/raw_ostream_test.cpp b/llvm/unittests/Support/raw_ostream_test.cpp
index ed059faec23b8..c7cb9e340dbcf 100644
--- a/llvm/unittests/Support/raw_ostream_test.cpp
+++ b/llvm/unittests/Support/raw_ostream_test.cpp
@@ -636,8 +636,9 @@ TEST(raw_ostreamTest, writeToNul) {
       writeToOutput("nul",
                     [&](raw_ostream &Out) -> Error {
                       std::error_code EC;
-                      sys::fs::directory_iterator It(
-                          RootTestDirectory.path(), EC), End;
+                      sys::fs::directory_iterator It(RootTestDirectory.path(),
+                                                     EC),
+                          End;
                       EXPECT_FALSE(EC);
                       EXPECT_EQ(It, End)
                           << "unexpected temp file on disk during Write(): "

>From c22cc139373dc5b2363f1db3e98bcfa45b0d25b4 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Wed, 15 Jul 2026 02:15:05 +0200
Subject: [PATCH 3/3] use canonical device name NUL

---
 llvm/lib/Support/raw_ostream.cpp            | 2 +-
 llvm/unittests/Support/raw_ostream_test.cpp | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index e4e046d709c53..28401d674479c 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -995,7 +995,7 @@ void buffer_unique_ostream::anchor() {}
 
 static bool isNullDeviceName(StringRef OutputFileName) {
 #ifdef _WIN32
-  if (OutputFileName.equals_insensitive("nul"))
+  if (OutputFileName.equals_insensitive("NUL"))
     return true;
 #endif
   return OutputFileName == "/dev/null";
diff --git a/llvm/unittests/Support/raw_ostream_test.cpp b/llvm/unittests/Support/raw_ostream_test.cpp
index 949163b396ec8..aded02c7b3402 100644
--- a/llvm/unittests/Support/raw_ostream_test.cpp
+++ b/llvm/unittests/Support/raw_ostream_test.cpp
@@ -661,8 +661,8 @@ TEST(raw_ostreamTest, writeToDevNull) {
 }
 
 #ifdef _WIN32
-TEST(raw_ostreamTest, writeToNul) {
-  // raw_null_ostream never touches the filesystem, so no "nul.temp-stream-*"
+TEST(raw_ostreamTest, writeToNUL) {
+  // raw_null_ostream never touches the filesystem, so no "NUL.temp-stream-*"
   // file should exist in the CWD while Write() runs.
   llvm::unittest::TempDir RootTestDirectory("writeToNul", /*Unique=*/true);
   SmallString<128> SavedCWD;
@@ -670,7 +670,7 @@ TEST(raw_ostreamTest, writeToNul) {
   ASSERT_FALSE(sys::fs::set_current_path(RootTestDirectory.path()));
 
   EXPECT_THAT_ERROR(
-      writeToOutput("nul",
+      writeToOutput("NUL",
                     [&](raw_ostream &Out) -> Error {
                       std::error_code EC;
                       sys::fs::directory_iterator It(RootTestDirectory.path(),



More information about the llvm-commits mailing list