简体   繁体   English

由 -O2 标志引起的信号 SIGSEGV

[英]signal SIGSEGV caused by the -O2 flag

What does the flag -O2 means?标志 -O2 是什么意思? , because I get the signal SIGSEGV when I compile my program with the flag -O2 , but If I remove that flag at the gcc command, the program works perfectly without any error, I was trying to solve Primitive Calculator problem using recursive functions, it's just a recursion and Memoization problem. ,因为我在使用标志-O2编译程序时收到信号SIGSEGV ,但是如果我在gcc命令中删除该标志,则程序可以完美运行而没有任何错误,我试图使用递归函数解决Primitive Calculator问题,它是只是一个递归和记忆问题。

then with this command the program works perfectly...然后使用此命令,程序可以完美运行...

gcc -pipe -std=c11 -g file.c gcc -pipe -std=c11 -g file.c

But with this another command it doesn't works, gets the signal SIGSEGV... :'(但是使用这个另一个命令它不起作用,得到信号 SIGSEGV... :'(

gcc -pipe -O2 -std=c11 -g file.c gcc -pipe -O2 -std=c11 -g file.c

For example If run the program compiled with that flag( -O2 ), with the input 96234 , I get this error.例如,如果运行使用该标志( -O2 )编译的程序,输入96234 ,我会收到此错误。

(gdb) run
The program being debugged has been started already.                           
Start it from the beginning? (y or n) y
Starting program: /home/windowsky/Desktop/coursera/week5/a.out                 
96234

Program received signal SIGSEGV, Segmentation fault.                         
0x00005555555551b2 in options (num=num@entry=21355, ptr=ptr@entry=0x7fffffffe7a8) at eje2.c:26                                                                          
26                                                                             
(gdb) 

It crashes with any reason in that point, as I mention before if you remove the flag -O2 the program works perfectly, I just want to know what the -O2 flag means at the compiler, because this doesn't make any sense for me I'm going to lose my head.在那一点上它会因任何原因崩溃,正如我之前提到的,如果您删除标志-O2程序可以完美运行,我只想知道-O2标志在编译器中的含义,因为这对我没有任何意义我要失去理智了。

Then this is the code.然后这是代码。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>

/* this is the type of operations that we can do */
enum opeType {
    SUB_1,
    DIV_2,
    DIV_3
};


/*  options: Recursive options */
int options (int num, int **ptr)
{
    int minOperations, numOperations, i;


    if (num <= 1)
        return 0;

    numOperations = 0;
    minOperations= 2147483647;
    
    for (i = 0; i < 3; ++i) {
        switch (i) {
            case DIV_2:
                if (num % 2 == 0) {
                    if (*(*ptr + (num / 2)) == 0)
                        *(*ptr + (num / 2)) = options(num / 2, ptr) + 1;
                    numOperations = *(*ptr + (num / 2));
                }
                break;
            case DIV_3:
                if (num % 3 == 0) {
                    if (*(*ptr + (num / 3)) == 0)
                        *(*ptr + (num / 3)) = options(num / 3, ptr) + 1;
                    numOperations = *(*ptr + (num / 3));
                }
                break;
            case SUB_1:
                if (*(*ptr + (num -1)) == 0)
                    *(*ptr + (num - 1)) = options(num - 1, ptr) + 1;
                numOperations = *(*ptr + (num - 1));
                break;
        }
        if (numOperations < minOperations && numOperations != 0)
            minOperations = numOperations;
    }

    return minOperations;
}


/* findingPath: This is the function that is going to find the path */
bool findingPath (int **ptr2, int num, int c)
{   
    int i;
    bool flag;

    if (num == 1)
        return true;

    else if (c >= 0) {

        flag = false;
        for (i = 2; i > -1; --i) {
            switch (i) {
                case SUB_1:
                    if (flag = findingPath(ptr2, num - 1, c - 1))
                        *(*ptr2 + c) = num - 1;
                    break;
                case DIV_2:
                    if (num % 2 == 0 && (flag = findingPath(ptr2, num / 2, c - 1)))
                        *(*ptr2 + c) = num / 2;
                    break;
                case DIV_3:
                    if (num % 3 == 0 && (flag = findingPath(ptr2, num / 3, c - 1)))
                        *(*ptr2 + c) = num / 3;
                    break;
            }
            if (flag)
                return true;
        }
    }

    return false;
}





/*  one_test: Just one test */
void one_test ()
{
    int num, *ptr, *ptr2;
    int res, i;

    num = 6;
    ptr = (int *) malloc(sizeof(int) * (num + 1));
    memset(ptr, 0, num);

    res = options(num, &ptr);
    assert(res == 2);

    ptr2 = (int *) malloc(sizeof(int) * (res > 0 ? res : 1));
    memset(ptr2, 0, res > 0 ? (res - 1) : 1);

    findingPath(&ptr2, num, res > 0 ? (res - 1) : 1);

    printf("%i\n", res);
    for (i = 0; i < res; i++)
        printf("%i ", *(ptr2 + i));
    printf("%i ", num);
    
    free(ptr);
    free(ptr2);
    ptr = NULL;
    ptr2 = NULL;

}


/*  manual_test: This is the manual test */
void manual_test ()
{
    int num, *ptr, *ptr2;
    int res, i;

    scanf("%i", &num);
    ptr = (int *) malloc(sizeof(int) * (num + 1));
    memset(ptr, 0, num);

    res = options(num, &ptr);

    ptr2 = (int *) malloc(sizeof(int) * (res > 0 ? res : 1));
    memset(ptr2, 0, res > 0 ? (res - 1) : 1);

    findingPath(&ptr2, num, res > 0 ? (res - 1) : 1);

    printf("%i\n", res);
    for (i = 0; i < res; i++)
        printf("%i ", *(ptr2 + i));
    printf("%i ", num);
    
    free(ptr);
    free(ptr2);
    ptr = NULL;
    ptr2 = NULL;
}

 

void main ()
{
    //one_test();

    manual_test();
}

To answer the specific question posed, the meaning of -O2 , as well as every other command-line option to gcc , is explained in the GCC manual .为了回答提出的具体问题, GCC 手册中解释了-O2以及gcc的所有其他命令行选项的含义。 You will find -O2 under Optimization Options , and following the link leads you to:您将在Optimization Options下找到-O2 ,然后按照链接将您带到:

-O2 Optimize even more... -O2优化更多...

So the -O2 option enables optimizations .所以-O2选项启用优化 See also How many GCC optimization levels are there?另请参阅有多少 GCC 优化级别? . .

It is very common for C programs to have bugs that cause undefined behavior , but that don't actually misbehave until optimizations are enabled. C 程序存在导致未定义行为的错误是很常见的,但在启用优化之前实际上不会出现错误行为。

See also:也可以看看:

If you want help finding the bug in your particular program, then please reduce it to a minimal reproducible example and ask a new question about it.如果您需要帮助查找特定程序中的错误,请将其简化为最小的可重现示例并提出一个新问题。

Running with valgrind shows fairly quickly your problem(s):使用 valgrind 运行会很快显示您的问题:

==27297== Memcheck, a memory error detector
==27297== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==27297== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==27297== Command: ./t
==27297== 
==27297== Conditional jump or move depends on uninitialised value(s)
==27297==    at 0x1088A5: options.part.0 (t.c:44)
==27297==    by 0x1096CB: options (t.c:153)
==27297==    by 0x1096CB: manual_test (t.c:137)
==27297==    by 0x4E5FBF6: (below main) (libc-start.c:310)
==27297== 
==27297== Conditional jump or move depends on uninitialised value(s)
==27297==    at 0x1088A5: options.part.0 (t.c:44)
==27297==    by 0x108986: options (t.c:21)
==27297==    by 0x108986: options.part.0 (t.c:45)
==27297==    by 0x1096CB: options (t.c:153)
==27297==    by 0x1096CB: manual_test (t.c:137)
==27297==    by 0x4E5FBF6: (below main) (libc-start.c:310)
==27297== 
==27297== Conditional jump or move depends on uninitialised value(s)
==27297==    at 0x1088A5: options.part.0 (t.c:44)
==27297==    by 0x108986: options (t.c:21)
==27297==    by 0x108986: options.part.0 (t.c:45)
==27297==    by 0x108986: options (t.c:21)
==27297==    by 0x108986: options.part.0 (t.c:45)
==27297==    by 0x1096CB: options (t.c:153)
==27297==    by 0x1096CB: manual_test (t.c:137)
==27297==    by 0x4E5FBF6: (below main) (libc-start.c:310)
==27297== 
==27297== Conditional jump or move depends on uninitialised value(s)
==27297==    at 0x1088A5: options.part.0 (t.c:44)
==27297==    by 0x108986: options (t.c:21)
==27297==    by 0x108986: options.part.0 (t.c:45)
==27297==    by 0x108986: options (t.c:21)
==27297==    by 0x108986: options.part.0 (t.c:45)
==27297==    by 0x108986: options (t.c:21)
==27297==    by 0x108986: options.part.0 (t.c:45)
==27297==    by 0x1096CB: options (t.c:153)
==27297==    by 0x1096CB: manual_test (t.c:137)
==27297==    by 0x4E5FBF6: (below main) (libc-start.c:310)
==27297== 
==27297== Stack overflow in thread #1: can't grow stack to 0x1ffe801000
==27297== 
==27297== Process terminating with default action of signal 11 (SIGSEGV): dumping core

So the direct cause of the SIGSEGV is a stack overflow.所以 SIGSEGV 的直接原因是堆栈溢出。 This happens whenever the input is too large, and happens sooner with -O2 than -O0 but happens regardless of optimization level每当输入太大时就会发生这种情况,并且 -O2 比 -O0 发生得更快,但无论优化级别如何都会发生

The second problem which may or may not be connected is use of uninitialized memory, due to the fact that you are not clearing your malloced arrays properly.第二个可能连接或未连接的问题是使用未初始化的 memory,因为您没有正确清除分配的 arrays。 You do:你做:

    ptr = (int *) malloc(sizeof(int) * (num + 1));
    memset(ptr, 0, num);

Which allocated space for num+1 ints, but only clears the first num bytes (which is probably just the first quarter of the array).它为 num+1 个整数分配了空间,但只清除了前 num 个字节(这可能只是数组的前四分之一)。 You want你要

    memset(ptr, 0, sizeof(int) * (num + 1));

that is, the argument to memset should be the same as the argument to malloc.也就是说,memset 的参数应该与 malloc 的参数相同。 Or you could just use calloc instead.或者你可以只使用 calloc 代替。


Fixing the memset problem fixes the "Conditional jump or move depends on uninitialised value" from valgrind but does not affect the stack overflow.修复 memset 问题修复了 valgrind 中的“条件跳转或移动取决于未初始化的值”,但不影响堆栈溢出。

Reversing the order of the "opeType" enum values delays the stack overflow -- more than doubling how large an input is required to trigger it -- but it still happens.颠倒“opeType”枚举值的顺序会延迟堆栈溢出——比触发它所需的输入量增加一倍多——但它仍然会发生。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM