Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -33,11 +33,12 @@ void run(); private: + void setError(const Twine &Msg); static std::vector tokenize(StringRef S); static StringRef skipSpace(StringRef S); + bool atEOF(); StringRef next(); bool skip(StringRef Tok); - bool atEOF() { return Tokens.size() == Pos; } void expect(StringRef Expect); void addFile(StringRef Path); @@ -57,6 +58,7 @@ StringSaver Saver; std::vector Tokens; + bool Error = false; size_t Pos = 0; bool IsUnderSysroot; }; @@ -86,11 +88,20 @@ } else if (Tok == "SECTIONS") { readSections(); } else { - fatal("unknown directive: " + Tok); + setError("unknown directive: " + Tok); + return; } } } +// We don't want to record cascading errors. Keep only the first one. +void LinkerScript::setError(const Twine &Msg) { + if (Error) + return; + error(Msg); + Error = true; +} + // Split S into linker script tokens. std::vector LinkerScript::tokenize(StringRef S) { std::vector Ret; @@ -102,8 +113,10 @@ // Quoted token if (S.startswith("\"")) { size_t E = S.find("\"", 1); - if (E == StringRef::npos) - fatal("unclosed quote"); + if (E == StringRef::npos) { + error("unclosed quote"); + return {}; + } Ret.push_back(S.substr(1, E - 1)); S = S.substr(E + 1); continue; @@ -127,8 +140,10 @@ for (;;) { if (S.startswith("/*")) { size_t E = S.find("*/", 2); - if (E == StringRef::npos) - fatal("unclosed comment in a linker script"); + if (E == StringRef::npos) { + error("unclosed comment in a linker script"); + return ""; + } S = S.substr(E + 2); continue; } @@ -139,15 +154,26 @@ } } +// An errneous token is handled as if it were the last token before EOF. +bool LinkerScript::atEOF() { return Error || Tokens.size() == Pos; } + StringRef LinkerScript::next() { - if (atEOF()) - fatal("unexpected EOF"); + if (Error) + return ""; + if (atEOF()) { + setError("unexpected EOF"); + return ""; + } return Tokens[Pos++]; } bool LinkerScript::skip(StringRef Tok) { - if (atEOF()) - fatal("unexpected EOF"); + if (Error) + return false; + if (atEOF()) { + setError("unexpected EOF"); + return false; + } if (Tok != Tokens[Pos]) return false; ++Pos; @@ -155,9 +181,11 @@ } void LinkerScript::expect(StringRef Expect) { + if (Error) + return; StringRef Tok = next(); if (Tok != Expect) - fatal(Expect + " expected, but got " + Tok); + setError(Expect + " expected, but got " + Tok); } void LinkerScript::addFile(StringRef S) { @@ -184,8 +212,9 @@ } else { std::string Path = findFromSearchPaths(S); if (Path.empty()) - fatal("Unable to find " + S); - Driver->addFile(Saver.save(Path)); + setError("Unable to find " + S); + else + Driver->addFile(Saver.save(Path)); } } @@ -193,7 +222,7 @@ expect("("); bool Orig = Config->AsNeeded; Config->AsNeeded = true; - for (;;) { + while (!Error) { StringRef Tok = next(); if (Tok == ")") break; @@ -213,7 +242,7 @@ void LinkerScript::readExtern() { expect("("); - for (;;) { + while (!Error) { StringRef Tok = next(); if (Tok == ")") return; @@ -223,7 +252,7 @@ void LinkerScript::readGroup() { expect("("); - for (;;) { + while (!Error) { StringRef Tok = next(); if (Tok == ")") return; @@ -238,7 +267,10 @@ void LinkerScript::readInclude() { StringRef Tok = next(); auto MBOrErr = MemoryBuffer::getFile(Tok); - fatal(MBOrErr, "cannot open " + Tok); + if (!MBOrErr) { + setError("cannot open " + Tok); + return; + } std::unique_ptr &MB = *MBOrErr; StringRef S = Saver.save(MB->getMemBufferRef().getBuffer()); std::vector V = tokenize(S); @@ -268,8 +300,10 @@ StringRef Tok = next(); if (Tok == ")") return; - if (Tok != ",") - fatal("unexpected token: " + Tok); + if (Tok != ",") { + setError("unexpected token: " + Tok); + return; + } next(); expect(","); next(); @@ -284,7 +318,7 @@ void LinkerScript::readSections() { expect("{"); - while (!skip("}")) + while (!Error && !skip("}")) readOutputSectionDescription(); } @@ -294,10 +328,10 @@ expect(":"); expect("{"); - while (!skip("}")) { + while (!Error && !skip("}")) { next(); // Skip input file name. expect("("); - while (!skip(")")) + while (!Error && !skip(")")) InputSections.push_back(next()); } } Index: test/ELF/invalid-linkerscript.test =================================================================== --- /dev/null +++ test/ELF/invalid-linkerscript.test @@ -0,0 +1,41 @@ +# RUN: mkdir -p %t.dir + +# RUN: echo foobar > %t1 +# RUN: not ld.lld %t1 2>&1 | FileCheck -check-prefix=ERR1 %s +# ERR1: unknown directive: foobar +# ERR1: no input files + +# RUN: echo "foo \"bar" > %t2 +# RUN: not ld.lld %t2 2>&1 | FileCheck -check-prefix=ERR2 %s +# ERR2: unclosed quote +# ERR2: no input files + +# RUN: echo "/*" > %t3 +# RUN: not ld.lld %t3 2>&1 | FileCheck -check-prefix=ERR3 %s +# ERR3: unclosed comment +# ERR3: no input files + +# RUN: echo "EXTERN (" > %t4 +# RUN: not ld.lld %t4 2>&1 | FileCheck -check-prefix=ERR4 %s +# ERR4: unexpected EOF +# ERR4: no input files + +# RUN: echo "EXTERN (" > %t5 +# RUN: not ld.lld %t5 2>&1 | FileCheck -check-prefix=ERR5 %s +# ERR5: unexpected EOF +# ERR5: no input files + +# RUN: echo "EXTERN xyz" > %t6 +# RUN: not ld.lld %t6 2>&1 | FileCheck -check-prefix=ERR6 %s +# ERR6: ( expected, but got xyz +# ERR6: no input files + +# RUN: echo "INCLUDE /no/such/file" > %t7 +# RUN: not ld.lld %t7 2>&1 | FileCheck -check-prefix=ERR7 %s +# ERR7: cannot open /no/such/file +# ERR7: no input files + +# RUN: echo "OUTPUT_FORMAT(x y z)" > %t8 +# RUN: not ld.lld %t8 2>&1 | FileCheck -check-prefix=ERR8 %s +# ERR8: unexpected token: y +# ERR8: no input files