[Support] Treat Windows "nul" as the null device in writeToOutput#208179
[Support] Treat Windows "nul" as the null device in writeToOutput#208179wenju-he wants to merge 2 commits into
Conversation
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
You can test this locally with the following command:git-clang-format --diff origin/main HEAD --extensions cpp -- llvm/lib/Support/raw_ostream.cpp llvm/unittests/Support/raw_ostream_test.cpp --diff_from_common_commit
View the diff from clang-format here.diff --git a/llvm/unittests/Support/raw_ostream_test.cpp b/llvm/unittests/Support/raw_ostream_test.cpp
index ed059faec..c7cb9e340 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(): "
|
|
@llvm/pr-subscribers-llvm-support Author: Wenju He (wenju-he) Changesllvm-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 Assisted by: Claude Full diff: https://github.com/llvm/llvm-project/pull/208179.diff 2 Files Affected:
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..c7cb9e340dbcf 100644
--- a/llvm/unittests/Support/raw_ostream_test.cpp
+++ b/llvm/unittests/Support/raw_ostream_test.cpp
@@ -623,6 +623,35 @@ 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);
|
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 nulin downstream test https://github.com/intel/llvm/blob/sycl/sycl/test/include_deps/header_reach.cppAssisted by: Claude