我有一个python代码库,有时会调用C ++程序来处理繁重的工作负载。一个这样的代码必须在大型文本文件中计算一定大小的所有kmers。对于读取的每一行,它都会创建一个临时索引来存储每个kmer的位置。这是处理每一行的函数:
void process_read(char* read, int num) {
int l = strlen(read) ;
std::string seq(read) ;
// index kmers
std::unordered_map<std::string, std::vector<int>> index ;
for (int i = 0 ; i <= l - 1 - 15 ; i++) {
std::string k = seq.substr(i, 15) ;
if (global_index->find(k) == global_index->end()) {
continue ;
}
if (index.find(k) == index.end()) {
index.insert(std::make_pair(k, std::vector<int>(1, i))) ;
} else {
index[k].push_back(i) ;
}
}
// 50+ lines of code commented out. It returns here
}
代码每次到达特定的输入行时就会崩溃:
ACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCAAACCATAACCCTAAACCTCACGATAACCCAAACCATCACCAAAAAAAAAAAAAACACACCTACCGAAACCAACAACATA
在此行的kmers中,只有AAAAAAAAAAAAAAC
和CAAAAAAAAAAAAAA
使其索引。由于某些我不了解的原因,尝试插入CAAAAAAAAAAAAAA
时,代码总是崩溃。我想这些键按顺序插入unordered_map
中是有问题的。将功能更改为此将仍然会在插入第二个键时导致相同的崩溃:
void process_read(char* read, int num) {
std::unordered_map<std::string, std::vector<int>> index ;
index.insert(std::make_pair("AAAAAAAAAAAAAAC", std::vector<int>(1, 2))) ;
index.insert(std::make_pair("CAAAAAAAAAAAAAA", std::vector<int>(1, 2))) ;
}
现在,此功能显然不像原始状态那样不访问任何全局状态,因此问题必须出在这些特定的键上(请注意,其中一个是另一个的循环移位,因此使用的哈希函数可能对此并不满意) ;但是,将这段代码放在程序的开头或编写仅执行此操作的另一个小程序似乎并不能重现崩溃,所以我真的很困惑。
任何建议都值得赞赏。
更新: 我在崩溃期间得到了这个堆栈跟踪。由于某些原因,我不能使用gdb进行调试,所以我想这是我将要获得的最好的结果。但是不知道该怎么解释。
*** Error in `src/python/kmer/c_counter.out': malloc(): memory corruption (fast): 0x0000000001eac690 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f189daa47e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x82651)[0x7f189daaf651]
/lib/x86_64-linux-gnu/libc.so.6(__libc_malloc+0x54)[0x7f189dab1184]
/usr/lib/x86_64-linux-gnu/libstdc++.so.6(_Znwm+0x18)[0x7f189e3a3e78]
/src/python/kmer/c_counter.out[0x41c5e4]
/src/python/kmer/c_counter.out[0x4146ea]
/src/python/kmer/c_counter.out[0x41453a]
/src/python/kmer/c_counter.out[0x41035b]
/src/python/kmer/c_counter.out[0x40b3d8]
/src/python/kmer/c_counter.out[0x40940a]
/src/python/kmer/c_counter.out[0x404528]
/src/python/kmer/c_counter.out[0x404f9d]
/src/python/kmer/c_counter.out[0x405f42]
/src/python/kmer/c_counter.out[0x4063d6]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f189da4d830]
/src/python/kmer/c_counter.out[0x403b39]
======= Memory map: ========
00400000-00440000 r-xp 00000000 00:2f 546796 src/python/kmer/c_counter.out
0063f000-00640000 rw-p 0003f000 00:2f 546796 src/python/kmer/c_counter.out
014a0000-01ebf000 rw-p 00000000 00:00 0 [heap]
7f1898000000-7f1898021000 rw-p 00000000 00:00 0
7f1898021000-7f189c000000 ---p 00000000 00:00 0
7f189da2d000-7f189dbed000 r-xp 00000000 fc:00 1439150 /lib/x86_64-linux-gnu/libc-2.23.so
7f189dbed000-7f189dded000 ---p 001c0000 fc:00 1439150 /lib/x86_64-linux-gnu/libc-2.23.so
7f189dded000-7f189ddf1000 r--p 001c0000 fc:00 1439150 /lib/x86_64-linux-gnu/libc-2.23.so
7f189ddf1000-7f189ddf3000 rw-p 001c4000 fc:00 1439150 /lib/x86_64-linux-gnu/libc-2.23.so
7f189ddf3000-7f189ddf7000 rw-p 00000000 00:00 0
7f189ddf7000-7f189de0d000 r-xp 00000000 fc:00 1439041 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f189de0d000-7f189e00c000 ---p 00016000 fc:00 1439041 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f189e00c000-7f189e00d000 rw-p 00015000 fc:00 1439041 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f189e00d000-7f189e115000 r-xp 00000000 fc:00 1439141 /lib/x86_64-linux-gnu/libm-2.23.so
7f189e115000-7f189e314000 ---p 00108000 fc:00 1439141 /lib/x86_64-linux-gnu/libm-2.23.so
7f189e314000-7f189e315000 r--p 00107000 fc:00 1439141 /lib/x86_64-linux-gnu/libm-2.23.so
7f189e315000-7f189e316000 rw-p 00108000 fc:00 1439141 /lib/x86_64-linux-gnu/libm-2.23.so
7f189e316000-7f189e488000 r-xp 00000000 fc:00 671990 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f189e488000-7f189e688000 ---p 00172000 fc:00 671990 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f189e688000-7f189e692000 r--p 00172000 fc:00 671990 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f189e692000-7f189e694000 rw-p 0017c000 fc:00 671990 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f189e694000-7f189e698000 rw-p 00000000 00:00 0
7f189e698000-7f189e6be000 r-xp 00000000 fc:00 1439146 /lib/x86_64-linux-gnu/ld-2.23.so
7f189e878000-7f189e89f000 rw-p 00000000 00:00 0
7f189e8bc000-7f189e8bd000 rw-p 00000000 00:00 0
7f189e8bd000-7f189e8be000 r--p 00025000 fc:00 1439146 /lib/x86_64-linux-gnu/ld-2.23.so
7f189e8be000-7f189e8bf000 rw-p 00026000 fc:00 1439146 /lib/x86_64-linux-gnu/ld-2.23.so
7f189e8bf000-7f189e8c0000 rw-p 00000000 00:00 0
7ffea4907000-7ffea4929000 rw-p 00000000 00:00 0 [stack]
7ffea49b6000-7ffea49b9000 r--p 00000000 00:00 0 [vvar]
7ffea49b9000-7ffea49bb000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
答案 0 :(得分:2)
将功能更改为此将在插入第二个键时仍然导致相同的崩溃:
[...]
将此代码放在程序的开头或编写另一个仅执行此操作的小程序似乎无法重现崩溃,所以我真的很困惑。
std::unordered_map
没有相关的全局状态,可以在“如果我一开始就运行此测试函数就一切正常”和“如果以后运行此测试函数,则地图崩溃”之间改变。由于程序中其他地方的未定义行为,您的内存损坏了-您所做的观察是您可以获得的最有力的证据。
答案 1 :(得分:0)
函数签名表明您不一定有一个以空结尾的字符串(一个以\ 0作为最后一个字符的字符串)。
但是您不能这样对待(您应该使用以num作为参数的变体)。我怀疑这种模式会在其他地方重复出现,并且有时会破坏您的记忆。
如果我是我,我将使用Valgrind或其他内存分析工具构建二进制文件并再次运行。它将捕获发生错误的访问。
您使用unordered_map的方式对我来说不错。