Skip to content

Commit

Permalink
Fix ROOT-8523: exception catching in jitted code.
Browse files Browse the repository at this point in the history
Another manifestation of this problem is that, in the broken case, the stack
trace shown by gdb (or any other tools) will appear corrupted.

The problem appears when the memory allocated for 2 or more module happen to
interleaves.  This could happens because the memory needed for large module is
acquired in chunks and the attempt to keep it close together (giving a hint to
mmap) is not enough, since it has not way to guarante there is no hole nor that
memory in between we later be release (and then re-used for a subsequent
module's code).

In more details:

It turns out that the piecemeal allocation of memory for the code segment
produced by the JIT can lead to a situation, highly dependent on memory usage of
the current process and interleaving of JIT actions vs user allocations, where
the code segment for multiple llvm JITed module can be interleaved.

Where this causes a problem is that the code in libgcc that deal with stack
unwinding (in particular the function Unwind_Find_FDE), assumes that the code
segment for the modules/libraries are *not* overlapping/interleaved and thus is
testing against just the start address of the code segment for the
modules/libraries assuming it is enough to search for the right module for a
given 'current instructions address'.

In the particular case reported by Chris, one module, corresponding to the user
scripts, ends up being composed of 906 code segments (each requires an
individual memory allocation).  There are also several small modules, one for
each of the TFile plugin handler routines.   In the failing case, the 906 code
segments happens to be allocated in (at least) two separate memory areas
(around 0x7ffff087e000 and around 0x7ffff729ef50) while the code segment for
P020_TRFIOFile ends up in 0x7ffff729a000 (in the middle of the other two
addresses).

The user code has the simple structure:
   - cling wrapping function
   - gallery_t user function containing a try catch
   - parameterSetID user methods, inlineable
   - gallery::Handle<art::TriggerResults>::throwHandleWhyFailed_() which throw
     an exception.

When Unwind_Find_FDE walks up the stack and reaches gallery_t, the instruction
address is 0x7ffff72a2d92 and the searching algorithm then thinks that this
correspond to a function in the P020_TRFIOFile module and then proceed to
discover that there is no such function and no exception handler and thus 'ends'
the search (and terminate the program).
  • Loading branch information
pcanal committed Jan 9, 2017
1 parent 4e902bd commit 3f74182
Showing 1 changed file with 31 additions and 0 deletions.
31 changes: 31 additions & 0 deletions interpreter/llvm/src/lib/ExecutionEngine/SectionMemoryManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup,
//
// FIXME: Initialize the Near member for each memory group to avoid
// interleaving.
// Note: this would not be sufficient as the Near member is just a hint
// to mmap.
std::error_code ec;
sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize,
&MemGroup.Near,
Expand All @@ -94,6 +96,35 @@ uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup,
return nullptr;
}

// To be sure that there is no interleaving, enforce the monotonic decrease
// of the memory adddress. This is required by libgcc's _Unwind_Find_FDE
// which does a linear search (of the top level dwarf objects) and note in the code
// "Note that pc_begin is sorted descending, and we expect objects to be
// non-overlapping. "
if (MemGroup.Near.base() && (size_t)MB.base() > (size_t)MemGroup.Near.base()) {
SmallVector<sys::MemoryBlock, 16> MemToDelete;
while ((size_t)MB.base() > (size_t)MemGroup.Near.base()) {
// Hold on to the memory until we get an acceptable one
// just so that we are not given it back.
MemToDelete.push_back(MB);
MB = sys::Memory::allocateMappedMemory(RequiredSize,
&MemGroup.Near,
sys::Memory::MF_READ |
sys::Memory::MF_WRITE,
ec);
if (ec) {
for (sys::MemoryBlock &Block : MemToDelete) {
sys::Memory::releaseMappedMemory(Block);
}
// FIXME: Add error propagation to the interface.
return nullptr;
}
}
for (sys::MemoryBlock &Block : MemToDelete) {
sys::Memory::releaseMappedMemory(Block);
}
}

// Save this address as the basis for our next request
MemGroup.Near = MB;

Expand Down

0 comments on commit 3f74182

Please sign in to comment.