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