簡體   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