在大型程序中很难跟踪SIGSEGV分段错误

时间:2012-04-26 06:16:20

标签: c++ segmentation-fault sigsegv heap-corruption

我为发布一个多次询问的问题而道歉(我刚读了10页)但我找不到解决方案。

我正在分别使用OpenGL和Portaudio开发多线程图形/音频程序。音频线程使用我正在为音频处理对象制作的库。 SIGSEGV可能有20%的时间发生(调试时更少),并且在使用新的流信息(采样率,矢量大小等)重置音频对象的负载时发生。 Code :: blocks调试器将故障定义为每次故障发生时来自不同位置。

这是音频处理循环:

while(true){
    stream->tick();
    menuAudio.tick();
    {
        boost::mutex::scoped_lock lock(*mutex);
        if(channel->AuSwitch.resetAudio){
            uStreamInfo newStream(channel->AuSwitch.newSrate, 
                 channel->AuSwitch.newVSize, channel->AuSwitch.newChans);
            menuAudio.resetStream(&newStream);
            (*stream) = newStream;
            menuAudio.resetStream(stream);
            channel->AuSwitch.resetAudio = false;
        }
    }
}

它检查来自图形线程的信息,告诉它重置音频并运行补丁对象的resetStream函数,它基本上是音频对象的向量并运行它们中的每一个:

void uPatch::resetStream(uStreamInfo* newStream)
{
    for(unsigned i = 0; i < numObjects; ++i){
/*This is where it reports this error: Program received signal SIGSEGV,  
Segmentation fault. Variables: i = 38, numObjects = 43 */
        objects[i]->resetStream(newStream); 
    }
}  

有时候它会说SIGSEGV来自不同的位置,但是由于它在使用调试器运行时很少发生故障,这是我唯一可能发生的事情。

由于对象太多,我不会发布所有重置代码,但作为示例:

void uSamplerBuffer::resetStream(uStreamInfo* newStream)
{
    audio.set(newStream, false);
    control.set(newStream, true);
    stream = newStream;
    incr = (double)buffer->sampleRate / (double)stream->sampleRate;
    index = 0;
}

audio.set代码为:

void uVector::set(uStreamInfo* newStream, bool controlVector)
{
    if(vector != NULL){
        for(unsigned i = 0; i < stream->channels; ++i)
            delete[] vector[i];
        delete vector;
    }
    if(controlVector)
        channels = 1;
    else
        channels = newStream->channels;
    vector = new float*[channels];
    for(unsigned i = 0; i < channels; ++i)
        vector[i] = new float[newStream->vectorSize];
    stream = newStream;
    this->flush();
}

我最好的猜测是它是一个堆栈溢出问题,因为它只发生在大量对象上,并且它们各自运行良好。也就是说,音频流本身运行良好,并以类似的方式运行。 objects[i]->resetStream(newStream);的循环也应该在每个成员函数之后弹出堆栈,所以我不明白为什么它会SIGSEGV。

任何意见/建议?

修改

这是一个错误删除的内存问题。应用程序验证程序在错误点处使其成为错误,而不是从其他位置发现的偶然故障。问题在于uVector流设置功能,因为该类的意图是使用stream->channels的多维数组的音频矢量,可以选择使用单维数组来控制信号。当删除以重新分配内存时,我意外地设置了所有uVector而不管要使用stream-&gt;删除的类型。通道。

if(vector != NULL){
    for(unsigned i = 0; i < stream->channels; ++i)
        delete[] vector[i];
    delete vector;
}

应该在哪里:

if(vector != NULL){
    for(unsigned i = 0; i < this->channels; ++i)
        delete[] vector[i];
    delete vector;
}

所以它正在删除它本不应该访问的内存,这会损坏堆。令我惊讶的是,段错误并没有更频繁地发生,因为这似乎是一个严重的问题。

2 个答案:

答案 0 :(得分:0)

我可以节省内存,你可以尝试像Electric Fence(或DUMA,它的孩子这样的工具来查看它是否是你执行的超出限定的写入。 通常这些类型的段错误(非永久性的,有时只发生)是先前缓冲区溢出的遗留物。

你也可以尝试Valgrind,它与上面的2个工具具有相同的效果,以及较慢执行的成本。

此外,尝试检查发生这种情况时您正在访问的错误地址的值:它看起来有效吗?有时,一个值可以提供有关您遇到的错误的信息(通常:尝试访问0x12处的内存,其中0X12是循环中的计数器:))。

对于堆栈溢出...我建议尝试增加被控制线程的堆栈大小,看看错误是否被复制。如果没有经过一系列的尝试,你就发现了问题。

至于windows:

答案 1 :(得分:0)

我认为你刚刚将其作为Stack Overflow问题。 :)

严肃地说,像这样的错误通常是访问不再存在的内存位置的对象的结果。在您的第一个代码块中,我看到您在堆栈上创建newStream,其范围仅限于它所属的if语句。然后将其复制到解除引用的指针(*stream)。是否为uStreamInfo类定义了安全且正确的分配?如果没有明确定义,编译器将静静地为对象赋值提供成员副本,这对于intdouble这样的简单原语是可以的,但对于动态分配的对象则不一定。 *stream可能会留下指向由newStream分配的内存的指针,但在newStream超出范围时已被释放。现在该RAM上的数据仍然存在,并且暂时看起来是正确的,但是被释放的内存,它可能在任何时候都被破坏,就像在崩溃之前一样。 :)

我建议密切关注何时分配和取消分配对象,以及哪些对象拥有哪些对象。您还可以采用分治方法,对大部分代码进行注释并逐渐启用更多代码,直到您再次看到崩溃开始。该错误可能出现在最近重新启用的代码中。