调用 free() 时发生混合语言程序崩溃

Posted

技术标签:

【中文标题】调用 free() 时发生混合语言程序崩溃【英文标题】:Mixed-language program crash occurs when free() called 【发布时间】:2012-11-06 05:37:05 【问题描述】:

我有一个程序,其中 C、C++ 和 Fortran 的代码已编译并链接在一起。主函数是用 C++ 编写的,可以在文件testQ.cpp 中找到。 C++ 代码调用文件getqpf.F 中的Fortran 子例程。 getqpf.F 中的子例程调用许多其他文件中的 C 函数。

在 GNU/Linux 上使用 gccgfortran 我已经成功地将程序链接在一起:

 g++ -c test-Q.cpp -I./boost/boost_1_52_0/ -g
 gcc -c paul2.c -g
 gcc -c paul2_L1.c -g
 gcc -c paul6.c -g
 gcc -c paul6_L1.c -g 
 gcc -c fit_slope.c -g
 gfortran -c getqpf.F -g
 g++ -o test-Q test-Q.o paul2.o paul2_L1.o paul6.o paul6_L1.o fit_slope.o getqpf.o -g -lgfortran

程序似乎运行正常。但是,在调用 free() 时它会在终止之前崩溃:

free(x1);

这是程序中的最后一条语句,只有在调用free()时程序才会崩溃。现在x1 是使用以下malloc 创建的:

double *x1;
x1 = (double*)malloc(iXget);

x1 指针被传递给 Fortran 代码,Fortran 子例程将它传递给 C 代码函数。

这是崩溃的输出。这里可能出了什么问题,我该如何调试?我最近安装了valgrind。如何使用它来调试我的程序?

*** glibc detected *** ./test-Q: free(): invalid next size (normal): 0x0000000000f50aa0 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7ae16)[0x7feabf64de16]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x6c)[0x7feabf6520fc]
./test-Q[0x402520]
./test-Q[0x4026b2]
./test-Q[0x401dbd]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7feabf5f430d]
./test-Q[0x401cf9]
======= Memory map: ========
00400000-0040b000 r-xp 00000000 08:11 9714095                            /media/RESEARCH/SAS2-version2/test-Q/test-Q
0060a000-0060b000 r--p 0000a000 08:11 9714095                            /media/RESEARCH/SAS2-version2/test-Q/test-Q
0060b000-0060c000 rw-p 0000b000 08:11 9714095                            /media/RESEARCH/SAS2-version2/test-Q/test-Q
00f39000-00f5a000 rw-p 00000000 00:00 0                                  [heap]
7feab8000000-7feab8021000 rw-p 00000000 00:00 0 
7feab8021000-7feabc000000 ---p 00000000 00:00 0 
7feabf39d000-7feabf3d2000 r-xp 00000000 08:01 18881806                   /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0
7feabf3d2000-7feabf5d1000 ---p 00035000 08:01 18881806                   /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0
7feabf5d1000-7feabf5d2000 r--p 00034000 08:01 18881806                   /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0
7feabf5d2000-7feabf5d3000 rw-p 00035000 08:01 18881806                   /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0
7feabf5d3000-7feabf76c000 r-xp 00000000 08:01 16515356                   /lib/x86_64-linux-gnu/libc-2.13.so
7feabf76c000-7feabf96b000 ---p 00199000 08:01 16515356                   /lib/x86_64-linux-gnu/libc-2.13.so
7feabf96b000-7feabf96f000 r--p 00198000 08:01 16515356                   /lib/x86_64-linux-gnu/libc-2.13.so
7feabf96f000-7feabf970000 rw-p 0019c000 08:01 16515356                   /lib/x86_64-linux-gnu/libc-2.13.so
7feabf970000-7feabf976000 rw-p 00000000 00:00 0 
7feabf976000-7feabf98b000 r-xp 00000000 08:01 16518820                   /lib/x86_64-linux-gnu/libgcc_s.so.1
7feabf98b000-7feabfb8a000 ---p 00015000 08:01 16518820                   /lib/x86_64-linux-gnu/libgcc_s.so.1
7feabfb8a000-7feabfb8b000 r--p 00014000 08:01 16518820                   /lib/x86_64-linux-gnu/libgcc_s.so.1
7feabfb8b000-7feabfb8c000 rw-p 00015000 08:01 16518820                   /lib/x86_64-linux-gnu/libgcc_s.so.1
7feabfb8c000-7feabfc0f000 r-xp 00000000 08:01 16515346                   /lib/x86_64-linux-gnu/libm-2.13.so
7feabfc0f000-7feabfe0e000 ---p 00083000 08:01 16515346                   /lib/x86_64-linux-gnu/libm-2.13.so
7feabfe0e000-7feabfe0f000 r--p 00082000 08:01 16515346                   /lib/x86_64-linux-gnu/libm-2.13.so
7feabfe0f000-7feabfe10000 rw-p 00083000 08:01 16515346                   /lib/x86_64-linux-gnu/libm-2.13.so
7feabfe10000-7feabfef8000 r-xp 00000000 08:01 18881835                   /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16
7feabfef8000-7feac00f8000 ---p 000e8000 08:01 18881835                   /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16
7feac00f8000-7feac0100000 r--p 000e8000 08:01 18881835                   /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16
7feac0100000-7feac0102000 rw-p 000f0000 08:01 18881835                   /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16
7feac0102000-7feac0117000 rw-p 00000000 00:00 0 
7feac0117000-7feac022b000 r-xp 00000000 08:01 18883022                   /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0
7feac022b000-7feac042a000 ---p 00114000 08:01 18883022                   /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0
7feac042a000-7feac042b000 r--p 00113000 08:01 18883022                   /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0
7feac042b000-7feac042d000 rw-p 00114000 08:01 18883022                   /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0
7feac042d000-7feac044e000 r-xp 00000000 08:01 16515354                   /lib/x86_64-linux-gnu/ld-2.13.so
7feac0630000-7feac0636000 rw-p 00000000 00:00 0 
7feac064a000-7feac064d000 rw-p 00000000 00:00 0 
7feac064d000-7feac064e000 r--p 00020000 08:01 16515354                   /lib/x86_64-linux-gnu/ld-2.13.so
7feac064e000-7feac0650000 rw-p 00021000 08:01 16515354                   /lib/x86_64-linux-gnu/ld-2.13.so
7fff2940a000-7fff2942b000 rw-p 00000000 00:00 0                          [stack]
7fff2952c000-7fff2952d000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted

更新

运行valgrind --tool=memcheck --leak-check=full --log-file=memcheck.log ./test-Q 后,我得到了一个看起来很奇怪的日志文件。也许有些东西没有正确设置?这里是:

==15621== Memcheck, a memory error detector
==15621== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==15621== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==15621== Command: ./test-Q
==15621== Parent PID: 14623
==15621== 
==15621== Invalid write of size 4
==15621==    at 0x401EE2: call_function(std::vector<double, std::allocator<double> >) (test-Q.cpp:183)
==15621==    by 0x4026B1: run_experiment() (test-Q.cpp:346)
==15621==    by 0x401DBC: main (test-Q.cpp:120)
==15621==  Address 0x5ecba78 is 1,000 bytes inside a block of size 1,001 alloc'd
==15621==    at 0x4C2A66F: malloc (vg_replace_malloc.c:270)
==15621==    by 0x401E9A: call_function(std::vector<double, std::allocator<double> >) (test-Q.cpp:179)
==15621==    by 0x4026B1: run_experiment() (test-Q.cpp:346)
==15621==    by 0x401DBC: main (test-Q.cpp:120)
==15621== 
--15621-- VALGRIND INTERNAL ERROR: Valgrind received a signal 11 (SIGSEGV) - exiting
--15621-- si_code=80;  Faulting address: 0x0;  sp: 0x4030e0df0

valgrind: the 'impossible' happened:
   Killed by fatal signal
==15621==    at 0x380624A6: vgPlain_arena_malloc (m_mallocfree.c:291)
==15621==    by 0x380294E4: vgMemCheck_new_block (mc_malloc_wrappers.c:263)
==15621==    by 0x3802967A: vgMemCheck_malloc (mc_malloc_wrappers.c:301)
==15621==    by 0x3809D05D: vgPlain_scheduler (scheduler.c:1665)
==15621==    by 0x380AC715: run_a_thread_NORETURN (syswrap-linux.c:103)

sched status:
  running_tid=1

Thread 1: status = VgTs_Runnable
==15621==    at 0x4C2A66F: malloc (vg_replace_malloc.c:270)
==15621==    by 0x401FB9: call_function(std::vector<double, std::allocator<double> >) (test-Q.cpp:217)
==15621==    by 0x4026B1: run_experiment() (test-Q.cpp:346)
==15621==    by 0x401DBC: main (test-Q.cpp:120)


Note: see also the FAQ in the source distribution.
It contains workarounds to several common problems.
In particular, if Valgrind aborted or crashed after
identifying problems in your program, there's a good chance
that fixing those problems will prevent Valgrind aborting or
crashing, especially if it happened in m_mallocfree.c.

If that doesn't help, please report this bug to: www.valgrind.org

In the bug report, send all the above text, the valgrind
version, and what OS and version you are using.  Thanks.

更新

这是与数组有关的函数。

// main function
int main()

    run_experiment();   
 


void run_experiment()


    const int MAX_VAL = 1001;
    std::string line;
    std::ifstream myfile ("s1.txt");
    std::vector<double>data(MAX_VAL);
    int cnt = 0;
    double val;


    if (myfile.is_open())
    
        while ( myfile.good() && cnt < MAX_VAL)
        
            std::getline (myfile,line); 
            val = boost::lexical_cast<double>(line);
            data[cnt++] = val;      
        
        myfile.close();

        // data vector seems to be OK here          


        // call the function to do the data processing
        // this is the line 346 called into question by Valgrind
        // run_experiment() (test-Q.cpp:346)
        call_function(data);    

    
    else std::cout << "Unable to open file"; 
 // end

这是函数声明。向量是按值传递的。

void call_function(std::vector<double> v);

更新

正如 mux 在下面的答案中敏锐地建议的那样,超出数组范围的写入确实是一个问题。这是有效的代码版本,cmets 中显示了错误的代码。我修改了向量以保存 float 类型的元素,但真正的问题确实是超出了数组的范围。

C 样式数组是使用malloc() 创建的,但必须使用sizeof() 函数来创建足够的空间。

更改这一行代码会导致错误消失。

 // function to call code in the q analysis function
    void call_function(std::vector<float> v)
    

        // create all of the inputs
        float *tri = NULL; 
        int nsamp;
        int lwin;
        int nfreqfit;   // calculated below 
        float dt;  
        float null;  
        int L2; 
        float df;       // calculated below
        float *qq = NULL;  
        float *pf = NULL; 
        float *ampls;  
        double *work1; 
        double *work2; 
        double *work3; 
        double *work4; 
        int mem; 
        int morder;
        int nfs;        // calculated below
        double *xReal = NULL;  
        double *xImag = NULL; 
        double *xAbs = NULL;
        double *x1 = NULL;
        int cen;
        int top;
        int bot; 
        float cut;
        int nfst;           // calculated below
        int raw;
        float fst;          // low frequency to fit; replaces fpeak frequency


        nsamp = v.size();
        lwin = 101;
        dt =  0.0042;
        null = 100;
        L2 = 1;
        mem = 0;            // keep this as is
        morder = 5;
        cen = 1;
        top = 0;
        bot = 0;
        cut = 0.50;
        raw = 1;
        fst = 0.0;          // lowest frequency to fit


        // this is the line that was changed
        tri = (float*)malloc(nsamp * sizeof(float));

        // This is the line that needed changing
        // tri = (float*)malloc(nsamp);

        // copy the data into the vector
        for (int i = 0; i < nsamp; i++)
            tri[i] = v[i];

       std::cout << "Done copying data to the vector" << std::endl;

    // more code here...

     // end of function


    void run_experiment()
    

        const int MAX_VAL = 1001;
        std::string line;
        std::ifstream myfile ("s1.txt");
        std::vector<float>data(MAX_VAL);
        int cnt = 0;
        float val;


        if (myfile.is_open())
        
            while ( myfile.good() && cnt < MAX_VAL)
            
                std::getline (myfile,line); 
                val = boost::lexical_cast<double>(line);
                data[cnt++] = val;      
            
            myfile.close();

            /*
            for (int i = 0; i < 1001; i++)
                std::cout << data[i] << std::endl;
            */


            // call the function to do the data processing
            call_function(data);    

        
        else std::cout << "Unable to open file"; 
     // end


int main()

    run_experiment();   
 

【问题讨论】:

(a) 在valgrind 下运行它以确保您没有在free() 之前滥用内存。 (b) 使用valgrind 可能会告诉你为什么free() 会崩溃。 (c) x1 没有被malloc() 等人分配,或者x1 之前被释放,或者x1 被重新分配并且重新分配移动了数据的可能性很高,所以你的指针无效,或者 (d) 你在某处越界,重写了malloc()free() 依赖的控制信息。您使用:valgrind ./test-Q 使用 valgrind 分析您的程序。 @JonathanLeffler:谢谢,乔纳森。我会看一下代码并尝试看看哪里出了问题。我也会尝试运行valgrind 另一个建议 - 您可以尝试打印您正在释放的指针,以确保它实际上指向有效数据并且它与您最初期望它包含的数据相同 哇!你打破了 valgrind !不错:) @Nicholas Kinar Valgrind 说 call_function() 访问的内存超过了分配的内存。也许x1 = (double*)malloc(iXget) 应该是x1 = (double*)malloc(iXget * sizeof *x1) 【参考方案1】:

您的程序中似乎有内存泄漏,您提供的输出根本没有帮助,您应该使用valgrind 运行程序来解决问题。试试:

valgrind --tool=memcheck --leak-check=full --log-file=memcheck.log <binary>

如果您fork 任何您可能想要添加的子进程:

--trace-children=yes

如果还是不能修复,那就贴出 memcheck.log 和相关代码。

编辑:看来你在这里写的东西超出了一些数组的范围:

call_function(std::vector<double, std::allocator<double> >) (test-Q.cpp:183)

你应该先解决这个问题,这可能是问题所在。

【讨论】:

感谢多路复用器!我在代码上运行了 valgrind,它产生了一个相当奇怪的日志文件。我已经发布了上面的输出。 @NicholasKinar 查看更新,请贴出相关代码。 好的,我已经发布了更多代码。 Valgrind 似乎不喜欢函数调用call_function(data)。谢谢多路复用器。 @NicholasKinar 实际上是call_function 抱歉,您也可以添加吗? @NicholasKinar valgrind 在 Invalid write of size 4 之后显示回调跟踪

以上是关于调用 free() 时发生混合语言程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

混合新旧数据时应用程序崩溃

为 Android 构建的混合应用程序在向输入框中输入数字时崩溃

开始运行应用程序时 EXC_BAD_ACCESS 崩溃?

vfork 导致内存“free()”崩溃,但 fork 没有,它是怎么发生的?

给定 %d 时,VC++ 6.0 应用程序在 CString::Format 内崩溃

检测我的Mac应用程序是否崩溃,然后继续正常崩溃