【问题标题】:Not sure where the segmentation fault is不确定分段错误在哪里
【发布时间】:2017-02-13 13:35:57
【问题描述】:

我在尝试编译 C++ 程序时遇到分段错误问题,但不确定问题出在哪里。我怀疑问题出在 .find() ..... 可能是迭代器运算符

以下是test01.cpp的一部分,我在其中运行它来测试代码并使用打印语句找出问题所在:

bool confirmEverythingMatches(const btree<long>& testContainer, const set<long>& stableContainer) {
  cout << "Confirms the btree and the set " 
          "contain exactly the same values..." << endl;


  for (long i = kMinInteger; i <= kMaxInteger; i++) {
    cout << "Start of for-loop to find iterator for comparisons..." << endl;

    if (stableContainer.find(i) != stableContainer.end()) {
      cout << "can find i (" << i << ") in stableContainer!" << endl;
    } else {
      cout << "cannot find i (" << i << ") in stableContainer!" << endl;
    }

    cout << "In between finding i in stable and testContainers..." << endl;

    if (testContainer.find(i) != testContainer.end()) {
      cout << "can find i (" << i << ") in testContainer!" << endl;
    } else {
      cout << "cannot find i (" << i << ") in testContainer!" << endl;
    }

    cout << "Before assigning the find to boolean variables..." << endl;

    bool foundInTree = (testContainer.find(i) != testContainer.end());
    cout << "testContainer.find(i) != testContainer.end()" << endl;


    bool foundInSet = (stableContainer.find(i) != stableContainer.end());
    cout << "stableContainer.find(i) != stableContainer.end()" << endl;

    if (foundInTree != foundInSet) {
      cout << "- btree and set don't contain the same data!" << endl; 
      cout << "Mismatch at element: " << i << endl;
      return false;
    } else {cout << "foundInTree == foundInSet!!!" << i << endl;}
  }
  cout << "- btree checks out just fine." << endl;

  return true;
}

}  // namespace close


/**
 * Codes for testing various bits and pieces. Most of the code is commented out
 * you should uncomment it as appropriate.
 **/
int main(void) {

  // initialise random number generator with 'random' seed
  initRandom();

  cout << "after initRandom().." << endl;

  // insert lots of random numbers and compare with a known correct container
  btree<long> testContainer(99);

  cout << "after specifying max node elements in testContainer.." << endl;

  set<long> stableContainer;

  cout << "after constructing stableContainer.." << endl;

  insertRandomNumbers(testContainer, stableContainer, 1000000);

  cout << "after inserting random numbers into testContainer and for success inserts, also into stableContainer.." << endl;

  btree<long> btcpy = testContainer;

  cout << "after copy assigning a copy of testContainer to btcopy.." << endl;

  confirmEverythingMatches(btcpy, stableContainer);

  cout << "after confirming everything internally matches between testContainer and stableContainer.." << endl;

  return 0; 
}

我在运行程序时得到的输出(编译时没问题)是这样的:

Confirms the btree and the set contain exactly the same values...
Start of for-loop to find iterator for comparisons...
cannot find i (1000000) in stableContainer!
In between finding i in stable and testContainers...
ASAN:DEADLYSIGNAL
=================================================================
==7345==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000018 (pc 0x000108d132a8 bp 0x000000000000 sp 0x7fff56eee6f0 T0)
    #0 0x108d132a7 in btree<long>::find(long const&) const (test01+0x1000022a7)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (test01+0x1000022a7) in btree<long>::find(long const&) const
==7345==ABORTING
Abort trap: 6

当我尝试在另一台机器上运行它时,我也遇到了这个错误:

==29936==ERROR: AddressSanitizer failed to allocate 0x200000 (2097152) bytes of SizeClassAllocator32: 12

发现进入find()的时候会出现segmentation fault:

/**
 * Identical in functionality to the non-const version of find,
 * save the fact that what's pointed to by the returned iterator
 * is deemed as const and immutable.
 *
 * @param elem the client element we are trying to match.
 * @return an iterator to the matching element, or whatever the
 *         const end() returns if no such match was ever found.
 */
template<typename T> typename btree<T>::const_iterator
btree<T>::find(const T& elem) const {
    std::cout << "CONST ITERATOR'S FIND" << std::endl;

Node *tmp_ = root_;
std::cout << "1" << std::endl;

while(true) {
std::cout << "2" << std::endl;
size_t i;

std::cout << "3" << std::endl;
// go through all elements from root to tail
for (i = 0; i < tmp_->__occupied_size_; ++i) {

    std::cout << "4" << std::endl;

    if (tmp_->__elem_[i] == elem) {

        std::cout << "5" << std::endl;

        // find the elem, return an iterator
        return const_iterator(tmp_, i, this);

        std::cout << "6" << std::endl;

    } else if (tmp_->__elem_[i] > elem) {

        std::cout << "7" << std::endl;

        // elem is not in current Node, go to descendants
        // for the elem.
        if (tmp_->__descendants_ == nullptr) {

            std::cout << "8" << std::endl;
            return cend();
            std::cout << "9" << std::endl;

        } else {

            std::cout << "10" << std::endl;
            tmp_ = tmp_->__descendants_[i];
            std::cout << "11" << std::endl;
            break;
                }
            }
        }
        // handling boundaries cases
        if (i == tmp_->__occupied_size_) {
            std::cout << "12" << std::endl;
            if (tmp_->__descendants_[i] == nullptr) {
                std::cout << "13" << std::endl;
                return cend();
                std::cout << "14" << std::endl;
            } else {
                std::cout << "15" << std::endl;
                tmp_ = tmp_->__descendants_[i];
            }
        }
    }
}

这个查找的打印语句是:

CONST ITERATOR'S FIND
1
2
3
4
4
7
10
11
2
3
4
7
10
11
ASAN:DEADLYSIGNAL

【问题讨论】:

  • 这个问题的代码太多了,你能不能试着把它剪成minimal reproducible example
  • 请将您的问题edit 提供给minimal reproducible example。包含的链接提供了有关如何执行此操作的帮助。
  • 剪掉了
  • 您尝试了多少调试?打印出来并没有多大帮助,但调试会显示程序和数据的状态,这对于找出问题更有用。
  • 0x000000000018 看起来您正试图在 btree::find 中使用空指针。使用调试器找出确切的位置。

标签: c++ iterator segmentation-fault find b-tree


【解决方案1】:

好的,那么基于这个find函数的实现,我想问题可能出在

if (tmp_->__descendants_ == nullptr) {
    std::cout << "8" << std::endl;
    return cend();
    std::cout << "9" << std::endl;
} else {
    std::cout << "10" << std::endl;
    tmp_ = tmp_->__descendants_[i];
    std::cout << "11" << std::endl;
    break;
}

然后

// handling boundaries cases
if (i == tmp_->__occupied_size_) {
    std::cout << "12" << std::endl;
    if (tmp_->__descendants_[i] == nullptr) {
        std::cout << "13" << std::endl;
        return cend();
        std::cout << "14" << std::endl;
    } else {
        std::cout << "15" << std::endl;
        tmp_ = tmp_->__descendants_[i];
    }
}

所以,您正在检查 tmp->__descendants_ 是否不为空。如果不是,那么你设置 tmp_ = tmp_->descendants_[i];

注意:你只是检查 __descendants_ 指针是否为空,你没有检查 __descendants_ [i] 是否为空!

如果 tmp->__descendants_[i] 为空(或超出了后代数组)怎么办?

如果该值为 null,则 tmp_->occupied_size_ 可能会给您提供段错误。

注意 2:由于某种原因,您使用相同的索引“i”来迭代 __elem_ 和 __descendants_。我不确定,后代是如何创建的,但这可能也是一个问题。

【讨论】:

  • 实现的哪一部分?我有 Btree.h、Btree.tem 和 Btree_iterator.h 和 Btree_iterator.tem
  • Btree 是你的实现吗?我不确定 tem 文件是什么。也许只是 btree.h 就足够了(尤其是 find() 实现)。
  • 这有帮助吗?后代_[i] 会导致段错误吗?
【解决方案2】:

这就是调试器存在的原因。在调试器中运行你的程序,让程序失败,然后调试器会告诉你出错的地方和原因。

看起来您可能有很多代码需要浏览,这里没有人真正想要这样做,因为这不是一个简洁的问题。

祝你好运!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-05
    • 1970-01-01
    • 2016-07-09
    • 2015-12-31
    • 2013-04-03
    • 1970-01-01
    相关资源
    最近更新 更多