From 3a118aa3443d6a7da034e1bb9b3d7ae22adbe42d Mon Sep 17 00:00:00 2001 From: Nick Kledzik Date: Thu, 16 Oct 2014 23:42:42 +0000 Subject: [PATCH] [mach-o] Fix crash when -all_load used with dylibs -all_load tells the darwin linker to immediately load all members of all archives. The code do that used reinterpret_cast<> instead of dyn_cast<>. If the file was a dylib, the reinterpret_cast<> turned a pointer to a dylib into a pointer to an archive...boom. Added test case to reproduce the crash, simplified the code and used dyn_cast<>. llvm-svn: 219990 --- lld/lib/Driver/DarwinInputGraph.cpp | 26 +++++++------------- lld/test/mach-o/force_load-dylib.yaml | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 18 deletions(-) create mode 100644 lld/test/mach-o/force_load-dylib.yaml diff --git a/lld/lib/Driver/DarwinInputGraph.cpp b/lld/lib/Driver/DarwinInputGraph.cpp index 1ddde24..f71afb0 100644 --- a/lld/lib/Driver/DarwinInputGraph.cpp +++ b/lld/lib/Driver/DarwinInputGraph.cpp @@ -35,31 +35,21 @@ std::error_code MachOFileNode::parse(const LinkingContext &ctx, narrowFatBuffer(*filePath); std::vector> parsedFiles; - if (_isWholeArchive) { - std::error_code ec = ctx.registry().parseFile(_buffer, parsedFiles); - if (ec) - return ec; - assert(parsedFiles.size() == 1); - std::unique_ptr f(parsedFiles[0].release()); - if (auto archive = - reinterpret_cast(f.get())) { - // FIXME: something needs to own archive File - //_files.push_back(std::move(archive)); - return archive->parseAllMembers(_files); - } else { - // if --whole-archive is around non-archive, just use it as normal. - _files.push_back(std::move(f)); - return std::error_code(); - } - } if (std::error_code ec = ctx.registry().parseFile(_buffer, parsedFiles)) return ec; for (std::unique_ptr &pf : parsedFiles) { - // If a dylib was parsed, inform LinkingContext about it. + // If file is a dylib, inform LinkingContext about it. if (SharedLibraryFile *shl = dyn_cast(pf.get())) { _context.registerDylib(reinterpret_cast(shl), _upwardDylib); } + // If file is an archive and -all_load, then add all members. + if (ArchiveLibraryFile *archive = dyn_cast(pf.get())) { + if (_isWholeArchive) { + // Note: the members are added to _files, but the archive is not. + return archive->parseAllMembers(_files); + } + } _files.push_back(std::move(pf)); } return std::error_code(); diff --git a/lld/test/mach-o/force_load-dylib.yaml b/lld/test/mach-o/force_load-dylib.yaml new file mode 100644 index 0000000..0b932e1 --- /dev/null +++ b/lld/test/mach-o/force_load-dylib.yaml @@ -0,0 +1,45 @@ +# RUN: lld -flavor darwin -arch x86_64 -dylib %p/Inputs/bar.yaml \ +# RUN: -install_name /usr/lib/libbar.dylib %p/Inputs/libSystem.yaml -o %t1.dylib +# RUN: lld -flavor darwin -arch x86_64 -dylib %s -all_load %t1.dylib \ +# RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/libSystem.yaml -o %t +# RUN: llvm-nm -m %t | FileCheck %s +# +# +# Test -all_load does not break linking with dylibs +# + +--- !mach-o +arch: x86_64 +file-type: MH_OBJECT +flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ] +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + address: 0x0000000000000000 + content: [ 0x55, 0x48, 0x89, 0xE5, 0x31, 0xC0, 0x5D, 0xE9, + 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x00000008 + type: X86_64_RELOC_BRANCH + length: 2 + pc-rel: true + extern: true + symbol: 1 +global-symbols: + - name: _foo + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 +undefined-symbols: + - name: _bar + type: N_UNDF + scope: [ N_EXT ] + value: 0x0000000000000000 + +... + + +# CHECK: (__TEXT,__text) external _foo -- 2.7.4