【问题标题】:c++ seg fault issuec ++ seg错误问题
【发布时间】:2012-05-08 21:17:17
【问题描述】:

我正在开发一个使用一些外部 C 库的 C++ 程序。据我所知,这不是问题的原因,问题出在我的 C++ 代码上。该程序运行良好,在我的测试数据集上没有任何错误或任何内容,但是在浏览了几乎整个完整数据集之后,我得到了一个段错误。运行 GDB 会给我这个段错误:

(gdb) 运行 -speciesMain=allMis1 -speciesOther=anoCar2 -speciesMain=allMis1 -speciesOther=anoCar2 /hive/data/genomes/allMis1/bed/lastz.anoCar2/mafRBestNet/*.maf.gz 启动程序:/cluster/home/jstjohn/bin/mafPairwiseSyntenyDecay -speciesMain=allMis1 -speciesOther=anoCar2 -speciesMain=allMis1 -speciesOther=anoCar2 /hive/data/genome s/allMis1/bed/lastz.anoCar2/mafRBestNet/*.maf.gz 从子进程 3718 分叉后分离。 程序收到信号 SIGSEGV,分段错误。 来自 /usr/lib64/libstdc++.so.6 的 __gnu_cxx::__exchange_and_add(int volatile*, int) () 中的 0x0000003009cb7672 (gdb) 向上 #1 0x0000003009c9db59 in std::basic_string, std::allocator >::~basic_string() () 来自 /usr/lib64/libstdc++.so.6 (gdb) 向上 #2 0x00000000004051e7 在 PairAlnInfo::~PairAlnInfo (this=0x7fffffffcd70, __in_chrg=) at mafPairwiseSyntenyDecay.cpp:37 (gdb) 向上 #3 0x0000000000404eb0 在 main (argc=2, argv=0x7fffffffcf78) 在 mafPairwiseSyntenyDecay.cpp:260

我的 PairAlnInfo 类的双重释放似乎正在发生一些事情。奇怪的是我没有定义析构函数,也没有用new 分配任何东西。我在 linux 机器上用 g++44 和 g++4.1.2 都试过了,结果是一样的。

为了让事情变得更奇怪,在我的 linux 机器上(有更多可用的 RAM 和所有东西,并不是说 RAM 是这个程序的问题,但它是一个强大的系统)在程序到达之前,如上所述发生了段错误循环打印输出。在我使用 g++ 或 clang++ 的更小的 macbook air 上,程序仍然会出现段错误,但直到 after 结果打印出来,就在主函数的最后一个 return(0) 之前,它不会这样做.这是使用 Mac 的默认 g++4.2 编译后,在我的 Mac 上运行在同一文件上的 GDB 跟踪的样子:

(更多结果)... 98000 27527 162181 0.83027 99000 27457 161467 0.829953 100000 27411 160794 0.829527 程序收到信号 EXC_BAD_ACCESS,无法访问内存。 原因:KERN_INVALID_ADDRESS 地址:0x00004a2c00106077 0x00007fff9365a6e5 在 std::string::_Rep::_M_dispose () (gdb) 向上 #1 0x00007fff9365a740 在 std::basic_string, std::allocator >::~basic_string () (gdb) 向上 #2 0x0000000100003938 in main (argc=1261, argv=0x851d5fbff533) at mafPairwiseSyntenyDecay.cpp:301 (gdb)

如果您没有注意到我发帖的时间,现在大约是凌晨 2:30...我已经解决这个问题大约 10 个小时了。非常感谢您花时间看这个并帮助我!复制我的情况的代码和一些说明如下。

如果您有兴趣下载和安装整个依赖项,请下载我的 KentLib 存储库,make 在基本目录中,然后转到examples/mafPairwiseSyntenyDecay 并在那里运行make。导致我正在讨论的错误的一个示例(相当大)是此处可用的 gzip 文件:100Mb file that the program crashes on。然后使用这些参数-speciesMain=allMis1 -speciesOther=anoCar2 anoCar2.allMis1.rbest.maf.gz 执行程序。

/**
 * mafPairwiseSyntenyDecay
 *  Author: John St. John
 *  Date: 4/26/2012
 *  
 *  calculates the mean synteny decay in different range bins
 *
 *
 */

//Kent source C imports
extern "C" {

#include "common.h"
#include "options.h"
#include "maf.h"

}

#include <map>
#include <string>
#include <set>
#include <vector>
#include <sstream>
#include <iostream>

//#define NDEBUG
#include <assert.h>

using namespace std;


/*
Global variables
 */

class PairAlnInfo {
public:
  string oname;
  int sstart;
  int send;
  int ostart;
  int oend;
  char strand;
  PairAlnInfo(string _oname,
      int _sstart, int _send,
      int _ostart, int _oend,
      char _strand):
        oname(_oname),
        sstart(_sstart),
        send(_send),
        ostart(_ostart),
        oend(_oend),
        strand(_strand){}
  PairAlnInfo():
    oname("DUMMY"),
    sstart(-1),
    send(-1),
    ostart(-1),
    oend(-1),
    strand(-1){}

};

vector<string> &split(const string &s, char delim, vector<string> &elems) {
  stringstream ss(s);
  string item;
  while(getline(ss, item, delim)) {
    elems.push_back(item);
  }
  return(elems);
}


vector<string> split(const string &s, char delim) {
  vector<string> elems;
  return(split(s, delim, elems));
}

#define DEF_MIN_LEN (200)
#define DEF_MIN_SCORE (200)

typedef map<int,PairAlnInfo> PairAlnInfoByPos;
typedef map<string, PairAlnInfoByPos > ChromToPairAlnInfoByPos;
ChromToPairAlnInfoByPos pairAlnInfoByPosByChrom;


void usage()
/* Explain usage and exit. */
{
  errAbort(
      (char*)"mafPairwiseSyntenyDecay -- Calculates pairwise syntenic decay from maf alignment containing at least the two specified species.\n"
      "usage:\n"
      "\tmafPairwiseSyntenyDecay [options] [*required options] file1.maf[.gz] ... \n"
      "Options:\n"
      "\t-help\tPrints this message.\n"
      "\t-minScore=NUM\tMinimum MAF alignment score to consider (default 200)\n"
      "\t-minAlnLen=NUM\tMinimum MAF alignment block length to consider (default 200)\n"
      "\t-speciesMain=NAME\t*Name of the main species (exactly as it appears before the '.') in the maf file (REQUIRED)\n"
      "\t-speciesOther=NAME\t*Name of the other species (exactly as it appears before the '.') in the maf file (REQUIRED)\n"
  );
}//end usage()


static struct optionSpec options[] = {
    /* Structure holding command line options */
    {(char*)"help",OPTION_STRING},
    {(char*)"minScore",OPTION_INT},
    {(char*)"minAlnLen",OPTION_INT},
    {(char*)"speciesMain",OPTION_STRING},
    {(char*)"speciesOther",OPTION_STRING},
    {NULL, 0}
}; //end options()

/**
 * Main function, takes filenames for paired qseq reads
 * and outputs three files.
 */
int iterateOverAlignmentBlocksAndStorePairInfo(char *fileName, const int minScore, const int minAlnLen, const string speciesMain, const string speciesOther){
  struct mafFile * mFile = mafOpen(fileName);
  struct mafAli * mAli;

  //loop over alignment blocks
  while((mAli = mafNext(mFile)) != NULL){
    struct mafComp *first = mAli->components;
    int seqlen = mAli->textSize;
    //First find and store set of duplicates in this block
    set<string> seen;
    set<string> dups;
    if(mAli->score < minScore || seqlen < minAlnLen){
      //free here and pre-maturely end
      mafAliFree(&mAli);
      continue;
    }

    for(struct mafComp *item = first; item != NULL; item = item->next){
      string tmp(item->src);
      string tname = split(tmp,'.')[0];
      if(seen.count(tname)){
        //seen this item
        dups.insert(tname);
      }else{
        seen.insert(tname);
      }
    }
    for(struct mafComp *item1 = first; item1->next != NULL; item1 = item1->next){
      //stop one before the end
      string tmp1(item1->src);
      vector<string> nameSplit1(split(tmp1,'.'));
      string name1(nameSplit1[0]);
      if(dups.count(name1) || (name1 != speciesMain && name1 != speciesOther)){
        continue;
      }

      for(struct mafComp *item2 = item1->next; item2 != NULL; item2 = item2->next){
        string tmp2(item2->src);
        vector<string> nameSplit2(split(tmp2,'.'));
        string name2 = nameSplit2[0];
        if(dups.count(name2) || (name2 != speciesMain && name2 != speciesOther)){
          continue;
        }

        string chr1(nameSplit1[1]);
        string chr2(nameSplit2[1]);
        char strand;
        if(item1->strand == item2->strand)
          strand = '+';
        else
          strand = '-';

        int start1,end1,start2,end2;

        if(item1->strand == '+'){
          start1 = item1->start;
          end1 = start1 + item1->size;
        }else{
          end1 = item1->start;
          start1 = end1 - item1->size;
        }

        if(item2->strand == '+'){
          start2 = item2->start;
          end2 = start2+ item2->size;
        }else{
          end2 = item2->start;
          start2 = end2 - item2->size;
        }

        if(name1 == speciesMain){
          PairAlnInfo aln(chr2,start1,end1,start2,end2,strand);
          pairAlnInfoByPosByChrom[chr1][start1] = aln;
        }else{
          PairAlnInfo aln(chr1,start2,end2,start1,end1,strand);
          pairAlnInfoByPosByChrom[chr2][start2] = aln;
        }

      } //end loop over item2
    } //end loop over item1
    mafAliFree(&mAli);
  }//end loop over alignment blocks

  mafFileFree(&mFile);
  return(0);
}


int main(int argc, char *argv[])
/* Process command line. */
{
  optionInit(&argc, argv, options);
  if(optionExists((char*)"help") || argc <= 1){
    usage();
  }
  int minAlnScore = optionInt((char*)"minScore",DEF_MIN_SCORE);
  int minAlnLen = optionInt((char*)"minAlnLen",DEF_MIN_LEN);

  string speciesMain(optionVal((char*)"speciesMain",NULL));
  string speciesOther(optionVal((char*)"speciesOther",NULL));

  if(speciesMain.empty() || speciesOther.empty())
    usage();

  //load the relevant alignment info from the maf(s)
  for(int i = 1; i<argc; i++){
    iterateOverAlignmentBlocksAndStorePairInfo(argv[i], minAlnScore, minAlnLen, speciesMain, speciesOther);
  }

  const int blockSize = 1000;
  const int blockCount = 100;

  int totalWindows[blockCount] = {0};
  int containBreak[blockCount] = {0};

  //we want the fraction of windows of each size that contain a break
  //


  for(ChromToPairAlnInfoByPos::iterator mainChromItter = pairAlnInfoByPosByChrom.begin();
      mainChromItter != pairAlnInfoByPosByChrom.end();
      mainChromItter++){
    //process the alignments shared by this chromosome
    //note that map stores them sorted by begin position
    vector<int> keys;
    for(PairAlnInfoByPos::iterator posIter = mainChromItter->second.begin();
        posIter != mainChromItter->second.end();
        posIter++){
      keys.push_back(posIter->first);
    }

    for(int i = 0; i < keys.size(); i++){
      //first check for trivial window (ie our block)
      PairAlnInfo pi1 = mainChromItter->second[keys[i]];
      assert(pi1.send > pi1.sstart);
      assert(pi1.sstart == keys[i]);
      int numBucketsThisWindow = (pi1.send - pi1.sstart) / blockSize;
      for(int k = 0; k < numBucketsThisWindow && k < blockCount; k++)
        totalWindows[k]++;


      for(int j = i+1; j < keys.size(); j++){

        PairAlnInfo pi2 = mainChromItter->second[keys[j]];

        assert(pi2.sstart == keys[j]);
        assert(pi2.send > pi2.sstart);
        assert(pi2.sstart > pi1.sstart);

        if(pi2.oname == pi1.oname){
          int moreToInc = (pi2.send - pi1.sstart) / blockSize;
          for(int k = numBucketsThisWindow; k < moreToInc && k < blockCount; k++)
            totalWindows[k]++;
          numBucketsThisWindow = moreToInc; //so we don't double count
        }else{

          int numDiscontigBuckets = (pi2.send - pi1.sstart) / blockSize;
          for(int k = numBucketsThisWindow; k < numDiscontigBuckets && k < blockSize; k++){
            containBreak[k]++;
            totalWindows[k]++;
          }
          numBucketsThisWindow = numDiscontigBuckets;
        }
        if((keys[j] - keys[i]) >= (blockSize * blockCount)){
          //i = j;
          break;
        }
      }
    }
  }



  cout << "#WindowSize\tNumContainBreak\tNumTotal\t1-(NumContainBreak/NumTotal)" << endl;
  for(int i = 0; i < blockCount; i++){
    cout << (i+1)*blockSize << '\t';
    cout << containBreak[i] << '\t';
    cout << totalWindows[i] << '\t';
    cout << (totalWindows[i] > 0? 1.0 - (double(containBreak[i])/double(totalWindows[i])): 0) << endl;
  }


  return(0);
} //end main()

【问题讨论】:

  • 肯定看起来像是程序中某处的堆覆盖。可能来自超出范围的访问,仅通过查看源很难找到。

标签: c++ memory-management segmentation-fault


【解决方案1】:

您的问题可能是由于在您看到实际错误之前的某个时间点发生在程序中的内存损坏。

您发布的代码中的一个潜在问题是循环:

 for(int k = numBucketsThisWindow; k<numDiscontigBuckets && k < blockSize; k++){

它使用blockSize 而不是正确的blockCount,这可能导致totalWindows[]containBreak[] 数组溢出。这将覆盖 speciesMainspeciesOther 字符串,以及堆栈上的任何其他内容,这很可能会导致您看到的错误。

【讨论】:

    【解决方案2】:

    尝试在 valgrind 下运行您的程序。这将为您提供可能或实际丢失内存、未初始化等的报告。

    【讨论】:

    • 感谢 valgrind 的建议 @Julian。我不得不选择其他人作为回答的人,因为他实际上发现了我的错误!那就是说我尝试在我的 Mac 上使用 valgrind,如果我正确阅读文档(检查堆栈数组访问越界问题),那将真正拯救我的诊断在 Darwin (--tool=exp-sgcheck) 上不受支持。我确实在我的 linux 机器上运行了这个工具,只是为了看看它将来是否有帮助,它识别出代码中的错误。我以后肯定会使用 valgrind,谢谢!
    • valgrind 摇滚不是吗?从代码中找出错误是一项艰巨的任务,值得称赞。
    • :) valgrind 为我节省了很多时间。我有一个类似的问题。未初始化的变量每次都会在随机的地方导致崩溃。
    猜你喜欢
    • 1970-01-01
    • 2018-10-03
    • 1970-01-01
    • 2012-06-21
    • 2012-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多