[llvm-dev] Possible stack corruption during call to JITSymbol::getAddress()
Lang Hames via llvm-dev
llvm-dev at lists.llvm.org
Sun Apr 16 21:44:28 PDT 2017
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/unwind-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/t
>> est.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<SectionMemoryMana
>> ger>(),
>> 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().createDataLayout());
>>
>> 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/20170416/394e7c37/attachment.html>
More information about the llvm-dev
mailing list