[lld] r297645 - [ELF] Fail the link early if an output path is invalid

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 13 10:24:52 PDT 2017


Author: ruiu
Date: Mon Mar 13 12:24:52 2017
New Revision: 297645

URL: http://llvm.org/viewvc/llvm-project?rev=297645&view=rev
Log:
[ELF] Fail the link early if an output path is invalid

Patch from James Henderson.

If a user has a long link, e.g. due to a large LTO link, they do not
wish to run it and find that it failed because there was a mistake in
their command-line, after they waited for some significant amount of
time. This change adds some basic checking of the linker output file
path, which is run shortly after parsing the command-line and linker
script. An error is emitted if LLD cannot write to the specified path.

Differential Revision: https://reviews.llvm.org/D30449

Added:
    lld/trunk/test/ELF/early-exit-for-bad-paths.s
Modified:
    lld/trunk/ELF/Driver.cpp
    lld/trunk/test/ELF/driver.test

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=297645&r1=297644&r2=297645&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Mon Mar 13 12:24:52 2017
@@ -42,6 +42,7 @@
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/Object/Decompressor.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileOutputBuffer.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/TarWriter.h"
 #include "llvm/Support/TargetSelect.h"
@@ -796,6 +797,17 @@ static uint64_t getImageBase(opt::InputA
   return V;
 }
 
+static void ensureWritable(StringRef Path) {
+  if (Path.empty())
+    return;
+
+  ErrorOr<std::unique_ptr<FileOutputBuffer>> Err =
+      FileOutputBuffer::create(Path, 1);
+  if (!Err)
+    error("cannot open output file " + Path + ": " +
+          Err.getError().message());
+}
+
 // Do actual linking. Note that when this function is called,
 // all linker scripts have already been parsed.
 template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
@@ -819,6 +831,13 @@ template <class ELFT> void LinkerDriver:
   if (Config->Entry.empty() && !Config->Relocatable)
     Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start";
 
+  // Fail early if the output file is not writable. If a user has a long link,
+  // e.g. due to a large LTO link, they do not wish to run it and find that it
+  // failed because there was a mistake in their command-line.
+  ensureWritable(Config->OutputFile);
+  if (ErrorCount)
+    return;
+
   // Handle --trace-symbol.
   for (auto *Arg : Args.filtered(OPT_trace_symbol))
     Symtab.trace(Arg->getValue());

Modified: lld/trunk/test/ELF/driver.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/driver.test?rev=297645&r1=297644&r2=297645&view=diff
==============================================================================
--- lld/trunk/test/ELF/driver.test (original)
+++ lld/trunk/test/ELF/driver.test Mon Mar 13 12:24:52 2017
@@ -11,7 +11,7 @@
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
 # RUN: not ld.lld %t -o /no/such/file 2>&1 | FileCheck -check-prefix=MISSING %s
-# MISSING: failed to open /no/such/file
+# MISSING: cannot open output file /no/such/file
 
 # RUN: ld.lld --help 2>&1 | FileCheck -check-prefix=HELP %s
 # HELP: USAGE:
@@ -48,11 +48,11 @@
 
 ## "--output=foo" is equivalent to "-o foo".
 # RUN: not ld.lld %t --output=/no/such/file 2>&1 | FileCheck -check-prefix=ERR7 %s
-# ERR7: failed to open /no/such/file
+# ERR7: cannot open output file /no/such/file
 
 ## "-output=foo" is equivalent to "-o utput=foo".
 # RUN: not ld.lld %t -output=/no/such/file 2>&1 | FileCheck -check-prefix=ERR8 %s
-# ERR8: failed to open utput=/no/such/file
+# ERR8: cannot open output file utput=/no/such/file
 
 .globl _start
 _start:

Added: lld/trunk/test/ELF/early-exit-for-bad-paths.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/early-exit-for-bad-paths.s?rev=297645&view=auto
==============================================================================
--- lld/trunk/test/ELF/early-exit-for-bad-paths.s (added)
+++ lld/trunk/test/ELF/early-exit-for-bad-paths.s Mon Mar 13 12:24:52 2017
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+# RUN: not ld.lld %t.o -o does_not_exist/output 2>&1 | \
+# RUN:   FileCheck %s -check-prefixes=NO-DIR,CHECK
+# RUN: not ld.lld %t.o -o %s/dir_is_a_file 2>&1 | \
+# RUN:   FileCheck %s -check-prefixes=DIR-IS-FILE,CHECK
+
+# RUN: echo "OUTPUT(\"does_not_exist/output\")" > %t.script
+# RUN: not ld.lld %t.o %t.script 2>&1 | \
+# RUN:   FileCheck %s -check-prefixes=NO-DIR,CHECK
+# RUN: echo "OUTPUT(\"%s/dir_is_a_file\")" > %t.script
+# RUN: not ld.lld %t.o %t.script 2>&1 | \
+# RUN:   FileCheck %s -check-prefixes=DIR-IS-FILE,CHECK
+
+# NO-DIR: error: cannot open output file does_not_exist/output:
+# DIR-IS-FILE: error: cannot open output file {{.*}}/dir_is_a_file:
+
+# We should exit before doing the actual link. If an undefined symbol error is
+# discovered we haven't bailed out early as expected.
+# CHECK-NOT: undefined_symbol
+
+  .globl _start
+_start:
+  call undefined_symbol




More information about the llvm-commits mailing list