You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker容器中多线程AlignGraph程序抛出std::length_error求助

问题定位与修复建议:Docker中AlignGraph触发std::length_error异常

问题概述

在Docker容器中运行多线程C++基因组比对工具AlignGraph时,触发std::length_error异常,异常发生在某线程的std::string::append字符串操作环节。该工具在容器外本地运行正常,已排查编译问题、尝试小输入数据,错误仍触发。

运行命令

Starting program: /opt/AlignGraph/AlignGraph/AlignGraph --read1 sample1.fasta --read2 sample2.fasta --contig /data/run/plentyofbugs_out/assembly/contigs.fasta --genome /data/reference_genome/GCA_013814885.1_ASM1381488v1_genomic.fna --distanceLow 100 --distanceHigh 1000 --extendedContig extendedContigs.fa --remainingContig remainingContigs.fa

调试栈回溯信息

Thread 3 "AlignGraph" received signal SIGABRT, Aborted.
[Switching to Thread 0x7ffff72016c0 (LWP 91)]
__pthread_kill_implementation (no_tid=0, signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:44
warning: 44     ./nptl/pthread_kill.c: No such file or directory
(gdb) backtrace
#0  __pthread_kill_implementation (no_tid=0, signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:44
#1  __pthread_kill_internal (signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:78
#2  __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3  0x00007ffff7b3f26e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4  0x00007ffff7b228ff in __GI_abort () at ./stdlib/abort.c:79
#5  0x00007ffff7ddeffe in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x00007ffff7df3e9c in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
#7  0x00007ffff7ddea49 in std::terminate() () from /lib/x86_64-linux-gnu/libstdc++.so.6
#8  0x00007ffff7df4128 in __cxa_throw () from /lib/x86_64-linux-gnu/libstdc++.so.6
#9  0x00007ffff7de2381 in std::__throw_length_error(char const*) () from /lib/x86_64-linux-gnu/libstdc++.so.6
#10 0x0000555555562b51 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_check_length (__s=0x555555580071 "basic_string::append", __n2=6, __n1=0,
    this=0x7ffff7200b30) at /usr/include/c++/13/bits/allocator.h:184
#11 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::append (__s=0x5555555802ce ".delta", this=0x7ffff7200b30) at /usr/include/c++/13/bits/basic_string.h:1473
#12 std::operator+<char, std::char_traits<char>, std::allocator<char> > (__rhs=0x5555555802ce ".delta", __lhs=...) at /usr/include/c++/13/bits/basic_string.h:3690
#13 task1 (arg=<optimized out>) at AlignGraph.cpp:3640
#14 0x00007ffff7b96a94 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:447
#15 0x00007ffff7c23c3c in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

对应代码片段(AlignGraph.cpp第3631-3656行)

3631 //NUCMER
3632                 for(chromosomeID = 0; chromosomeID < ins.numChromosomes; chromosomeID ++)
3633                 {
3634                         command = "nucmer tmp/_genome." + itoa(chromosomeID) + ".fa tmp/_contigs.fa -p tmp/_contigs_genome." + itoa(chromosomeID) + " > nucmer_doc.txt 2> nucmer_doc.txt";
3635                         if(system(command.c_str()) != 0)
3636                         {
3637                                 command = "touch tmp/_contigs_genome." + itoa(chromosomeID) + ".delta";
3638                                 system(command.c_str());
3639                         }
3640                         command = "tmp/_contigs_genome." + itoa(chromosomeID) + ".delta";
3641                         delta2psl(command);
3642                 }
3643         }
3644         else
3645         {
3646                 for(chromosomeID = 0; chromosomeID < ins.numChromosomes; chromosomeID ++)
3647                 {
3648                         command = "pblat tmp/_genome." + itoa(chromosomeID) + ".fa tmp/_contigs.fa -noHead tmp/_contigs_genome." + itoa(chromosomeID) + ".psl -fastMap -threads=8 > blat_doc.txt 2> blat_doc.txt";
3649                         if(system(command.c_str()) != 0)
3650                         {
3651                                 command = "blat tmp/_genome." + itoa(chromosomeID) + ".fa tmp/_contigs.fa -noHead tmp/_contigs_genome." + itoa(chromosomeID) + ".psl -fastMap > blat_doc.txt 2> blat_doc.txt";
3652                                 if(system(command.c_str()) != 0) {cout << "BLAT CALL FAILED!" << endl; exit(-1);}
3653                         }
3654                 }
3655         }
3656 }

根因分析

核心问题在于代码中使用了非标准C++函数itoa:

  1. itoa并非C++标准库函数,属于平台相关的扩展函数。本地环境(可能是Windows或特定Linux发行版)的libc提供了该函数,但Docker容器内的glibc通常没有实现itoa,或者其实现返回的是指向栈内存的指针。
  2. 多线程环境下,栈内存会被频繁覆盖,当itoa返回的栈指针在后续字符串拼接(std::string::append)时被访问,会读取到无效的内存内容,导致字符串长度校验失败,触发std::length_error异常。
  3. 本地运行正常是因为本地libc的itoa实现可能使用了静态缓冲区或其他安全机制,而容器内的实现不具备该特性。

代码修复方案

将所有itoa(chromosomeID)替换为标准C++字符串转换方法std::to_string(chromosomeID),同时确保代码头部包含<string>头文件(如果尚未包含)。

修复后的核心代码片段:

3634                         command = "nucmer tmp/_genome." + std::to_string(chromosomeID) + ".fa tmp/_contigs.fa -p tmp/_contigs_genome." + std::to_string(chromosomeID) + " > nucmer_doc.txt 2> nucmer_doc.txt";
// ...
3637                                 command = "touch tmp/_contigs_genome." + std::to_string(chromosomeID) + ".delta";
// ...
3640                         command = "tmp/_contigs_genome." + std::to_string(chromosomeID) + ".delta";
// ...
3648                         command = "pblat tmp/_genome." + std::to_string(chromosomeID) + ".fa tmp/_contigs.fa -noHead tmp/_contigs_genome." + std::to_string(chromosomeID) + ".psl -fastMap -threads=8 > blat_doc.txt 2> blat_doc.txt";
// ...
3651                                 command = "blat tmp/_genome." + std::to_string(chromosomeID) + ".fa tmp/_contigs.fa -noHead tmp/_contigs_genome." + std::to_string(chromosomeID) + ".psl -fastMap > blat_doc.txt 2> blat_doc.txt";

调试步骤

  • 验证itoa可用性:在Docker容器内编译并运行如下测试程序,检查itoa是否存在及返回值是否有效:
    #include <stdio.h>
    int main() {
        int num = 1;
        char* str = itoa(num);
        printf("%s\n", str);
        return 0;
    }
    
  • 替换itoa后重新编译AlignGraph,在容器内运行测试,确认异常是否消失。
  • 使用gdb在容器内调试,查看替换前itoa返回的字符串内容,确认是否存在内存无效的情况。

最小复现示例建议

  • 编写多线程测试程序,模拟原代码的字符串拼接逻辑:
    #include <iostream>
    #include <string>
    #include <pthread.h>
    
    void* thread_func(void* arg) {
        int id = *(int*)arg;
        std::string cmd = "test." + itoa(id) + ".txt"; // 使用itoa
        std::cout << cmd << std::endl;
        return nullptr;
    }
    
    int main() {
        pthread_t threads[5];
        int ids[5] = {0,1,2,3,4};
        for(int i=0; i<5; i++) {
            pthread_create(&threads[i], nullptr, thread_func, &ids[i]);
        }
        for(int i=0; i<5; i++) {
            pthread_join(threads[i], nullptr);
        }
        return 0;
    }
    
    在Docker容器内编译运行该程序,观察是否触发类似的std::length_error异常。
  • 使用最小规模的基因组和contig文件,仅保留NUCMER分支的逻辑,简化原程序进行测试。

内容的提问来源于stack exchange,提问作者somilsharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 10:29:55