Sigsegv segmentation fault как исправить

Время на прочтение
3 мин

Количество просмотров 65K

Вводная

C++ является «небезопасным» («unmanaged») языком, поэтому программы могут «вылетать» — аварийно завершать работу без сохранения данных пользователя, сообщения об ошибке и т.п. — стоит только, например, залезть в не инициализированную память. Например:

void fall()
{
  char * s = "short_text";
  sprintf(s,"This is very long text");
}

или

void fall()
{
  int * pointer = NULL;
  *pointer = 13;
}

Всем было бы лучше, если бы мы могли «отловить» падение программы — точно так же, как в java ловим исключения — и выполнить хоть что-то перед тем, как программа упадет (сохранить документ пользователя, вывести диалог с сообщением об ошибке и т.п.)

Общего решения задача не имеет, так как C++ не имеет собственной модели обработки исключений, связанных с работой с памятью. Тем не менее, мы рассмотрим два способа, использующих особенности операционной системы, вызвавшей исключение.

Способ 1: SEH

Если Вы используете OS Windows в качестве целевой ОС и Visual C++ в качестве компилятора, то Вы можете использовать Structured Exception Handling — расширение языка С++ от Microsoft, позволяющее отлавливать любые исключения, происходящие в программе.

Общий синтаксис обработки исключений выглядит следующим образом:

__try
{
  segfault1();
}
__except( condition1 )
{
  // обработка исключения, если condition1 == EXCEPTION_EXECUTE_HANDLER.
  // в condition1 может (должен) быть вызов метода, проверяющего 
  //    тип исключения, и возвращающего EXCEPTION_EXECUTE_HANDLER 
  //    если тип исключения соответствует тому, что мы хотим обработать
}
__except( condition2 )
{
  // еще один обработчик
}
__finally
{
  // то, что выполнится если ни один из обработчиков не почешется
}

Вот «работающий пример» — «скопируй и вставь в Visual Studio»

#include <stdio.h>
#include <windows.h>
#include <excpt.h>

int memento() // обработка Segfault
{
	MessageBoxA(NULL,"Memento Mori","Exception catched!",NULL);
	return 0;
}

void fall() // генерация segfault
{
	  int* p = 0x00000000;   
	  *p = 13;
}

int main(int argc, char *argv[])
{
	__try
	{
		fall();
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		memento();
	}
}

Мне лично не удалось заставить заработать __finally (поэтому я и написал __except с кодом проверки, который всегда работает), но это, возможно, кривизна моих рук.

Данная методика, при всей ее привлекательности, имеет ряд минусов:

  • Один компилятор. Одна ОС. Не «чистый С++». Если Вы хотите работать без средств MS — Вы не сможете использовать эту методику
  • Один поток — одна таблица. Если Вы напишете конструкцию из __try… __except, внутри __try запустите другой поток и, не выходя из __try второй поток вызовет segfault, то… ничего не произойдет, программа упадет «как обычно». Потому, что на каждый поток нужно писать отдельный обработчик SEH.

Минусов оказалось настолько много, что приходится искать второе решение.

Способ 2: POSIX — сигналы

Способ рассчитан на то, что в момент падения программа получает POSIX-сообщение SIGSEGV. Это безусловно так во всех UNIX-системах, но это фактически так (хотя никто не гарантировал, windows — не posix-совместима) и в windows тоже.

Методика простая — мы должны написать обработчик сообщения SIGSEGV, в котором программа совершит «прощальные действия» и, наконец, упадет:

void posix_death_signal(int signum)
{
	memento(); // прощальные действия
        signal(signum, SIG_DFL); // перепосылка сигнала
	exit(3); //выход из программы. Если не сделать этого, то обработчик будет вызываться бесконечно.
}

после чего мы должны зарегистрировать этот обработчик:

signal(SIGSEGV, posix_death_signal);

Вот готовый пример:

#include <stdio.h>
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <signal.h>


int memento()
{
	int a=0;
	MessageBoxA(NULL,"Memento mori","POSIX Signal",NULL);
	return 0;
}
void fall()
{
	  int* p = 0x00000000; 
	  *p = 13;
}
void posix_death_signal(int signum)
{
	memento();
	signal(signum, SIG_DFL);
	exit(3);
}


int main(int argc, char *argv[])
{
	signal(SIGSEGV, posix_death_signal);
	fall();
}

В отличие от SEH, это работает всегда: решение «многопоточное» (вы можете уронить программу в любом потоке, обработчик запустится в любом случае) и «кроссплатформенное» — работает под любым компилятором, и под любой POSIX-совместимой ОС.

The segmentation fault, also known as segfault, is a type of computer error that occurs whenever an unexpected condition causes the processor to attempt to access a memory location that’s outside its own program storage area. The term “segmentation” refers to a memory protection mechanism used in virtual memory operating systems.

This specific error arises because data is typically shared on a system using different memory sections, and the program storage space is shared among applications.

Segmentation faults are usually triggered by an access violation, which occurs when the CPU attempts to execute instructions outside its memory area or tries to read or write into some reserved address that does not exist. This action results in halting the current application and generates an output known as Segmentation Fault.

#1. What are the Symptoms of Segmentation Fault?

The symptoms of segmentation faults may vary depending on how and where they’re generated. Typically, this error is generated due to one of the following conditions:

#a. Dereferencing a null pointer

Programming languages offer references, which are pointers that identify where in memory an item is located. A null pointer is a special pointer that doesn’t point to any valid memory location. Dereferencing (accessing) null pointer results in segmentation faults or null pointer exceptions.

/**
 * @file main.c
 * @author freecoder
 * @brief this program allow to handle a segmentation fault error
 *
 * @version 1.0
 * @date 8 Jan. 2022
 *
 * @copyright Copyright (c) 2022
 *
 */
#include <stdio.h>

/* main program entry */
int main(int argc, char **argv)
{
	/* local variables */
	unsigned int *puiPointer = NULL;
	/* body program */
	*puiPointer = 20;
	return 0;
}

after compiling and running the program with the gdb command, the segmentation fault error appears:

➜  Article-XX gcc -g main.c -o main
➜  Article-XX ./main               
[1]    7825 segmentation fault  ./main
➜  Article-XX gdb ./main           
GNU gdb (Debian 10.1-1.7) 10.1.90.20210103-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...
(gdb) start
Temporary breakpoint 1 at 0x401111: file main.c, line 20.
Starting program: /home/others/Article-XX/main 
warning: Error disabling address space randomization: Operation not permitted
Temporary breakpoint 1, main (argc=1, argv=0x7ffc9c096258) at main.c:20
20              unsigned int *puiPointer = NULL;
(gdb) list
15
16      /* main program entry */
17      int main(int argc, char **argv)
18      {
19              /* local variables */
20              unsigned int *puiPointer = NULL;
21
22              /* body program */
23
24              *puiPointer = 20;
(gdb) s
24              *puiPointer = 20;
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x000000000040111d in main (argc=1, argv=0x7ffc9c096258) at main.c:24
24              *puiPointer = 20;
(gdb) 
segmentation fault Dereferencing a null pointer

#b. Trying to access memory not initialized

Programs using uninitialized variables may crash when attempting to access uninitialized memory or may expose data stored in the uninitialized variables by writing to them. Also in the case when the program attempts to read or write to an area of memory not allocated with malloc(), calloc() or realloc().

An example of a simple segmentation fault is trying to read from a variable before it has been set:

/**
 * @file main.c
 * @author freecoder
 * @brief this program allow to handle a segmentation fault error
 *
 * @version 1.0
 * @date 8 Jan. 2022
 *
 * @copyright Copyright (c) 2022
 *
 */
#include <stdio.h>

/* main program entry */
int main(int argc, char **argv)
{
	/* local variables */
	unsigned int *puiPointer;
	/* body program */
	*puiPointer = 20;
	return 0;
}

In this case, the pointer puiPointer will be pointing to a random location in memory, so when the program attempts to read from it (by dereferencing *puiPointer), a segmentation fault will be triggered:

➜  Article-XX gcc -g main.c -o main
➜  Article-XX gdb ./main           
GNU gdb (Debian 10.1-1.7) 10.1.90.20210103-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...
(gdb) start
Temporary breakpoint 1 at 0x401111: file main.c, line 24.
Starting program: /home/others/Article-XX/main 
warning: Error disabling address space randomization: Operation not permitted
Temporary breakpoint 1, main (argc=1, argv=0x7fff6df4f038) at main.c:24
24              *puiPointer = 20;
(gdb) list
19              /* local variables */
20              unsigned int *puiPointer;
21
22              /* body program */
23
24              *puiPointer = 20;
25
26              return 0;
27      }
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401115 in main (argc=1, argv=0x7fff6df4f038) at main.c:24
24              *puiPointer = 20;
(gdb) 
segmentation fault - Trying to access memory not initialized

#c. Trying to access memory out of bounds for the program

In most situations, if a program attempts to access (read or write) memory outside of its boundaries, a segmentation fault error will occur. A code example of a simple segmentation fault error is below:

/**
 * @file main.c
 * @author freecoder
 * @brief this program allow to handle a segmentation fault error
 *
 * @version 1.0
 * @date 8 Jan. 2022
 *
 * @copyright Copyright (c) 2022
 *
 */
#include <stdio.h>

/* main program entry */
int main(int argc, char **argv)
{
	/* local variables */
	unsigned int uiArray[20];
	/* body program */
	uiArray[5000] = 1;
	return 0;
}

As shown bellow, the segmentation fault occurs after executing the out of bounds statement:

➜  Article-XX gcc -g main.c -o main
➜  Article-XX gdb ./main           
GNU gdb (Debian 10.1-1.7) 10.1.90.20210103-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...
(gdb) start
Temporary breakpoint 1 at 0x401111: file main.c, line 23.
Starting program: /home/others/Article-XX/main 
warning: Error disabling address space randomization: Operation not permitted
Temporary breakpoint 1, main (argc=1, argv=0x7ffdb68620f8) at main.c:23
23              uiArray[5000] = 1;
(gdb) list
18      {
19              /* local variables */
20              unsigned int uiArray[20];
21
22              /* body program */
23              uiArray[5000] = 1;
24
25              return 0;
26      }
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
main (argc=1, argv=0x7ffdb68620f8) at main.c:23
23              uiArray[5000] = 1;
(gdb) 
segmentation fault memory out of bounds

#d. Trying to modify string literals

/**
 * @file main.c
 * @author freecoder
 * @brief this program allow to handle a segmentation fault error
 *
 * @version 1.0
 * @date 8 Jan. 2022
 *
 * @copyright Copyright (c) 2022
 *
 */
#include <stdio.h>

/* main program entry */
int main(int argc, char **argv)
{
	/* local variables */
	char* pucString = "Sample String 1";
	/* body program */
	pucString[14] = '2';
	return 0;
}

As shown bellow, we got a segmentation error because the compiler put the string constant “Sample String 1” in read-only memory while trying to modify the contents of that memory which fails as a result:

➜  Article-XX gcc -g main.c -o main
➜  Article-XX gdb ./main           
GNU gdb (Debian 10.1-1.7) 10.1.90.20210103-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...
(gdb) start
Temporary breakpoint 1 at 0x401111: file main.c, line 20.
Starting program: /home/others/Article-XX/main 
warning: Error disabling address space randomization: Operation not permitted
Temporary breakpoint 1, main (argc=1, argv=0x7ffc2ea212e8) at main.c:20
20              char* pucString = "Sample String 1";
(gdb) list
15
16      /* main program entry */
17      int main(int argc, char **argv)
18      {
19              /* local variables */
20              char* pucString = "Sample String 1";
21
22              /* body program */
23              pucString[14] = '2';
24
(gdb) n
23              pucString[14] = '2';
(gdb) 
Program received signal SIGSEGV, Segmentation fault.
main (argc=1, argv=0x7ffc2ea212e8) at main.c:23
23              pucString[14] = '2';
(gdb) 

segmentation fault modify string

#e. Using variable’s value as an address

A segmentation fault occurs when accidentally you are using a variable’s value as an address as you can see through the code example bellow:

/**
 * @file main.c
 * @author freecoder
 * @brief this program allow to handle a segmentation fault error
 *
 * @version 1.0
 * @date 8 Jan. 2022
 *
 * @copyright Copyright (c) 2022
 *
 */
#include <stdio.h>

/* main program entry */
int main(int argc, char **argv)
{
	/* local variables */
	int iVariable;
	/* body program */
	scanf("%d", iVariable);
	return 0;
}

As shown in the terminal consol bellow, the segmentation occurs after the scans statement:

➜  Article-XX gcc -g main.c -o main
➜  Article-XX gdb ./main           
GNU gdb (Debian 10.1-1.7) 10.1.90.20210103-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...
(gdb) start
Temporary breakpoint 1 at 0x401135: file main.c, line 23.
Starting program: /home/others/Article-XX/main 
warning: Error disabling address space randomization: Operation not permitted
Temporary breakpoint 1, main (argc=1, argv=0x7fff418f9658) at main.c:23
23              scanf("%d", iVariable);
(gdb) list
18      {
19              /* local variables */
20              int iVariable;
21
22              /* body program */
23              scanf("%d", iVariable);
24
25              return 0;
26      }
(gdb) n
1
Program received signal SIGSEGV, Segmentation fault.
0x00007ff3e1d2201a in __vfscanf_internal (s=<optimized out>, format=<optimized out>, [email protected]=0x7fff418f9460, [email protected]=2)
    at vfscanf-internal.c:1895
1895    vfscanf-internal.c: No such file or directory.
(gdb) 
segmentation fault gemination fault using variable's value as address

#f. Stack overflow

The segmentation fault error may occur if the call stack pointer exceeds the stack bound in case of an infinite recursive function call:

/**
 * @file main.c
 * @author freecoder
 * @brief this program allow to handle a segmentation fault error
 *
 * @version 1.0
 * @date 8 Jan. 2022
 *
 * @copyright Copyright (c) 2022
 *
 */
#include <stdio.h>

/* main program entry */
int main(void)
{
	/* local variables */
	/* body program */
	main();
	return 0;
}

As shown bellow, the segmentation fault error happened, due to a stack oveflow after calling the main function:

➜  Article-XX gcc -g main.c -o main
➜  Article-XX gdb ./main                                
GNU gdb (Debian 10.1-1.7) 10.1.90.20210103-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...
(gdb) start
Temporary breakpoint 1 at 0x40110a: file main.c, line 22.
Starting program: /home/others/Article-XX/main 
warning: Error disabling address space randomization: Operation not permitted
Temporary breakpoint 1, main () at main.c:22
22              main();
(gdb) list
17      int main(void)
18      {
19              /* local variables */
20
21              /* body program */
22              main();
23
24              return 0;
25      }
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
main () at main.c:22
22              main();
(gdb) 

segmentation fault Stack overflow

#2. How do you Fix Segmentation Faults?

Because segmentation faults are often associated with memory management issues or problematic pointer assignments, they can be fixed by making sure that the target application correctly handles these errors and does not attempt to read or write memory locations outside its own address space.

There are also certain procedures which you can follow in order to prevent and fix segmentation faults:

#a. How to Prevent Segmentation Faults?

Most segmentation faults occur due to memory access errors, so it’s important to make sure that pointers used by an application always reference valid data areas.

  • Check the reference of null memory.
  • Testing the code with Valgrind or Electric Fence
  • Assert() before dereferencing a suspective pointer, mainly a pointer embedded in a struct that is maintained in a container in a list or an array.
  • Always remember to initialize pointers properly.
  • Protect shared resources against concurrent access in multithreading by using a mutex or a semaphore.
  • Use of free() routine

#b. How to Fix Segmentation Faults?

There are some tools that you can use in order to fix the segmentation faults:

  • Gdb and core dump file
  • Gdb and backtrace.
  • Debugfs and Dmesg for kernel debugging

Conclusion

A segmentation fault is generally caused by a programming bug that tries to access either non-existent or protected memory. It can also happen as a result of dividing an integer by zero (causing the program counter to be redirected to nowhere), accessing memory that is out of bounds at an address that does not contain valid data or code.

Finally, when enabled on some operating systems (and in some embedded programming environments), the processor may issue an exception if a memory address contains a non-mapped machine code instruction.

I hope this post has clarified what segmentation faults on the x86 architecture imply and how to avoid them. Do not forget to share the information on social networks if you believe it is useful for others. If you have any queries, please do not hesitate to leave a comment and subscribe to our newsletter. Best of luck with your coding and see you in the next article!

In this guide, we will dive into the concept of segmentation fault errors, also known as SIGSEGV. We will understand why these errors occur, how to debug them, and some best practices to prevent them. This information will be useful for developers dealing with low-level programming languages like C and C++.

Table of Contents

  1. What is a Segmentation Fault?
  2. Common Causes of Segmentation Faults
  3. Debugging Segmentation Faults
  4. Best Practices to Prevent Segmentation Faults
  5. FAQ

What is a Segmentation Fault?

A segmentation fault, or SIGSEGV, is a specific kind of error caused by accessing memory that is not allocated for your application. It is a protective mechanism that prevents programs from accessing restricted memory areas, causing potential data corruption or loss. When a program encounters a segmentation fault, the operating system sends a SIGSEGV signal and terminates the program.

Common Causes of Segmentation Faults

Here are some common causes of segmentation faults:

  1. Dereferencing NULL pointers: When you try to access memory through a NULL pointer, a segmentation fault occurs.
  2. Buffer overflow: Writing data beyond the allocated memory space can lead to segmentation faults.
  3. Uninitialized pointers: Using an uninitialized pointer can result in undefined behavior and segmentation faults.
  4. Improper usage of memory allocation functions: Incorrect usage of malloc, calloc, realloc, and free can lead to segmentation faults.
  5. Stack overflow: When a program uses up all the available stack memory, it can lead to a segmentation fault.

Debugging Segmentation Faults

To debug segmentation faults, you can use tools like gdb or lldb. Here’s a step-by-step guide to using gdb:

  1. Compile your program with the -g flag: This flag tells the compiler to include debugging information in the output. For instance, gcc -g -o my_program my_program.c.
  2. Run your program with gdb: Execute gdb my_program to start gdb with your program.
  3. Set a breakpoint: Use the break command to set a breakpoint in your program. For example, break main.
  4. Run your program: Use the run command to start running your program.
  5. Examine the backtrace: When gdb encounters a segmentation fault, it will display the line number and a backtrace of the function calls. Use the backtrace command to examine the call stack.
  6. Inspect variables and memory: Use the print command to inspect the values of variables and memory addresses. For instance, print *ptr to see the value stored at the address pointed to by ptr.
  7. Continue debugging: You can use commands like step, next, and continue to navigate through your program and debug the issue.

Best Practices to Prevent Segmentation Faults

Here are some best practices to help prevent segmentation faults:

  1. Always initialize your pointers.
  2. Check for NULL pointers before dereferencing them.
  3. Use proper memory allocation and deallocation functions.
  4. Validate array indices and buffer sizes.
  5. Use tools like Valgrind to detect memory leaks and other memory-related issues.

FAQ

What is SIGSEGV?

SIGSEGV is a signal sent by the operating system to a process when it attempts to access memory that is not allocated for it. It stands for “Segmentation Violation” and is commonly associated with segmentation fault errors.

Can segmentation faults damage my computer?

Segmentation faults usually do not cause any harm to your computer. The operating system terminates the process that caused the segmentation fault to prevent potential data corruption or loss.

What is the difference between segmentation fault and bus error?

A segmentation fault occurs when a program tries to access memory that is not allocated for it, while a bus error occurs when a program tries to access memory in a way that is not allowed by the hardware (e.g., misaligned memory access).

How can I handle segmentation faults in my program?

You can use signal handling functions like signal() or sigaction() to catch SIGSEGV signals and execute a custom handler function. However, this approach should be used with caution, as it may lead to unpredictable behavior and is not recommended for fixing segmentation faults.

Are segmentation faults specific to C and C++?

Segmentation faults are more common in low-level languages like C and C++ that allow direct memory manipulation. However, they can also occur in other languages due to issues in the runtime environment or underlying libraries.

Understanding and Debugging C/C++ Segmentation Faults

How to Debug Segmentation Faults in C/C++

Debugging Segmentation Faults and Pointer Problems

I have been working on a Qt Creator application, and just recently ran into a run-time error that I have no idea how to find and fix. The program just unexpectedly finishes once it starts up, and when I run the debug, it gives me the error:

The inferior stopped because it
received a signal from the operating
system.

Signal name: SIGSEGV

Signal meaning: Segmentation fault

Now I understand that this error is caused by attempted access to an invalid memory location, but I have absolutely no clue what I did to trigger it. The debugger seems to be pointing me to a specific line of code:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QString>
#include "ui_mainwindow.h"
#include "foamdata.h"
#include "domaingeneration.h"


namespace Ui {
    class MainWindow;
}


class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    int getXDim() const { return ui->xDim->value(); } // THIS is where it points to!!
    int getYDim() const { return ui->yDim->value(); }


private slots:
    void on_findDir_clicked();

    void on_create_clicked();

    void on_generateDomain_clicked();

private:
    Ui::MainWindow *ui;
    DomainGeneration dg;    //declaring second window as a member of main window
};

#endif // MAINWINDOW_H

That function is used in this:

#include "domaingeneration.h"
#include "ui_domaingeneration.h"
#include <QCheckBox>
#include "mainwindow.h"

DomainGeneration::DomainGeneration(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DomainGeneration)
{
    ui->setupUi(this);

    // Generating checkboxes for domain generation
    MainWindow* main;
    int x_dim = main->getXDim();
    int y_dim = main->getYDim();
    QVector<QCheckBox*> checkBoxVector;
    for(int i = 0; i < x_dim; ++i){
        for(int j = 0; j < y_dim; ++j){
            checkBoxVector.append(new QCheckBox(this));
            checkBoxVector.last()->setGeometry(i * 20, j * 20, 20, 20);
        }
    }
}


DomainGeneration::~DomainGeneration()
{
    delete ui;
}

Here is the mainwindow source code:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "functions.h"
#include "main.cpp"
#include <QtGui/QApplication>
#include <QFileDialog>
#include <fstream>
#include "foamdata.h"
#include "domaingeneration.h"


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}




// This is the function that handles the directory search when the 'browse' button is pressed
void MainWindow::on_findDir_clicked()
{
    QString path;   //declaring the path to the base directory

    path = QFileDialog::getExistingDirectory(   //gathering the directory from QFileDialog class
        this, tr("Choose the project directory"),
        "/home",
        QFileDialog::ShowDirsOnly
        | QFileDialog::DontResolveSymlinks );

    ui->baseDir->setText( path );   //setting the retrieved path into the line edit box
}



// This function makes the project by creating a new directory with name 'project_name'
// in the base directory, and collects the OpenFOAM version number and simulation type
void MainWindow::on_create_clicked()
{

    QString project_name, foam_version, full_dir, slash, base_dir;
    base_dir = ui->baseDir->text();
    project_name = ui->projectName->text();     //getting the text from the 'projectName' field
    foam_version = ui->version->currentText();  //getting the selection from the 'version' drop-down box

    project_info.save_version(foam_version);        //saving data in a global project variable
    project_info.save_projName(project_name);
    project_info.save_simType(ui->simType->currentText());

    //first checking if the fields have input in them:
    QString blank = "";
    QString no_text0 = "Please enter project name";
    if( project_name==no_text0 || (project_name==blank) ) {
        ui->projectName->setText( no_text0 );
        return;
    }


    QString no_text1 = "Please enter a valid directory";
    if( base_dir==no_text1 || base_dir==blank || !QDir( base_dir ).exists() ) {
        ui->baseDir->setText( no_text1 );
        return;
    }


    slash = "/";        // needed to separate folders in the directory (can't use a literal)
    full_dir = base_dir.append(slash.append(project_name));
    project_info.save_directory(full_dir);

    if( !QDir(full_dir).exists() )  //check if directory already exists
        QDir().mkdir(full_dir);     //creating directory

    QString blockmesh_filename, suffix;
    suffix = "_blockMeshDict";
    slash = "/";    //must re-define
    blockmesh_filename = full_dir.append( slash.append( project_name.append(suffix) ) );
    std::ofstream create_file( blockmesh_filename.toStdString().c_str() );  //creating empty blockmesh file

}


void MainWindow::on_generateDomain_clicked()    //opening the new window for domain generation
{
    dg.show();
}

Can anybody help me find what the heck is going on?

What is the root cause of the segmentation fault (SIGSEGV), and how to handle it?

Rohan Bari's user avatar

Rohan Bari

7,4223 gold badges14 silver badges34 bronze badges

asked Oct 14, 2009 at 5:20

Vaibhav's user avatar

0

Wikipedia has the answer, along with a number of other sources.

A segfault basically means you did something bad with pointers. This is probably a segfault:

char *c = NULL;
...
*c; // dereferencing a NULL pointer

Or this:

char *c = "Hello";
...
c[10] = 'z'; // out of bounds, or in this case, writing into read-only memory

Or maybe this:

char *c = new char[10];
...
delete [] c;
...
c[2] = 'z'; // accessing freed memory

Same basic principle in each case – you’re doing something with memory that isn’t yours.

answered Oct 14, 2009 at 5:25

Chris Lutz's user avatar

Chris LutzChris Lutz

72.9k16 gold badges128 silver badges182 bronze badges

There are various causes of segmentation faults, but fundamentally, you are accessing memory incorrectly. This could be caused by dereferencing a null pointer, or by trying to modify readonly memory, or by using a pointer to somewhere that is not mapped into the memory space of your process (that probably means you are trying to use a number as a pointer, or you incremented a pointer too far). On some machines, it is possible for a misaligned access via a pointer to cause the problem too – if you have an odd address and try to read an even number of bytes from it, for example (that can generate SIGBUS, instead).

answered Oct 14, 2009 at 5:25

Jonathan Leffler's user avatar

Jonathan LefflerJonathan Leffler

726k140 gold badges899 silver badges1275 bronze badges

2

SigSegV means a signal for memory access violation, trying to read or write from/to a memory area that your process does not have access to. These are not C or C++ exceptions and you can’t catch signals. It’s possible indeed to write a signal handler that ignores the problem and allows continued execution of your unstable program in undefined state, but it should be obvious that this is a very bad idea.

Most of the time this is because of a bug in the program. The memory address given can help debug what’s the problem (if it’s close to zero then it’s likely a null pointer dereference, if the address is something like 0xadcedfe then it’s intentional safeguard or a debug check, etc.)

One way of “catching” the signal is to run your stuff in a separate child process that can then abruptly terminate without taking your main process down with it. Finding the root cause and fixing it is obviously preferred over workarounds like this.

answered May 23, 2019 at 15:05

Ashish Khandelwal's user avatar

using an invalid/null pointer? Overrunning the bounds of an array? Kindof hard to be specific without any sample code.

Essentially, you are attempting to access memory that doesn’t belong to your program, so the OS kills it.

answered Oct 14, 2009 at 5:22

MichaelM's user avatar

MichaelMMichaelM

5,4682 gold badges30 silver badges23 bronze badges

Here is an example of SIGSEGV.

root@pierr-desktop:/opt/playGround# cat test.c
int main()
{
     int * p ;
     * p = 0x1234;
     return 0 ;
}
root@pierr-desktop:/opt/playGround# g++ -o test test.c  
root@pierr-desktop:/opt/playGround# ./test 
Segmentation fault

And here is the detail.

How to handle it?

  1. Avoid it as much as possible in the
    first place.

    Program defensively: use assert(), check for NULL pointer , check for buffer overflow.

    Use static analysis tools to examine your code.

    compile your code with -Werror -Wall.

    Has somebody review your code.

  2. When that actually happened.

    Examine you code carefully.

    Check what you have changed since the last time you code run successfully without crash.

    Hopefully, gdb will give you a call stack so that you know where the crash happened.


EDIT : sorry for a rush. It should be *p = 0x1234; instead of p = 0x1234;

answered Oct 14, 2009 at 5:23

pierrotlefou's user avatar

pierrotlefoupierrotlefou

39.5k36 gold badges134 silver badges174 bronze badges

4

The initial source cause can also be an out of memory.

answered Nov 13, 2020 at 16:07

Makusensu's user avatar

MakusensuMakusensu

2793 silver badges10 bronze badges

2

Segmentation fault arrives when you access memory which is not declared by the program. You can do this through pointers i.e through memory addresses. Or this may also be due to stackoverflow for example:

void rec_func() { int q = 5; rec_func(); }

public int Main() { rec_func(); return 0; }

This call will keep on consuming stack memory until it’s completely filled and thus finally stackoverflow happens.
Note: it might not be visible in some competitive questions as it leads to timeouterror first but for those in which timeout doesn’t happens its a hard time figuring out SIGSEGV.

Matt's user avatar

Matt

25.1k18 gold badges120 silver badges184 bronze badges

answered Oct 14, 2018 at 7:03

NIKESH SINGH's user avatar

1

Добавить комментарий