繁体   English   中英

由 -O2 标志引起的信号 SIGSEGV

[英]signal SIGSEGV caused by the -O2 flag

标志 -O2 是什么意思? ,因为我在使用标志-O2编译程序时收到信号SIGSEGV ,但是如果我在gcc命令中删除该标志,则程序可以完美运行而没有任何错误,我试图使用递归函数解决Primitive Calculator问题,它是只是一个递归和记忆问题。

然后使用此命令,程序可以完美运行...

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

但是使用这个另一个命令它不起作用,得到信号 SIGSEGV... :'(

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

例如,如果运行使用该标志( -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) 

在那一点上它会因任何原因崩溃,正如我之前提到的,如果您删除标志-O2程序可以完美运行,我只想知道-O2标志在编译器中的含义,因为这对我没有任何意义我要失去理智了。

然后这是代码。

#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();
}

为了回答提出的具体问题, GCC 手册中解释了-O2以及gcc的所有其他命令行选项的含义。 您将在Optimization Options下找到-O2 ,然后按照链接将您带到:

-O2优化更多...

所以-O2选项启用优化 另请参阅有多少 GCC 优化级别? .

C 程序存在导致未定义行为的错误是很常见的,但在启用优化之前实际上不会出现错误行为。

也可以看看:

如果您需要帮助查找特定程序中的错误,请将其简化为最小的可重现示例并提出一个新问题。

使用 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

所以 SIGSEGV 的直接原因是堆栈溢出。 每当输入太大时就会发生这种情况,并且 -O2 比 -O0 发生得更快,但无论优化级别如何都会发生

第二个可能连接或未连接的问题是使用未初始化的 memory,因为您没有正确清除分配的 arrays。 你做:

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

它为 num+1 个整数分配了空间,但只清除了前 num 个字节(这可能只是数组的前四分之一)。 你要

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

也就是说,memset 的参数应该与 malloc 的参数相同。 或者你可以只使用 calloc 代替。


修复 memset 问题修复了 valgrind 中的“条件跳转或移动取决于未初始化的值”,但不影响堆栈溢出。

颠倒“opeType”枚举值的顺序会延迟堆栈溢出——比触发它所需的输入量增加一倍多——但它仍然会发生。

暂无
暂无

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

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