为啥我的字符串分配会导致分段错误?

Posted

技术标签:

【中文标题】为啥我的字符串分配会导致分段错误?【英文标题】:Why is my string assignment causing a segmentation fault?为什么我的字符串分配会导致分段错误? 【发布时间】:2011-08-30 13:14:36 【问题描述】:

我试图消除段错误的常见原因,例如取消引用空指针,但我很难过。此错误不会出现在我的调试模式下的测试机器上,但会出现在我的生产机器上发布编译。两者都设置为 /O0 以消除这种可能性。当我注释掉字符串分配时,段错误消失了,现在我只需要了解发生了什么,以便我可以修复它。

可能有一些更明显的东西,但另一个复杂的问题是该代码正在由内核模式应用程序调用,而供应商关于为系统编写安全代码的唯一说明是“每个需要任何东西的函数来自操作系统或必须等待来自操作系统的任何东西都不起作用”(逐字)。

union 
    REAL_T real[8];
    char   byte[64];
 fileName;

void transferFilenames () 
    string tempname;

    // This is from an api I must use, it retrieves values from NVRAM on
    // an accessory board.  Specifically it will return 8 REAL_T values
    // and store them starting at &filename.real[0], inp/outpArray are 
    // globals defined elsewhere.
    inpArray.I7_ARRAY.INDEX = 2903;
    inpArray.I7_ARRAY.LEN = 8;
    inpArray.I7_ARRAY.Z_PAR_PTR = &fileName.real[0];
    b_array ( READ_CYCLE_PARAMS, &status, &inpArray, &outpArray );

    // if status != 0, there was an error
    if ( status == 0 ) 
        // there is no guarantee of being null terminated
        fileName.byte[63] = 0;

        /* This test code didn't fix the problem
        int i;
        char myStr[64];
        for ( i = 0; i < 64; i++ )
            myStr[i] = fileName.byte[i];
        if ( myStr[0] != '\0' )
            string mystring( myStr ); // seg fault
        */
        tempname.assign( fileName.byte ); // Throws seg fault
        // tempname.assign( &fileName.byte[0] ); // try to be more explicit

        // controlBlock is a global class defined elsewhere
        controlBlock->setFileName ( tempname, ISINPUT);
     else 
        controlBlock->setFileName( "BAD", ISINPUT );
    
    return;

当我重载控制块以直接获取 char* controlBlock-&gt;setFileName( &amp;fileName.byte[0] ) 并完全删除字符串分配时,分段错误消失了。重载所做的只是将 char* 分配给本地字符串并调用常规方法。

我在幕后缺少什么?

【问题讨论】:

你的核心文件/调试器说fileName.byte是什么时候崩溃? @MarkB 程序崩溃时没有创建转储文件。实时系统不支持实时调试,而宽松的计时系统不存在此错误。 我之前已经注释掉了这个块中的所有代码,除了 assign 语句和段错误仍然存​​在。将其反转并仅留下注释的分配删除了段错误。 你也在其他地方使用 std::string 吗?它确实在堆上分配,而不是在堆栈上。 添加到 murrekatt 的评论中,并在我的回答之后我的:子句 需要操作系统中的任何内容或必须等待操作系统中的任何内容的每个功能都将不起作用阻止您使用大量 C++ 库。有问题的系统很可能按照malloc (size_t) kill (0, SEGBUS); 的方式实现malloc 【参考方案1】:

问题可能不在对tempname.assign() 的调用中。流水线可能会导致对恶魔真正所在位置的一些错误报告。这句话让我觉得恶魔在别处:

当我重载控制块以直接获取 char* controlBlock->setFileName( &fileName.byte[0] ) 并完全删除字符串分配时,分段错误消失了。

在一种情况下,您将std::string 传递给setFileName,在另一种情况下传递char*。换个试试

controlBlock->setFileName ( tempname, ISINPUT);

controlBlock->setFileName ( tempname.c_str(), ISINPUT);

附录 问题很可能在于使用std::string,句号。如果保留的大小太小,std::string::assign() 将调用malloc。使保留大小足够大也可能不起作用;这可能只是将malloc 调用推入构造函数。使用动态分配内存的东西不符合子句每个需要操作系统提供任何东西或必须等待操作系统提供任何东西的功能都将不起作用

事实上,这个子句很可能会阻止在这台机器上使用大量的 C++ 库。 C++ 库在分配和释放内存方面非常松散,std::string 做了很多。

【讨论】:

使用 tempname.c_str() 仍然会抛出段错误。 我也同意问题可能不在 assign() 处,但它是我可以缩小范围以重现错误的唯一代码行。 鉴于您在其他地方的 cmets,您是否有计时错误?您是否需要以某种方式等到b_array 完成其工作?要注意的另一件事是,设置一个联合成员然后访问另一个成员,严格来说是非法的(这是未定义的行为)。虽然这个技巧确实适用于大多数机器和大多数编译器,但总有一种奇怪的野兽在它不起作用的地方。也许你已经抓住了这样一只野兽的尾巴。 最后一个想法:std::string::assign() 将调用malloc。这是否安全,特别是考虑到“需要操作系统提供任何内容或必须等待操作系统提供任何内容的每个功能 将无法工作”? 我不需要等待 b_array (这是一个阻塞调用)。您对字符串分配 内部 malloc 的评论很可能是解释。默认情况下,我们得到 15 个字符,所以我尝试分配越来越小的字符。较小不会产生错误,但较大会产生错误。

以上是关于为啥我的字符串分配会导致分段错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 MPI_Barrier 在 C++ 中会导致分段错误

尝试在函数内动态分配父指针给子指针会导致分段错误

为啥此代码会导致分段错误错误?

为啥这个字符会出现分段错误?

访问全局数组会导致分段错误

为啥释放内存会导致分段错误?