Skip to content

[Support] Set OF_Delete for InMemoryBuffer's call to openFileForWrite under commit #140109

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

dgg5503
Copy link
Contributor

@dgg5503 dgg5503 commented May 15, 2025

#134787 unintentionally enabled --mmap-output-file by default under LLD which caused the Windows-only test lld\test\ELF\link-open-file.test to fail. This failure uncovered what appears to be an inconsistency on Windows between createOnDiskBuffer and createInMemoryBuffer with respect to DELETE access for the output file.

The output file created by createOnDiskBuffer sets the flag OF_Delete as part of fs::TempFile::create while the output file created by createInMemoryBuffer sets OF_None under InMemoryBuffer::commit.

The test lld\test\ELF\link-open-file.test ensures that if FILE_SHARE_DELETE is not specified for an output file that LLD is expected to overwrite, LLD should fail. This only happens if: "the file or device has been opened for delete access" which is only done for fs::TempFile::create.

See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#FILE_SHARE_DELETE.

Therefore, I propose setting OF_Delete for InMemoryBuffer::commit's call to openFileForWrite to stay consistent with fs::TempFile::create.


This PR stems from my findings here: #134787 (comment)

… under commit

llvm#134787 unintentionally enabled
`--mmap-output-file` by default under LLD which caused the Windows-only test
`lld\test\ELF\link-open-file.test` to fail. This failure uncovered what appears
to be an inconsistency on Windows between `createOnDiskBuffer` and
`createInMemoryBuffer` with respect to `DELETE` access for the output file.

The output file created by `createOnDiskBuffer` sets the flag `OF_Delete` as
part of `fs::TempFile::create` while the output file created by
`createInMemoryBuffer` sets `OF_None` under `InMemoryBuffer::commit`.

The test `lld\test\ELF\link-open-file.test` ensures that if
`FILE_SHARE_DELETE` is _not_ specified for an output file that LLD is expected
to overwrite, LLD should fail. This only happens if: "the file or device has
been opened for delete access" which is only done for `fs::TempFile::create`.

See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#FILE_SHARE_DELETE.

Therefore, I propose setting `OF_Delete` for `InMemoryBuffer::commit`'s call to
`openFileForWrite` to stay consistent with `fs::TempFile::create`.
@llvmbot
Copy link
Member

llvmbot commented May 15, 2025

@llvm/pr-subscribers-llvm-support

Author: Douglas (dgg5503)

Changes

#134787 unintentionally enabled --mmap-output-file by default under LLD which caused the Windows-only test lld\test\ELF\link-open-file.test to fail. This failure uncovered what appears to be an inconsistency on Windows between createOnDiskBuffer and createInMemoryBuffer with respect to DELETE access for the output file.

The output file created by createOnDiskBuffer sets the flag OF_Delete as part of fs::TempFile::create while the output file created by createInMemoryBuffer sets OF_None under InMemoryBuffer::commit.

The test lld\test\ELF\link-open-file.test ensures that if FILE_SHARE_DELETE is not specified for an output file that LLD is expected to overwrite, LLD should fail. This only happens if: "the file or device has been opened for delete access" which is only done for fs::TempFile::create.

See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#FILE_SHARE_DELETE.

Therefore, I propose setting OF_Delete for InMemoryBuffer::commit's call to openFileForWrite to stay consistent with fs::TempFile::create.


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

2 Files Affected:

  • (modified) lld/test/ELF/link-open-file.test (+9-3)
  • (modified) llvm/lib/Support/FileOutputBuffer.cpp (+1-1)
diff --git a/lld/test/ELF/link-open-file.test b/lld/test/ELF/link-open-file.test
index 17c7ba95e6ebe..8693a53ead5d5 100644
--- a/lld/test/ELF/link-open-file.test
+++ b/lld/test/ELF/link-open-file.test
@@ -10,8 +10,10 @@
 ## FILE_SHARE_WRITE  = 2
 ## FILE_SHARE_DELETE = 4
 
-# RUN:     %python %s %t.o 7
-# RUN: not %python %s %t.o 3 2>&1 | FileCheck %s
+# RUN:     %python %s %t.o 7 false
+# RUN: not %python %s %t.o 3 false 2>&1 | FileCheck %s
+# RUN:     %python %s %t.o 7 true
+# RUN: not %python %s %t.o 3 true 2>&1 | FileCheck %s
 # CHECK: error: failed to write output '{{.*}}': {{.*}}
 
 import contextlib
@@ -26,6 +28,7 @@ import time
 
 object_file = sys.argv[1]
 share_flags = int(sys.argv[2])
+use_mmap = bool(sys.argv[3])
 
 @contextlib.contextmanager
 def open_with_share_flags(filename, share_flags):
@@ -55,7 +58,10 @@ os.makedirs(outdir)
 elf = os.path.join(outdir, 'output_file.elf')
 open(elf, 'wb').close()
 with open_with_share_flags(elf, share_flags):
-    subprocess.check_call(['ld.lld.exe', object_file, '-o', elf])
+    args = ['ld.lld.exe', object_file, '-o', elf]
+    if use_mmap:
+        args.append("--mmap-output-file")
+    subprocess.check_call(args)
 
 ## Check the linker wrote the output file.
 with open(elf, 'rb') as f:
diff --git a/llvm/lib/Support/FileOutputBuffer.cpp b/llvm/lib/Support/FileOutputBuffer.cpp
index a2396d7629488..c8b035986fb5b 100644
--- a/llvm/lib/Support/FileOutputBuffer.cpp
+++ b/llvm/lib/Support/FileOutputBuffer.cpp
@@ -99,7 +99,7 @@ class InMemoryBuffer : public FileOutputBuffer {
     int FD;
     std::error_code EC;
     if (auto EC =
-            openFileForWrite(FinalPath, FD, CD_CreateAlways, OF_None, Mode))
+            openFileForWrite(FinalPath, FD, CD_CreateAlways, OF_Delete, Mode))
       return errorCodeToError(EC);
     raw_fd_ostream OS(FD, /*shouldClose=*/true, /*unbuffered=*/true);
     OS << StringRef((const char *)Buffer.base(), BufferSize);

@llvmbot
Copy link
Member

llvmbot commented May 15, 2025

@llvm/pr-subscribers-lld

Author: Douglas (dgg5503)

Changes

#134787 unintentionally enabled --mmap-output-file by default under LLD which caused the Windows-only test lld\test\ELF\link-open-file.test to fail. This failure uncovered what appears to be an inconsistency on Windows between createOnDiskBuffer and createInMemoryBuffer with respect to DELETE access for the output file.

The output file created by createOnDiskBuffer sets the flag OF_Delete as part of fs::TempFile::create while the output file created by createInMemoryBuffer sets OF_None under InMemoryBuffer::commit.

The test lld\test\ELF\link-open-file.test ensures that if FILE_SHARE_DELETE is not specified for an output file that LLD is expected to overwrite, LLD should fail. This only happens if: "the file or device has been opened for delete access" which is only done for fs::TempFile::create.

See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#FILE_SHARE_DELETE.

Therefore, I propose setting OF_Delete for InMemoryBuffer::commit's call to openFileForWrite to stay consistent with fs::TempFile::create.


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

2 Files Affected:

  • (modified) lld/test/ELF/link-open-file.test (+9-3)
  • (modified) llvm/lib/Support/FileOutputBuffer.cpp (+1-1)
diff --git a/lld/test/ELF/link-open-file.test b/lld/test/ELF/link-open-file.test
index 17c7ba95e6ebe..8693a53ead5d5 100644
--- a/lld/test/ELF/link-open-file.test
+++ b/lld/test/ELF/link-open-file.test
@@ -10,8 +10,10 @@
 ## FILE_SHARE_WRITE  = 2
 ## FILE_SHARE_DELETE = 4
 
-# RUN:     %python %s %t.o 7
-# RUN: not %python %s %t.o 3 2>&1 | FileCheck %s
+# RUN:     %python %s %t.o 7 false
+# RUN: not %python %s %t.o 3 false 2>&1 | FileCheck %s
+# RUN:     %python %s %t.o 7 true
+# RUN: not %python %s %t.o 3 true 2>&1 | FileCheck %s
 # CHECK: error: failed to write output '{{.*}}': {{.*}}
 
 import contextlib
@@ -26,6 +28,7 @@ import time
 
 object_file = sys.argv[1]
 share_flags = int(sys.argv[2])
+use_mmap = bool(sys.argv[3])
 
 @contextlib.contextmanager
 def open_with_share_flags(filename, share_flags):
@@ -55,7 +58,10 @@ os.makedirs(outdir)
 elf = os.path.join(outdir, 'output_file.elf')
 open(elf, 'wb').close()
 with open_with_share_flags(elf, share_flags):
-    subprocess.check_call(['ld.lld.exe', object_file, '-o', elf])
+    args = ['ld.lld.exe', object_file, '-o', elf]
+    if use_mmap:
+        args.append("--mmap-output-file")
+    subprocess.check_call(args)
 
 ## Check the linker wrote the output file.
 with open(elf, 'rb') as f:
diff --git a/llvm/lib/Support/FileOutputBuffer.cpp b/llvm/lib/Support/FileOutputBuffer.cpp
index a2396d7629488..c8b035986fb5b 100644
--- a/llvm/lib/Support/FileOutputBuffer.cpp
+++ b/llvm/lib/Support/FileOutputBuffer.cpp
@@ -99,7 +99,7 @@ class InMemoryBuffer : public FileOutputBuffer {
     int FD;
     std::error_code EC;
     if (auto EC =
-            openFileForWrite(FinalPath, FD, CD_CreateAlways, OF_None, Mode))
+            openFileForWrite(FinalPath, FD, CD_CreateAlways, OF_Delete, Mode))
       return errorCodeToError(EC);
     raw_fd_ostream OS(FD, /*shouldClose=*/true, /*unbuffered=*/true);
     OS << StringRef((const char *)Buffer.base(), BufferSize);

@llvmbot
Copy link
Member

llvmbot commented May 15, 2025

@llvm/pr-subscribers-lld-elf

Author: Douglas (dgg5503)

Changes

#134787 unintentionally enabled --mmap-output-file by default under LLD which caused the Windows-only test lld\test\ELF\link-open-file.test to fail. This failure uncovered what appears to be an inconsistency on Windows between createOnDiskBuffer and createInMemoryBuffer with respect to DELETE access for the output file.

The output file created by createOnDiskBuffer sets the flag OF_Delete as part of fs::TempFile::create while the output file created by createInMemoryBuffer sets OF_None under InMemoryBuffer::commit.

The test lld\test\ELF\link-open-file.test ensures that if FILE_SHARE_DELETE is not specified for an output file that LLD is expected to overwrite, LLD should fail. This only happens if: "the file or device has been opened for delete access" which is only done for fs::TempFile::create.

See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#FILE_SHARE_DELETE.

Therefore, I propose setting OF_Delete for InMemoryBuffer::commit's call to openFileForWrite to stay consistent with fs::TempFile::create.


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

2 Files Affected:

  • (modified) lld/test/ELF/link-open-file.test (+9-3)
  • (modified) llvm/lib/Support/FileOutputBuffer.cpp (+1-1)
diff --git a/lld/test/ELF/link-open-file.test b/lld/test/ELF/link-open-file.test
index 17c7ba95e6ebe..8693a53ead5d5 100644
--- a/lld/test/ELF/link-open-file.test
+++ b/lld/test/ELF/link-open-file.test
@@ -10,8 +10,10 @@
 ## FILE_SHARE_WRITE  = 2
 ## FILE_SHARE_DELETE = 4
 
-# RUN:     %python %s %t.o 7
-# RUN: not %python %s %t.o 3 2>&1 | FileCheck %s
+# RUN:     %python %s %t.o 7 false
+# RUN: not %python %s %t.o 3 false 2>&1 | FileCheck %s
+# RUN:     %python %s %t.o 7 true
+# RUN: not %python %s %t.o 3 true 2>&1 | FileCheck %s
 # CHECK: error: failed to write output '{{.*}}': {{.*}}
 
 import contextlib
@@ -26,6 +28,7 @@ import time
 
 object_file = sys.argv[1]
 share_flags = int(sys.argv[2])
+use_mmap = bool(sys.argv[3])
 
 @contextlib.contextmanager
 def open_with_share_flags(filename, share_flags):
@@ -55,7 +58,10 @@ os.makedirs(outdir)
 elf = os.path.join(outdir, 'output_file.elf')
 open(elf, 'wb').close()
 with open_with_share_flags(elf, share_flags):
-    subprocess.check_call(['ld.lld.exe', object_file, '-o', elf])
+    args = ['ld.lld.exe', object_file, '-o', elf]
+    if use_mmap:
+        args.append("--mmap-output-file")
+    subprocess.check_call(args)
 
 ## Check the linker wrote the output file.
 with open(elf, 'rb') as f:
diff --git a/llvm/lib/Support/FileOutputBuffer.cpp b/llvm/lib/Support/FileOutputBuffer.cpp
index a2396d7629488..c8b035986fb5b 100644
--- a/llvm/lib/Support/FileOutputBuffer.cpp
+++ b/llvm/lib/Support/FileOutputBuffer.cpp
@@ -99,7 +99,7 @@ class InMemoryBuffer : public FileOutputBuffer {
     int FD;
     std::error_code EC;
     if (auto EC =
-            openFileForWrite(FinalPath, FD, CD_CreateAlways, OF_None, Mode))
+            openFileForWrite(FinalPath, FD, CD_CreateAlways, OF_Delete, Mode))
       return errorCodeToError(EC);
     raw_fd_ostream OS(FD, /*shouldClose=*/true, /*unbuffered=*/true);
     OS << StringRef((const char *)Buffer.base(), BufferSize);

Copy link
Member

@MaskRay MaskRay left a comment

Choose a reason for hiding this comment

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

Thanks!

I now see that https://reviews.llvm.org/D82567 introduced the Windows-specific test lld/test/ELF/link-open-file.test .

The test appears to open the output file with FILE_SHARE_DELETE using Python, then invoke lld. If lld opens the output file with FILE_SHARE_DELETE, it will be able to delete it.

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