[llvm-dev] Possible stack corruption during call to JITSymbol::getAddress()

David Lurton via llvm-dev llvm-dev at lists.llvm.org
Mon May 1 07:50:48 PDT 2017


Nobody has responded yet and at this point I'm not holding my breath.  I
sent a second email asking if I had the correct procedure for requesting an
account, etc, but there was no response to that either.

I think I can apply that workaround to my project.  I have a bunch of tests
to which will have share a statically allocated JIT--not ideal but not too
awful I don't think.

On Sun, Apr 30, 2017 at 8:01 PM, Lang Hames <lhames at gmail.com> wrote:

> Hi David,
>
> Sorry to hear. Has anyone followed up with you yet?
>
> I've continued to dig in to this in my spare time and I've found the
> issue. It's a use-after-free, rather than any sort of memory smashing. ORC
> is currently failing to deregister the EH-frame section when the JIT is
> torn down (but *is* deallocating the memory for it). Normally that's not
> disastrous (though it does leave bogus EH frames in memory), but in your
> case the thrown exception tears down the JIT itself, so the unwinder ends
> up reading eh-frames that have been deallocated. I'm working on a fix to
> have the JIT properly deregister EH frames, but one workaround for now
> would be to make sure you catch the exception before it causes the JIT
> stack to be destructed.
>
> Cheers,
> Lang.
>
> On Thu, Apr 20, 2017 at 9:42 AM, David Lurton <dlurton at gmail.com> wrote:
>
>> Well, 3 days later and so far nobody has responded to my request for an
>> account on bugs.llvm.org.. so it doesn't look like I'm going to be able
>> to create that bug on my own, unfortunately.
>>
>> On Wed, Apr 19, 2017 at 6:27 PM, Lang Hames <lhames at gmail.com> wrote:
>>
>>> Hi David,
>>>
>>> Thanks very much for that. I'll continue to dig in as time permits, and
>>> I'll update the bug report with my progress once it's filed.
>>>
>>> Cheers,
>>> Lang.
>>>
>>> On Mon, Apr 17, 2017 at 6:42 PM, David Lurton <dlurton at gmail.com> wrote:
>>>
>>>> Thanks Lang.  I think I'll go the bug creation route.  I have an email
>>>> out to llvm-admin requesting an account on bugs.llvm.org.  I'll let
>>>> you know when I've filed the bug.
>>>>
>>>> On Sun, Apr 16, 2017 at 9:44 PM, Lang Hames <lhames at gmail.com> wrote:
>>>>
>>>>> Hi David,
>>>>>
>>>>> This looks like bad eh-frame data due to a failure to fix up the frame
>>>>> descriptor entries:
>>>>>
>>>>> <debug: adding frame> EHFrameAddr: 0x7feae5827000, EHFrameLoadAddr:
>>>>> 0x00000000e5827000, EHFrameSize: 60
>>>>> ==64588==ERROR: AddressSanitizer: SEGV on unknown address
>>>>> 0x7feae5827020 (pc 0x7feae886d970 bp 0x000000000001 sp 0x7ffca10e75f8 T0)
>>>>>
>>>>> Eyeballing the code in RuntimeDyldELF (vs RuntimeDyldMachO, which is
>>>>> doing the right thing) I see it lacks the necessary fixups. If you're
>>>>> feeling game you can try to port RuntimeDyldMachO's solution to
>>>>> RuntimeDyldELF (where MachO uses a template argument, you'll need to switch
>>>>> over the RuntimeDyldImpl Arch member to determine the pointer size for the
>>>>> fixup). Otherwise you should file a bug on bugs.llvm.org and CC me,
>>>>> and then I can CC some of the ELF devs and see if anyone has time.
>>>>>
>>>>> In the mean time, turning off exception support should fix this,
>>>>> though I'm not sure whether that's a viable option for your use case.
>>>>>
>>>>> Cheers,
>>>>> Lang.
>>>>>
>>>>> On Thu, Apr 13, 2017 at 10:53 AM, Lang Hames <lhames at gmail.com> wrote:
>>>>>
>>>>>> Hi David,
>>>>>>
>>>>>> This is definitely the right place to ask.
>>>>>>
>>>>>> Let me see if I can reproduce this locally...
>>>>>>
>>>>>> Cheers,
>>>>>> Lang.
>>>>>>
>>>>>>
>>>>>> On Sun, Apr 9, 2017 at 2:02 PM, David Lurton via llvm-dev <
>>>>>> llvm-dev at lists.llvm.org> wrote:
>>>>>>
>>>>>>> Firstly, apologies if this is not the right place to be asking this
>>>>>>> question--feel free to point me in the correct direction.  I could be doing
>>>>>>> something wrong here but stackoverflow didn't feel like the correct place
>>>>>>> for this since there's so little there about LLVM ORC.
>>>>>>>
>>>>>>> Basically, I have a reproduction case (below) where if I throw an
>>>>>>> exception before I call JITSymbol::getAddress() everything works properly
>>>>>>> but throwing the same exception afterward will result in a SIGSEGV during
>>>>>>> stack unwinding.  This suggests to me that somehow the stack is getting
>>>>>>> corrupted during the JITSymbol::getAddress() call.
>>>>>>>
>>>>>>> This problem was initially discovered while working on my own
>>>>>>> project.  While troubleshooting this I've discvoered that when LLVM is
>>>>>>> -DLLVM_USE_SANITIZER:STRING=Address the problem happens at
>>>>>>> different points during execution, perhaps having something to do with the
>>>>>>> padding around the stack variables added by the sanitizer?  See the note
>>>>>>> after the call to runTest() in main().
>>>>>>>
>>>>>>> I'm running this under an up-to-date Antergos Linux, clang version:
>>>>>>> 3.9.1 (tried compiling LLVM and the example program below with gcc 6.3.1
>>>>>>> and the result is the same) clang set to default compiler by setting the
>>>>>>> following environment variables:
>>>>>>>
>>>>>>>     CC=/usr/bin/clang
>>>>>>>     CXX=/usr/bin/clang++
>>>>>>>
>>>>>>> Commands used to build LLVM:
>>>>>>>
>>>>>>>     git clone https://github.com/llvm-mirror/llvm.git
>>>>>>>     git checkout release_40
>>>>>>>     cd llvm
>>>>>>>     mkdir build
>>>>>>>     cd build
>>>>>>>     cmake .. -DLLVM_BUILD_LLVM_DYLIB:BOOL=ON
>>>>>>> -DLLVM_ENABLE_RTTI:BOOL=ON -DLLVM_ENABLE_EH:BOOL=ON
>>>>>>> -DLLVM_USE_SANITIZER:STRING=Address -DLLVM_PARALLEL_COMPILE_JOBS:STRING=8
>>>>>>> -DLLVM_ENABLE_ASSERTIONS:BOOL=ON
>>>>>>>     cmake --build . -- -j 8
>>>>>>>     sudo cmake --build . --target install
>>>>>>>
>>>>>>> Command used to build test case executable:
>>>>>>>
>>>>>>>     clang test.cpp -std=c++14 -lstdc++ -lLLVM-4.0 -Wall -pedantic
>>>>>>> -Wextra  -fstack-protector-all -fsanitize=address -fexceptions
>>>>>>>
>>>>>>> Then of course:
>>>>>>>
>>>>>>>     ./a.out
>>>>>>>
>>>>>>> Output from the a.out:
>>>>>>>
>>>>>>> ASAN:DEADLYSIGNAL
>>>>>>> =================================================================
>>>>>>> ==6582==ERROR: AddressSanitizer: SEGV on unknown address
>>>>>>> 0x7f59eeb06020 (pc 0x7f59f1b20930 bp 0x000000000001 sp 0x7ffc5e546218 T0)
>>>>>>> ==6582==The signal is caused by a READ memory access.
>>>>>>>
>>>>>>>
>>>>>>> The result if running `backtrace` in GDB while execution is paused
>>>>>>> after the SIGSEGV occurs:
>>>>>>>
>>>>>>> #0  read_encoded_value_with_base (encoding=encoding at entry=28
>>>>>>> '\034', base=base at entry=0, p=p at entry=0x7fffe8a06020 <error: Cannot
>>>>>>> access memory at address 0x7fffe8a06020>, val=val at entry=0x7fffffffd6d8)
>>>>>>> at /build/gcc/src/gcc/libgcc/unwind-pe.h:252
>>>>>>> #1  0x00007fffeba05a61 in binary_search_single_encoding_fdes
>>>>>>> (pc=0x7fffeba04426 <_Unwind_Resume+54>, ob=0x0) at
>>>>>>> /build/gcc/src/gcc/libgcc/unwind-dw2-fde.c:908
>>>>>>> #2  search_object (ob=ob at entry=0x60400001d9d0, pc=pc at entry=0x7fffeba04426
>>>>>>> <_Unwind_Resume+54>) at /build/gcc/src/gcc/libgcc/unwi
>>>>>>> nd-dw2-fde.c:977
>>>>>>> #3  0x00007fffeba05fdd in _Unwind_Find_registered_FDE
>>>>>>> (bases=0x7fffffffda78, pc=0x7fffeba04426 <_Unwind_Resume+54>) at
>>>>>>> /build/gcc/src/gcc/libgcc/unwind-dw2-fde.c:1013
>>>>>>> #4  _Unwind_Find_FDE (pc=0x7fffeba04426 <_Unwind_Resume+54>,
>>>>>>> bases=bases at entry=0x7fffffffda78) at /build/gcc/src/gcc/libgcc/unwi
>>>>>>> nd-dw2-fde-dip.c:454
>>>>>>> #5  0x00007fffeba02b23 in uw_frame_state_for (context=context at entry
>>>>>>> =0x7fffffffd9d0, fs=fs at entry=0x7fffffffd820) at
>>>>>>> /build/gcc/src/gcc/libgcc/unwind-dw2.c:1241
>>>>>>> #6  0x00007fffeba03d40 in uw_init_context_1 (context=context at entry
>>>>>>> =0x7fffffffd9d0, outer_cfa=outer_cfa at entry=0x7fffffffdc00,
>>>>>>> outer_ra=0x5110fc) at /build/gcc/src/gcc/libgcc/unwind-dw2.c:1562
>>>>>>> #7  0x00007fffeba04427 in _Unwind_Resume (exc=0x60d00000c7b0) at
>>>>>>> /build/gcc/src/gcc/libgcc/unwind.inc:224
>>>>>>> #8  0x00000000005110fc in runTest () at
>>>>>>> /home/dave/projects/untitled/test.cpp:124
>>>>>>> #9  0x0000000000511138 in main (argc=1, argv=0x7fffffffe698) at
>>>>>>> /home/dave/projects/untitled/test.cpp:132
>>>>>>>
>>>>>>> My test-case is below.  In runTest(), note the commented out throw
>>>>>>> statement before symbol.getAddress() and the uncommented one after it.
>>>>>>> Also note the comments after the call to runTest() in main().
>>>>>>>
>>>>>>> Thanks.
>>>>>>>
>>>>>>>
>>>>>>> #include "llvm/ADT/STLExtras.h"
>>>>>>> #include "llvm/ExecutionEngine/ExecutionEngine.h"
>>>>>>> #include "llvm/IR/IRBuilder.h"
>>>>>>> #include "llvm/ExecutionEngine/SectionMemoryManager.h"
>>>>>>> #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
>>>>>>> #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
>>>>>>> #include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
>>>>>>> #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
>>>>>>> #include "llvm/IR/Mangler.h"
>>>>>>> #include "llvm/Support/DynamicLibrary.h"
>>>>>>> #include "llvm/Support/TargetSelect.h"
>>>>>>> #include <iostream>
>>>>>>>
>>>>>>> using namespace llvm;
>>>>>>> using namespace llvm::orc;
>>>>>>>
>>>>>>> /** This class taken verbatim from
>>>>>>>  * https://github.com/llvm-mirror/llvm/blob/release_40/examples
>>>>>>> /Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h
>>>>>>>  * This is from the same revision of LLVM I am using (the release_40
>>>>>>> branch as of 4/8/2017)
>>>>>>>  */
>>>>>>> class KaleidoscopeJIT {
>>>>>>> private:
>>>>>>>     std::unique_ptr<TargetMachine> TM;
>>>>>>>     const DataLayout DL;
>>>>>>>     ObjectLinkingLayer<> ObjectLayer;
>>>>>>>     IRCompileLayer<decltype(ObjectLayer)> CompileLayer;
>>>>>>>
>>>>>>> public:
>>>>>>>     typedef decltype(CompileLayer)::ModuleSetHandleT ModuleHandle;
>>>>>>>
>>>>>>>     KaleidoscopeJIT()
>>>>>>>             : TM(EngineBuilder().selectTarget()),
>>>>>>> DL(TM->createDataLayout()),
>>>>>>>               CompileLayer(ObjectLayer, SimpleCompiler(*TM)) {
>>>>>>>         llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
>>>>>>>     }
>>>>>>>
>>>>>>>     TargetMachine &getTargetMachine() { return *TM; }
>>>>>>>
>>>>>>>     ModuleHandle addModule(std::unique_ptr<Module> M) {
>>>>>>>         // Build our symbol resolver:
>>>>>>>         // Lambda 1: Look back into the JIT itself to find symbols
>>>>>>> that are part of
>>>>>>>         //           the same "logical dylib".
>>>>>>>         // Lambda 2: Search for external symbols in the host process.
>>>>>>>         auto Resolver = createLambdaResolver(
>>>>>>>                 [&](const std::string &Name) {
>>>>>>>                     if (auto Sym = CompileLayer.findSymbol(Name,
>>>>>>> false))
>>>>>>>                         return Sym;
>>>>>>>                     return JITSymbol(nullptr);
>>>>>>>                 },
>>>>>>>                 [](const std::string &Name) {
>>>>>>>                     if (auto SymAddr =
>>>>>>>                             RTDyldMemoryManager::getSymbol
>>>>>>> AddressInProcess(Name))
>>>>>>>                         return JITSymbol(SymAddr,
>>>>>>> JITSymbolFlags::Exported);
>>>>>>>                     return JITSymbol(nullptr);
>>>>>>>                 });
>>>>>>>
>>>>>>>         // Build a singleton module set to hold our module.
>>>>>>>         std::vector<std::unique_ptr<Module>> Ms;
>>>>>>>         Ms.push_back(std::move(M));
>>>>>>>
>>>>>>>         // Add the set to the JIT with the resolver we created above
>>>>>>> and a newly
>>>>>>>         // created SectionMemoryManager.
>>>>>>>         return CompileLayer.addModuleSet(std::move(Ms),
>>>>>>>
>>>>>>>  make_unique<SectionMemoryManager>(),
>>>>>>>                                          std::move(Resolver));
>>>>>>>     }
>>>>>>>
>>>>>>>     JITSymbol findSymbol(const std::string Name) {
>>>>>>>         std::string MangledName;
>>>>>>>         raw_string_ostream MangledNameStream(MangledName);
>>>>>>>         Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
>>>>>>>         return CompileLayer.findSymbol(MangledNameStream.str(),
>>>>>>> true);
>>>>>>>     }
>>>>>>>
>>>>>>>     void removeModule(ModuleHandle H) {
>>>>>>>         CompileLayer.removeModuleSet(H);
>>>>>>>     }
>>>>>>> };
>>>>>>>
>>>>>>> const std::string FUNC_NAME = "someFunction";
>>>>>>>
>>>>>>> void runTest() {
>>>>>>>     llvm::LLVMContext context;
>>>>>>>     llvm::IRBuilder<> irBuilder{context};
>>>>>>>     KaleidoscopeJIT jit;
>>>>>>>
>>>>>>>     auto module = std::make_unique<llvm::Module>("help", context);
>>>>>>>     module->setDataLayout(jit.getTargetMachine().createDataLayou
>>>>>>> t());
>>>>>>>
>>>>>>>     auto function = llvm::cast<llvm::Function>(mod
>>>>>>> ule->getOrInsertFunction(FUNC_NAME,
>>>>>>>
>>>>>>>        llvm::Type::getInt32Ty(context), nullptr));
>>>>>>>
>>>>>>>     auto block = llvm::BasicBlock::Create(context, "functionBody",
>>>>>>> function);
>>>>>>>     irBuilder.SetInsertPoint(block);
>>>>>>>
>>>>>>>     irBuilder.CreateRet(llvm::ConstantInt::get(context,
>>>>>>> llvm::APInt(32, 1, true)));
>>>>>>>     jit.addModule(std::move(module));
>>>>>>>
>>>>>>>     llvm::JITSymbol symbol = jit.findSymbol(FUNC_NAME);
>>>>>>>
>>>>>>>     //Just to ensure that the symbol is in fact valid (symbol
>>>>>>> evaluates to true during execution)
>>>>>>>     if(!symbol) {
>>>>>>>         throw std::runtime_error("Symbol not found");
>>>>>>>     }
>>>>>>>
>>>>>>>     //when uncommented, the throw statement does NOT cause a SIGSEGV.
>>>>>>>     //throw std::runtime_error("This should not crash.");
>>>>>>>     uint64_t ptr = symbol.getAddress();
>>>>>>>     //HOWEVER... a SIGSEGV occurs during stack-unwinding while
>>>>>>> throwing the exception below.
>>>>>>>     //Hence, the call to symbol.getAddress() must be causing some
>>>>>>> kind of memory corruption.
>>>>>>>     //My guess is that it's clobbering the stack.
>>>>>>>     throw std::runtime_error("This should not crash but does
>>>>>>> anyway.");
>>>>>>>
>>>>>>>     std::cout << "Ptr is " << ptr << "\n";
>>>>>>>
>>>>>>>     int (*someFuncPtr)() = reinterpret_cast<int (*)()>(ptr);
>>>>>>>     //int (*someFuncPtr)() = (int (*)())ptr;
>>>>>>>
>>>>>>>     int returnValue = someFuncPtr();
>>>>>>>
>>>>>>>     std::cout << "Return value is: " << returnValue << "\n";
>>>>>>>
>>>>>>> }
>>>>>>>
>>>>>>> int main(int argc, char **argv) {
>>>>>>>
>>>>>>>     llvm::InitializeNativeTarget();
>>>>>>>     llvm::InitializeAllAsmPrinters();
>>>>>>>
>>>>>>>     try {
>>>>>>>         runTest();
>>>>>>>
>>>>>>>         //NOTE:  if LLVM is compiled without -DLLVM_USE_SANITIZER:STRING=Address,
>>>>>>> the last throw in runTest() does not cause
>>>>>>>
>>>>>>>         //a SIGSEGV, however this throw will.
>>>>>>>
>>>>>>>         //throw std::runtime_error("This should not crash but does
>>>>>>> anyway.");
>>>>>>>     } catch(std::runtime_error &e) {
>>>>>>>         std::cout << "Exception caught: " << e.what() << "\n";
>>>>>>>     }
>>>>>>>
>>>>>>>     llvm::llvm_shutdown();
>>>>>>>     return 0;
>>>>>>> }
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> LLVM Developers mailing list
>>>>>>> llvm-dev at lists.llvm.org
>>>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170501/cee425a7/attachment-0001.html>


More information about the llvm-dev mailing list