[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