crash in JIT when running the inliner

Hi,

Today I've been trying to debug a weird bug that makes JIT crash with certain code and when using the inliner. This may sound weird, but if I disable the inliner, it doesn't crash.
I include an example gdb dump below. Does something looks wrong? Do you think it's a bug in JIT or it's just some other piece of code that is writing on the JIT memory?.. I don't really know how to debug this..

Any help/tips/whatever would be greatly appreciated.

Thanks,
Nuno

Hi,

Today I've been trying to debug a weird bug that makes JIT crash with
certain code and when using the inliner. This may sound weird, but if I
disable the inliner, it doesn't crash.
I include an example gdb dump below. Does something looks wrong? Do you
think it's a bug in JIT or it's just some other piece of code that is
writing on the JIT memory?.. I don't really know how to debug this..

my guess is that the code you are jitting is scribbling over
memory.

Any help/tips/whatever would be greatly appreciated.

Try running under valgrind.

Ciao,

Duncan.

Today I've been trying to debug a weird bug that makes JIT crash with
certain code and when using the inliner. This may sound weird, but if I
disable the inliner, it doesn't crash.
I include an example gdb dump below. Does something looks wrong? Do you
think it's a bug in JIT or it's just some other piece of code that is
writing on the JIT memory?.. I don't really know how to debug this..

my guess is that the code you are jitting is scribbling over
memory.

ok, so, my previous code was making bad things, because it was writing the bitcode to file after each function translation. The problem is that WriteBitcodeToFile() releases the memory and thus the 2nd compilation would have pointers to IR that had been already freed.
After fixing this problem in my code, I still get the very same problem: the program crashes when I run the inliner. Running valgrind on the program without the inliner doesn't show any error. If I run the program with the inliner (just uncoment 1 line), valgrind gives a few errors.

Example of one of the errors:

==11384== Invalid read of size 4
==11384== at 0x54B6F04: llvm::StringMapEntryBase::getKeyLength() const (StringMap.h:47)
==11384== by 0x59C6CFD: llvm::Value::getNameStr() const (Value.cpp:162)
==11384== by 0x544FE54: llvm::Value::getName() const (Value.h:110)
==11384== by 0x55E7DA8: (anonymous namespace)::JITResolver::JITCompilerFn(void*) (JITEmitter.cpp:269)
==11384== by 0x54AA47B: X86CompilationCallback2 (X86JITInfo.cpp:350)
==11384== by 0x54AA0C8: (within /usr/local/lib/php/extensions/no-debug-non-zts-20071006/phpllvm.so)
==11384== by 0x8F74D78: ???
==11384== by 0x55E15BF: llvm::JIT::runFunction(llvm::Function*, std::vector<llvm::GenericValue, std::allocator<llvm::GenericValue> > const&) (JIT.cpp:323)
==11384== by 0x544D9B6: phpllvm::execute(_zend_op_array*) (phpllvm_execute.cpp:200)
==11384== by 0x8FA3365: ???
==11384== by 0x55E15BF: llvm::JIT::runFunction(llvm::Function*, std::vector<llvm::GenericValue, std::allocator<llvm::GenericValue> > const&) (JIT.cpp:323)
==11384== by 0x544D9B6: phpllvm::execute(_zend_op_array*) (phpllvm_execute.cpp:200)
==11384== Address 0x5ec7778 is 0 bytes inside a block of size 32 free'd
==11384== at 0x402266C: operator delete(void*) (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==11384== by 0x54C5034: __gnu_cxx::new_allocator<llvm::SDValue>::deallocate(llvm::SDValue*, unsigned) (new_allocator.h:96)
==11384== by 0x54C505E: std::_Vector_base<llvm::SDValue, std::allocator<llvm::SDValue> >::_M_deallocate(llvm::SDValue*, unsigned) (stl_vector.h:133)
==11384== by 0x54C5097: std::_Vector_base<llvm::SDValue, std::allocator<llvm::SDValue> >::~_Vector_base() (stl_vector.h:119)
==11384== by 0x54C50F9: std::vector<llvm::SDValue, std::allocator<llvm::SDValue> >::~vector() (stl_vector.h:272)
==11384== by 0x5683471: llvm::SelectionDAGLowering::~SelectionDAGLowering() (SelectionDAGISel.cpp:496)
==11384== by 0x567683D: llvm::SelectionDAGISel::BuildSelectionDAG(llvm::SelectionDAG&, llvm::BasicBlock*, std::vector<std::pair<llvm::MachineInstr*, unsigned>, std::allocator<std::pair<llvm::MachineInstr*, unsigned> > >&, llvm::FunctionLoweringInfo&) (SelectionDAGISel.cpp:5252)
==11384== by 0x56768C0: llvm::SelectionDAGISel::SelectBasicBlock(llvm::BasicBlock*, llvm::MachineFunction&, llvm::FunctionLoweringInfo&, std::vector<std::pair<llvm::MachineInstr*, unsigned>, std::allocator<std::pair<llvm::MachineInstr*, unsigned> > >&, llvm::RecyclingAllocator<llvm::BumpPtrAllocator, llvm::SDNode, 136, 4>&) (SelectionDAGISel.cpp:5469)
==11384== by 0x5676A14: llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function&, llvm::MachineFunction&, llvm::FunctionLoweringInfo&) (SelectionDAGISel.cpp:5452)
==11384== by 0x5677609: llvm::SelectionDAGISel::runOnFunction(llvm::Function&) (SelectionDAGISel.cpp:4904)
==11384== by 0x54C4BCC: (anonymous namespace)::X86DAGToDAGISel::runOnFunction(llvm::Function&) (X86ISelDAGToDAG.cpp:123)
==11384== by 0x59A59CF: llvm::FPPassManager::runOnFunction(llvm::Function&) (PassManager.cpp:1260)

Does this error makes sense to anyone?

Thanks,
Nuno

Hi,

So I found what's problem that has been bugging me. The main problem is that the inliner deletes internal functions that are no longer called, even if there's still a reference to those functions in the JIT stub->function map (leaving dangling pointers behind).

Let me expand:
1) I JIT compile a few functions (with getPointerFunction()). As I'm using the JIT engine in lazy mode, this code contains a function call to a stub of function foo
2) I run the inliner optimization and it decides to inline all the calls to function foo
3) the inliner pass decides that the function can be removed because it is internal and there are no references left
4) I run one of the previously JITed functions (that contain a call to a stub of foo) and it crashes, because it tries to compile a function that no longer lives in memory

So, is this explanation clear enough for you to understand the problem?
Do you think this bug can be fixed (by making the inliner pass JIT-aware or by injecting dependencies in the call graph from the JIT stub map)?

Thank you,
Nuno