[英]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.