Как устранить ошибку Segmentation fault; core dumped при работе с указателями C ? — Хабр Q&A

Вводная

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

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

или

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

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

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

Как устранить ошибку segmentation fault; core dumped при работе с указателями c ?

Есть 2 класса:

1) UI

//UI.h
#ifndef UI_H
#define UI_H
#include <map>
#include <string>
#include <FL/Fl_Button.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Output.H>
#include <FL/Fl_Widget.H>
using namespace std;
class App;
class Calculator;
class UI {
public: Fl_Window *flWindow; map< string, Fl_Box* > flBox; map< string, Fl_Button*> flButtons; Fl_Output *output; App *app; Calculator *calc; UI(App* app); void startWindow(); void endWindow(); void createUI(); static void resetOutputCb(Fl_Widget *w, void *data); void changeOutputValue(); void prepareOutput(string& insertedValue, bool isNewAction);
};
#endif /* UI_H */

2) Calculator:

//Calculator.h
#ifndef CALCULATOR_H
#define CALCULATOR_H
#include <string>
#include <FL/Fl_Widget.H>
using namespace std;
class UI;
class Calculator {
public: Calculator(UI *ui); UI *ui; string leftOperand; string action; string rightOperand; static void clickButtonCb(Fl_Widget *w, void *data); bool isNewAction(string action);
private: void makeCalc(bool isNewValue); double plus(double x, double y);
};
#endif /* CALCULATOR_H */

Класс UI инициализирует класс Calсulator и передает ему указатель на самого себя:

UI::UI(App *app) { this->app = app; this->calc = new Calculator(this);
}

Класс Calculator в свою очередь записывает указатель на UI в одно из своих свойств:

Calculator::Calculator(UI *ui) :
leftOperand("0"),
rightOperand(""),
action("") { this->ui = ui;
}
}

Однако теперь при попытке вызвать из Calculator метод класса UI:

void UI::prepareOutput(string& insertedValue, bool isNewAction) { if (calc->action != "" && !isNewAction) { // странно, что при calc->action != "" ошибки нет if (calc->rightOperand == "0") { calc->rightOperand = ""; } calc->rightOperand = insertedValue; // НО ВОТ ТУТ Возникает ошибка при работе с calc->rightOperand } else if (!isNewAction) { if (calc->leftOperand == "0") { calc->leftOperand = ""; } calc->leftOperand = insertedValue; } if (isNewAction && calc->rightOperand == "" && calc->action != "" && insertedValue != "=") { calc->action = insertedValue; }
}

возникает ошибка:

:/>  windows - batch file to check 64bit or 32bit OS - Stack Overflow

Segmentation fault; core dumped;

Такая же возникает ошибка, если в классе Calculator сделать что-то вроде :

string str = this->ui->calc->leftOperand; // Segmentation fault; core dumped

При дебаге в переменных видны “странные” для меня значения, ведь ожидаются простые строки:
5b3874af7b5f8755241208.png

Почему возникает эта ошибка и как ее исправить?

Не запускается сервер

§

Ошибка segmentation fault (core dumped)

Есть данный код на СИ, суть в том, чтобы в двумерном массиве с помощью потоков (Linux) найти самую большую последовательность чисел по возрастанию. При компиляции всё хорошо, а как запускаю программу появляется ошибка Segmentation fault (core dumped)

#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
void random1(int arr[5][100]) {
int i,j;
for(i=0; i<5;i )
{
for(j=0; j<100;j )
{
arr[i][j]=rand()0;
printf("%dt", arr[i][j]);
}
printf("n");
}
printf("n");
}
void* thread_func1(int arr[5][100]){
int buffer = 1, maxbuffer=0, max=0, minElement=0, maxElement;
int i,j;
for(i=0;i<5;i )
{
for(j=0;j<100;j )
{
if(arr[i][j 1]>arr[i][j])
{
buffer ;
max=buffer;
if(maxbuffer<max)
{
maxbuffer = max;
maxElement = arr[i][j 1];
}
}
if(arr[i][j 1]<=arr[i][j])
{
max=buffer;
if(maxbuffer<max)
{ maxbuffer = max;
maxElement = arr[i][j 1];
}
buffer = 1;
}
}
minElement = (maxElement 1)-maxbuffer;
for( i = minElement; i<=maxElement; i )
{
printf("%dt", arr[i][j]);
}
}
}
int main() {
int A[5][100];
int stime;
stime=time(NULL);
srand(stime);
random1(A);
pthread_t k1,k2;
pthread_create(&k1, NULL, (void*)thread_func1,(int*)A);
pthread_join(k1,NULL);
printf("%ld",k1);
exit (0);
}

Еще один пример реализации функции thread_func1, но там тоже выходит эта ошибка

void* thread_func1(int arr[5][100]){
int start=0, lenght=1, max_start=0, max_lenght=0;
int i,j;
for(i=0;i<5;i ){
for(j=0;j<100;j ){
for(int k=j 1;k<100;k )
{
if(arr[i][j]<arr[i][k])
lenght ;
else{
if(lenght>max_lenght)
max_lenght= lenght, max_start=start;
start = k, lenght = 1;
}
}
}
}
for(i = max_start; i<max_start max_lenght; i ){
for (j=max_start; i<max_start max_lenght; i ){
printf("%p", arr[i][j]);}}}

Ошибка:segmentation fault (core dumped): как можно исправить (shared memory) c

Ошибка слишком проста – Вы пытаетесь обращаться к объекту, который не создали

std::queue<std::string>* str = (std::queue<std::string>*)shmat(ShmID, 0, 0);

то есть, str указывает на память, но что там… а кто его знает. Если обычную структуру так можно размещать, то с классы нужно только через конструктор.

// получим указатель на память
void *p = shmat(ShmID, 0, 0);
// используем placement new для создания объекта по месту
std::queue<std::string> * str = new(p)std::queue<std::string>();

после такого изменения уже не падает. Но нужно не забыть вызвать деструктор (delete str;). И видимо его нужно вызвать только в одном из процессов. И самое главное – не вызвать его тогда, когда ещё другой процесс использует его.

:/>  Как отключить Интернет на компьютере на время

Также нужно аккуратно посинхронизировать обращения к памяти, а то может быть очень весело – std::queue не ожидает, что он работает с разных процессов.

Способ 1: seh

Если Вы используете OS Windows в качестве целевой ОС и Visual C в качестве компилятора, то Вы можете использовать

— расширение языка С от 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.
:/>  Как активировать windows с помощью командной строки

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

Способ 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-совместимой ОС.