Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Post-Mortem: Segment Fault from Unchecked Vector Iterator Erasure

Tech 2
class FdMonitor::Internal {
public:
    void unregister(int fd);
    void registerFd(int fd);
    std::vector<int> awaitEvents();
    
private:
    std::vector<int> watchList_;
    std::mutex listMutex_;
    std::pair<int, int> signalPipe_;
};

The fault manifested in the unregister() routine:

void FdMonitor::Internal::unregister(int fd)
{
    std::lock_guard<std::mutex> lock(listMutex_);
    watchList_.erase(std::find(watchList_.begin(), watchList_.end(), fd));
}

When the file descriptor is absent from the container, std::find returns watchList_.end(). Passing this past-the-end iterator to erase() triggers undefined behavior, typically manifesting as a segmentation fault during the subsequent memory relocation.

The robust implementation validates the iterator before mutation:

void FdMonitor::Internal::unregister(int fd)
{
    std::lock_guard<std::mutex> lock(listMutex_);
    auto target = std::find(watchList_.begin(), watchList_.end(), fd);
    if (target == watchList_.end()) {
        return;
    }
    watchList_.erase(target);
}

Analyzing the core dump reveals the execution path leading to the crash:

#0  __memcpy_avx_unaligned_erms ()
#1  std::__copy_move<true, true, std::random_access_iterator_tag>::__copy_m<int>
    (__first=0x4, __last=0x0, __result=0x0)
#2  std::__copy_move_a2<true, int*, int*> (__first=0x4, __last=0x0, __result=0x0)
#3  std::__copy_move_a1<true, int*, int*> (__first=0x4, __last=0x0, __result=0x0)
#4  std::__copy_move_a<...> (__first=<error: Cannot access memory at address 0x4>,
    __last=non-dereferenceable iterator, __result=non-dereferenceable iterator)
#5  std::move<...> (__first=<error: Cannot access memory at address 0x4>,
    __last=non-dereferenceable iterator, __result=non-dereferenceable iterator)
#6  std::vector<int>::_M_erase (this=0x55a8f87e22d0,
    __position=non-dereferenceable iterator)
#7  std::vector<int>::erase (this=0x55a8f87e22d0,
    __position=non-dereferenceable iterator)
#8  FdMonitor::Internal::unregister (this=0x55a8f87e22d0, fd=0)

The stack trace exposes the mechanism of failure. At frame #6, std::vector::_M_erase invokes the move operation to shift elements leftward, filling the gap at the erased position. The implemantation conceptually executes:

_GLIBCXX_MOVE3(__position + 1, end(), __position);

When __position equals end() (address 0x0 in the optimized implementation), incrementing it yields 0x4 (frame #5 and below). This invalid source pointer propagates down to __copy_move, where memmove attempts to read from unmapped memory, generating the SIGSEGV.

The critical observation lies in frame #1: both __last and __result hold null pointers, while __first contains the corrupted address 0x4. This pattern—where the destination and end-boundary pointers are null but the source pointer is a small non-zero value—strongly indicates that the erasure algorithm received the container's end iterator as the deletion point.

In std::vector's internal architecture, _M_erase expects a dereferenceable iterator within the valid element range [begin(), end()). When this precondition is violated, the pointer arithmetic inside the move routine produces addresses out side the allocaetd buffer, causing the memory subsystem to abort the process during the block-copy operation.

Always validate search results against the container's end iterator before passing them to modifier algorithms.

Tags: C++

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.