c++通过GDB接收段错误,而不是xCode——需要帮助调试

c++ receives segfault through GDB but not xCode -- need help debugging

本文关键字:xCode 调试 帮助 GDB 通过 段错误 错误 c++      更新时间:2023-10-16

我正在做一个项目,最近开始遇到一个特别严重的段错误。下面是一些背景信息:

1——我有一个"订单"队列,我已经测试了以下内容:a——填充(0个订单、1个订单和多个订单),删除,直到isEmpty()返回true,并用这些结果填充其他队列(这复制了程序的行为)

2——从gdb中找到:

(gdb) run
Starting program: /Users/Nicholas M. Iodice/Dropbox/tufts/noz2/noz2/a.out 
Reading symbols for shared libraries ++......................... done
order added 1
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: 13 at address: 0x0000000000000000
0x0000000100003a66 in Queue::remove (this=0x7fff5fbffaa0) at Queue.cpp:85
85      ElementType retVal = front->order;
(gdb) where
#0  0x0000000100003a66 in Queue::remove (this=0x7fff5fbffaa0) at Queue.cpp:85
#1  0x0000000100002c08 in Packer::packItem (this=0x7fff5fbffaa0, time=1) at Packer.cpp:88
#2  0x0000000100002e3f in Packer::update (this=0x7fff5fbffaa0, time=1) at Packer.cpp:131
#3  0x0000000100002e9c in PackerManager::update (this=0x7fff5fbffaa0, i=1) at Packer.cpp:295
#4  0x0000000100001ffa in Manager::run (this=0x7fff5fbff830, careAboutSupreme=false) at Manager.cpp:126
#5  0x000000010000511a in main (argc=0, argv=0x7fff5fbffb48) at main.cpp:173
(gdb) 

"订单添加1"是我添加的一些日志记录,当我的"Fetcher"类向"PackerManager"类发送订单时发生,PackerManager类决定向哪个"Packer"对象添加订单。我修改了我的代码,以便所有订单都通过一个"Packer"对象路由,用于调试目的。

3——这意味着当"Packer"对象调用packItem(它将从我的队列中调用remove())时,该队列中只有一个订单。我已经在这些课程之外测试了这个,它工作得很好。

    以下是一些相关代码:
从"队列"

Queue::Queue()
{
    front = NULL;
    back = NULL;
    //head = NULL;
    //tail = NULL;
    count = 0;
}
//instert to back of queue
void Queue::insert(ElementType order)
{
    if(isEmpty()){
        back = new Node;
        back->order = order;
        back->next = NULL;
        front = back;
    }else{
        Node* tmp = new Node;
        tmp->order = order;
        back->next = tmp;
        back = back->next;
        back->next = NULL;
    }
    count++;
}
//checks if head & tail = NULL
bool Queue::isEmpty()
{
    if(front == NULL && back == NULL){
        return true;
    }
    return false;
}

抛出这行segfault: "ElementType retVal = front->order;"

ElementType Queue::remove()
{
    if(isEmpty()){
        cout << "ntYou cannot remove from an empty Queue... Exiting.nn";
        exit(1);
    }
    ElementType retVal = front->order;
    //delete front;
    if(front == back){
        front = NULL;
        back = NULL;
    }else{
        front = front->next;
    }
    count --;
    return retVal;
}

这段代码从队列中调用remove。它调用的是"regularOrders"

//retreives next order to begin packing
void Packer::packItem(int time)
{
    if( careAboutSupreme && !supremeOrders.isEmpty() ){
        orderBeingPacked = supremeOrders.remove();
        orderBeingPackedStartTime = time;
    }else if( careAboutSupreme && isDelayOrderWaiting ){
        orderBeingPacked = orderBeingDelayed;
        orderBeingPackedStartTime = orderBeingDelayedStart + delayDuration;
        delayDuration = 0;
        isDelayOrderWaiting = false;
    }else if( !regularOrders.isEmpty() ){
        orderBeingPacked = regularOrders.remove();
        orderBeingPackedStartTime = time;
    }
}

同样,队列通过这个值i = 1和i> 1的测试:

#if Q
    Queue q1;
    Queue q2;
    for(int i=0 ; i<5 ; i++){
        Order o;
        q1.insert(o);
    }
    while(!q1.isEmpty()){
        q2.insert(q1.remove());
    }
    sortQueueByOrderNumber(q2);
    while(!q2.isEmpty()){
        q2.remove();
    }
    cout << "Expecting to exit now" << endl;
    q2.remove();
#endif
void sortQueueByOrderNumber(Queue q)
{
    if(q.getCount() == 0){
        return;
    }
    int cnt = q.getCount();
    Order* orderArray = new Order[cnt];
    Order tmpOrder;
    //put orders into array -- after this they are in order, but in an array
    while(q.getCount() != 0){
        tmpOrder = q.remove();
        orderArray[tmpOrder.orderNum-1] = tmpOrder;
    }
    //now we stuff em back into the queue, in order!
    for(int i=0 ; i<cnt ; i++){
        tmpOrder = orderArray[i];
        q.insert(tmpOrder);
    }
    delete[] orderArray;
}

请让我知道我还能提供什么。

编辑:它看起来像一个空指针不是问题在这里:我试着添加这个:

ElementType retVal;
if(front == NULL){
    cout <<"oops!";
}else{
    retVal = front->order;
}

代码仍然落入分配retVal = front->顺序。所以front != NULL,然而,它认为front->顺序是一个不好的内存位置。

编辑2:好吧,这很奇怪。当使用clang++编译时,它实际上可以工作(如果我之前另有说明,请原谅),只是不是g++。怎么啦?

编辑3 好了,我把这些文件scp到另一台机器上并试着运行它。现在我在g++和clang++中都遇到了分段错误,但是,在与队列完全无关的完全不同的区域。

是否有其他东西我应该看看,可能会导致更广泛的内存问题?

段错误现在发生时,试图更新一个包装器对象。代码如下,它无法更新时间(this->time = time)——我认为这不应该发生,这就是为什么我认为可能有一个更大的问题。另外,我检查了GDB,但这个->时间不是NULL。

void Packer::update(int time)
{
    this->time = time;
    //if orderNum = 0 we havent gotten a real order yet. This is the default from the constructor for Order
    if(orderBeingPacked.orderNum == 0){
        packItem(time);
    }

isEmpty()返回false 保证front不是NULL

Put assert in isEmpty() like:

bool Queue::isEmpty()
{
    if(front == NULL || back == NULL){
        assert(front == NULL);
        assert(back == NULL);
        return true;
    }
    return false;
}

同样,你是否在构造函数中将frontback初始化为NULL ?


编辑:

另一件要检查的事情是你的订单号是否超过sortQueueByOrderNumber:

中的临时数组
void sortQueueByOrderNumber(Queue q)
{
    ...
    int cnt = q.getCount();
    Order* orderArray = new Order[cnt];
    Order tmpOrder;
    //put orders into array -- after this they are in order, but in an array
    while(q.getCount() != 0){
        tmpOrder = q.remove();
        assert(tmpOrder.orderNum >= 1);       // <<<<<<<<<<<<<<<<<<<<<
        assert(tmpOrder.orderNum-1 < cnt);    // <<<<<<<<<<<<<<<<<<<<<
        orderArray[tmpOrder.orderNum-1] = tmpOrder;
    }
    ...
}

EDIT2:另一个潜在的缺陷:确保在复制队列结构时实现赋值操作符和复制构造函数:

Queue::Queue(const Queue &other) :
  front(NULL),
  back(NULL),
  count(0)
{
  Node *node = other.front;
  while (node != NULL)
  {
    insert(node->order);
    node = node->next;
  }
}

否则,例如,当调用sortQueueByOrderNumber(Queue q)时(假设您没有使其成为Maciek B指出的引用),您将共享(因为等待默认复制构造函数工作)多个queue实例之间的队列节点,或者更糟的是,您将在一个对象上的所有节点上调用delete超出范围(例如在sortQueueByOrderNumber的末尾),而另一个Queue实例仍然指向(删除)Node对象。

删除注释掉了吗?

ElementType retVal = front->order;
//delete front;
if(front == back){
    front = NULL;
    back = NULL;
}else{
    front = front->next;
}
你不应该删除front,然后使用front->next。试试这个:
ElementType retVal = front->order;
Node* x = front;
if(front == back){
    front = NULL;
    back = NULL;
}else{
    front = front->next;
}
delete x;
编辑:

方法sortQueueByOrderNumber按值接受Queue参数,因此frontback的任何更改都不会存储在原始Queue对象中。将签名更改为:

void sortQueueByOrderNumber(Queue& q)

如果你仍然有问题,那么使用valgrind。它应该找到这些内存问题,或者至少为您指明正确的方向。