2

将程序从 linux 移植到 solaris,使用 solarisstudio 12.3 构建它。

它有以下定义:

typedef std::list<ISocketMultiplexerJob *> CSocketJobs;
typedef CSocketJobs::iterator CJobCursor;

CSocketJobs   m_socketJobs;

这个代码:

CSocketMultiplexer::CJobCursor
CSocketMultiplexer::nextCursor(CJobCursor cursor)
{
    CLock lock(m_mutex);

        CJobCursor j = m_socketJobs.end();
        CJobCursor i = cursor;
        while (++i != m_socketJobs.end()) {
            if (*i != m_cursorMark) {   // CRASHES HERE!!
                j = i;

                // move our cursor just past the job
                m_socketJobs.splice(++i, m_socketJobs, cursor);
                break;                                                  
             }
        }
        return j;
  }

它在上面指出的行崩溃,因为:

(dbx) print i
i = {
    _C_node = (nil)
}

看起来“++i”迭代从列表中消失了,但是针对 m_socketJobs.end() 的测试没有看到它并让它通过。需要帮助调试,例如,如何以更能识别 c++ 的方式分析 dbx 中的 *i?

nextCursor() 的调用者在这个片段中,<>:

                // collect poll entries
                if (m_update) {
                       m_update = false;
                       pfds.clear();
                       pfds.reserve(m_socketJobMap.size());

                       CJobCursor cursor    = newCursor();
                       CJobCursor jobCursor = nextCursor(cursor);
                       while (jobCursor != m_socketJobs.end()) {
                               ISocketMultiplexerJob* job = *jobCursor;
                               if (job != NULL) {
                                    pfd.m_socket = job->getSocket();
                                    pfd.m_events = 0;
                                    if (job->isReadable()) {
                                            pfd.m_events |= IArchNetwork::kPOLLIN;
                                    }
                                    if (job->isWritable()) {
                                            pfd.m_events |= IArchNetwork::kPOLLOUT;
                                    }
                                    pfds.push_back(pfd);
                               }                               
                               jobCursor = nextCursor(cursor);  //FATAL CALL
                       }

这是函数 newCursor():

CSocketMultiplexer::CJobCursor
   CSocketMultiplexer::newCursor() {  
     CLock lock(m_mutex);
     return m_socketJobs.insert(m_socketJobs.begin(), m_cursorMark);
}

我做了一些研究,发现 newCursor()/nextCursor() 排序工作和不工作......也许另一个线程正在损害上下文。在下面的示例中(嵌入在我的程序中)“CJobCursor c = newCursor();”的第一个 init 很健壮,我可以插入“c= nextCursor(c);”行 在我的程序中的任何地方,它都不会崩溃。但是下一个带有评论“BAD”的有缺陷,并在第二个 nexCursor() 调用中崩溃。我觉得这很有趣,但还没有解释。我认为我需要在整个程序中继续测试,因为上下文正在扼杀东西。你怎么看?

void
CSocketMultiplexer::serviceThread(void*)
{
    std::vector<IArchNetwork::CPollEntry> pfds;
    IArchNetwork::CPollEntry pfd;

                    CJobCursor c    = newCursor();
                    CJobCursor j = nextCursor(c);
                    c = nextCursor(c);
                    c = nextCursor(c);

    // service the connections
    for (;;) {
            CThread::testCancel();

            // wait until there are jobs to handle
            {
                    CLock lock(m_mutex);
                    while (!(bool)*m_jobsReady) {
                            m_jobsReady->wait();
                    }
            }

            // lock the job list
            lockJobListLock();
            lockJobList();

            // collect poll entries
            if (m_update) {
                    m_update = false;
                    pfds.clear();
                    pfds.reserve(m_socketJobMap.size());

                    CJobCursor cursor    = newCursor();  //BAD, Ill-fated object
                    CJobCursor jobCursor = nextCursor(cursor);
                    c = nextCursor(c);
                    cursor = nextCursor(cursor);        // SEGV's here
                    while (jobCursor != m_socketJobs.end()) {
                            ISocketMultiplexerJob* job = *jobCursor;
                            if (job != NULL) {
                                    pfd.m_socket = job->getSocket();
                                    pfd.m_events = 0;
                                    if (job->isReadable()) {
                                            pfd.m_events |= IArchNetwork::kPOLLIN;
                                    }
                                    if (job->isWritable()) {
                                            pfd.m_events |= IArchNetwork::kPOLLOUT;
                                    }
                                    pfds.push_back(pfd);
                            }                               
                            c = nextCursor(c);
                            jobCursor = nextCursor(cursor);
                    }
                    c = nextCursor(c);
                    deleteCursor(cursor);
            }
4

1 回答 1

1

看起来“++i”迭代从列表中消失了

不,我认为它看起来像一个无效的迭代器(可能是默认构造的),而不是一个过去的迭代器。

Astd::list<T>::iterator 需要能够再次通过列表向后递减,因此它不能指向 null,否则一旦到达末尾并且它变为 null,您就不能再向后退了。通常,一个过去的std::list迭代器必须指向一个哨兵节点。

所以你i没有指向任何元素,m_socketJobs这意味着无论你增加多少次都无法到达,所以m_socketJobs.end()总是如此。ii != m_socketJobs.end()

尝试添加assert( i != CJobCursor() )到函数的顶部,我敢打赌它会在那里中止,因为我认为您使用无效的迭代器调用了该函数。

您不应该仅仅因为它是 true 就假设(++i != m_socketJobs.end())迭代器是可取消引用的。

于 2014-12-18T00:58:04.853 回答